My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
MacroExpansion  
Macro expansion using Apparat
Featured, Phase-Implementation
Updated Nov 2, 2010 by joaebert

Introduction

Macro expansion is inlining for the poor. Apparat has a very spartanic API that allows you to write efficient and maintainable code. It is easy to implement. So here it is. In order to use macro expansion for your SWF you would use TDSI to do the job like "tdsi -i input.swf -o output.swf"

The drawback is that you will have to follow some rules. And the syntax is not always very pleasing at this stage.

About Macros

A macro is usually a snippet you define somewhere in your code. Tiny little monkeys inside of a compiler copy and replace all macro occurrences with the code defined for it.

Apparat brings those tiny little monkeys back to ActionScript.

Defining A Macro

If you want to define a macro you have to extend from apparat.inline.Macro. Then you write some static methods in your class and you are all set. Note that a Macro may never ever return a value.

package com.acme {
  import apparat.inline.Macro

  public final class Foo extends Macro {
    public static function increment(x: int): void {
      x++
    }
  }
}

Et voilĂ . Now whenever you write Foo.increment(x) it will be replaced with x++. Without any drawback in terms of speed. As you can see, usually Foo.increment(x) would never alter the value of x. With macro expansion it does. This is useful since it is the only way to return parameters.

Golden Rules

The current state of the macro expansion is bare bones, dead simple. Apparat will not optimize your code or do anything clever with it, it will just replace those macros. In order to do that you have to follow some rules:

  • You may pass only(!) local variables as parameters to a macro.
  • A macro class may contain only static methods that return void.
  • A macro may not contain exception handlers.

There are some more rules -- like a Macro may not be a dynamic class. But those are more like silver rules, not golden.

Local variables only

Because of simplicity, speed and filesize the macro expansion does not allow you to pass anything else than local variables to a macro. This sucks but keeps the code really simple.

Assume that we have a method Foo.add(x, y) which does nothing else than x += y. This could would be illegal:

var a: int = 0
Foo.add(a, 2 + 2)

2 + 2 is not a local variable so Apparat will tell you that it found some weird illegal operation. Probably PushByte(2) in this case. So how would you do this? You will have to create a temporary parameter for 2 + 2. This is legal again:

var a: int = 0
var b: int = 2 + 2
Foo.add(a, b)//note, only local variables!

Return type must be void

This leads to an error. A method may not return a value.

package com.acme {
  import apparat.inline.Macro

  public final class Foo extends Macro {
    public static function add(x: int, y: int): int {
      return x + y
    }
  }
}

This is how you would return a value using macro expansion.

package com.acme {
  import apparat.inline.Macro

  public final class Foo extends Macro {
    public static function add(x: int, y: int, result: int): void {
      result = x + y
    }
  }
}

A macro may not contain exception handlers

There is no nice solution to this problem. This is illegal:

package com.acme {
  import apparat.inline.Macro

  public final class Foo extends Macro {
    public static function bar(): void {
      try { /* ... */ } catch(e: Error) { trace(e) }
    }
  }
}

The only way to handle an exception is like this. You wrap the handler around the macro.

try { Foo.bar() } catch(e: Error) { trace(e) }
Comment by makc.the...@gmail.com, Dec 11, 2010

Perhaps it should also be noted that TDSI does not inline methods of classes defined outside of package.

Comment by project member joaebert, Dec 12, 2010

What do you mean by methods of classes defined outside of package?

Comment by makc.the...@gmail.com, Dec 12, 2010

i.e. stuff like this: package {

public class Foo () {
public function Foo () {
// will not be inlined; // I had to move Bar into separate file Bar.yo ();
}
}
} class Bar {
public static function yo ():void {}
}

Comment by makc.the...@gmail.com, Dec 12, 2010

...where class Bar extends your class, obviously.

Comment by project member joaebert, Dec 20, 2010

Sorry I still do not get what you mean. "// will not be inlined;". What won't be inlined?

Comment by makc.the...@gmail.com, Dec 24, 2010

call to Bar.yo() will not be inlined, unless Bar (extending Macro) is in the package.

Comment by makc.the...@gmail.com, Dec 24, 2010

(google wiki screwed up the code, that comment was actually three lines)

Comment by explomas...@gmail.com, Feb 16, 2011

@Max But it seems that you don't extend Macro in Bar class(Or you dropped it for the sake of example? )


Sign in to add a comment
Powered by Google Project Hosting