Archive

Archive for September, 2010

asblocks & asbuilder update :: as3 code creation impl complete

September 16th, 2010 Michael Schmalle 3 comments

Hi,

Just thought I would pass along the example below to show where this project is at. I have worked really hard the last week to implement most of the actionscript 3 code creation.

I have also refactored the asdoc parser to use a linked list. This allows complete control over the ast after it is created and during creation with ast utilities.

I’m working on a little turnkey project that will show devs how to implement the libraries. The below code is included in this project;

GIT Repos

  • asblocks – AST and bloc read-write
  • asbuilder – AIR specific implementations (requires asblocks)

Code:

private var factory:ASFactory; 
 
protected function createProject():void
{
	factory = new ASBuilderFactory();
 
	var project:IASProject = factory.newEmptyASProject(
		File.desktopDirectory.resolvePath("test_src").nativePath);
 
	var classA:ICompilationUnit = project.newClass("my.domain.ClassA");
	var interfaceA:ICompilationUnit = project.newInterface("my.domain.IInterfaceA");
 
	var doc:IDocComment;
	var tag0:IDocTag;
	var tag1:IDocTag;
 
	var ctype:IClassType = IClassType(classA.typeNode);
	ctype.superClass = "ClassB";
	ctype.addImplementedInterface("IInterfaceA");
	ctype.addImplementedInterface("IInterfaceB");
 
	ctype.description = "A class documentation comment\nwith multiple lines.";
	doc = ctype.documentation;
	tag0 = doc.newDocTag("see", "my.other.Class");
	tag1 = doc.newDocTag("author", "Mike Schmalle <mschmalle@teotigraphix.com>");
 
	// add metadata
	var event:IMetaData = ctype.newMetaData("Event");
	event.description = "A class documentation comment\nwith multiple lines.";
 
	tag0 = event.documentation.newDocTag("see", "ClassB#event:myOtherEvent");
 
	event.addNamedStringParameter("name", "myEvent");
	event.addNamedStringParameter("type", "flash.events.Event");
 
	var defaultProperty:IMetaData = ctype.newMetaData("DefaultProperty");
	defaultProperty.addNamedStringParameter("defaultValue", "dataProvider");
 
	ctype.newMetaData("Bindable");
 
	createField(ctype);
	createStaticField(ctype);
	createStaticConstant(ctype);
 
	createMethod(ctype);
	createFinalMethod(ctype);
	createStaticMethod(ctype);
	createGetMethod(ctype);
	createSetMethod(ctype);
	createComplexMethod(ctype);
 
	walkUnit(classA);
 
	project.writeAll();
}
 
protected function walkUnit(unit:ICompilationUnit):void
{
	var visitor:IASVisitor = new TestVisitor();
	var walker:IASWalker = new ASWalker(visitor);
	walker.walkCompilationUnit(unit);
}
 
protected function createField(type:IClassType):void
{
	var f:IField = type.newField("field", Visibility.PUBLIC, "int");
	f.description = "An integer field.";
	var tag0:IDocTag = f.documentation.newDocTag("productversion", "1.0");
}
 
protected function createStaticField(type:IClassType):void
{
	var f:IField = type.newField("STATIC_FIELD", Visibility.PUBLIC, "int");
	f.isStatic = true;
	f.initializer = exp("42");
}
 
protected function createStaticConstant(type:IClassType):void
{
	var f:IField = type.newField("CONSTANT_FIELD", Visibility.PROTECTED, "int");
	// change field to static
	f.isStatic = true;
	// change field to a constant
	f.isConstant = true;
	// set the initializer
	f.initializer = exp("42");
}
 
protected function createMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("method", Visibility.PUBLIC, "void");
 
	// add parameters
	m.addParameter("arg0", "int");
	m.addParameter("arg1", "int", "42");
	m.addRestParam("rest");
 
	// change type 
	m.type = "String";
	m.addComment("TODO implement method");
	// add a return
	m.newReturn(factory.newExpression("null"));
}
 
protected function createFinalMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("methodFinal", Visibility.PUBLIC, "void");
}
 
protected function createStaticMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("methodStatic", Visibility.PUBLIC, "void");
	m.isStatic = true;
}
 
protected function createGetMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("property", Visibility.PUBLIC, "int");
	m.accessorRole = AccessorRole.GETTER;
	m.newReturn(factory.newNumberLiteral(-1));
}
 
protected function createSetMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("property", Visibility.PUBLIC, "void");
	m.addParameter("value", "int");
	m.accessorRole = AccessorRole.SETTER;
}
 
protected function createComplexMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("complex", Visibility.PRIVATE, "void");
	// add an if() statement
	var ifstmt:IIfStatement = m.newIf(exp("i < len && hasNext()"));
	// add a var declaration
	var dc:IDeclarationStatement = ifstmt.parseNewDeclaration("len:int = 2");
	// make it a constant
	dc.isConstant = true;
	// add a for() statement
	var forstmt:IForStatement = ifstmt.parseNewFor("var i:int = 0", "i < len", "i++");
	// add a switch() statement
	var swstmt:ISwitchStatement = forstmt.newSwitch(exp("name"));
	// add a case to the switch
	var cs1:ISwitchCase = swstmt.newCase("\"one\"");
	cs1.newBreak();
	// add a case to the switch
	var cs2:ISwitchCase = swstmt.newCase("\"two\"");
	var ifstmt2:IIfStatement = cs2.newIf(exp("i == 2"));
	// add a single lin comment
	ifstmt2.addComment("Trace the result");
	ifstmt2.addStatement("trace('Hello Two')");
	cs2.newBreak();
	// add a default to the switch
	var dfstmt:ISwitchDefault = swstmt.newDefault();
	dfstmt.newThrow(exp("new Error('Error here')"));
}
 
private function exp(expression:String):IExpression
{
	return factory.newExpression(expression);
}

Output:

package my.domain {
	/**
	 * A class documentation comment
	 * with multiple lines.
	 * @see ClassB#event:myOtherEvent
	 */
	[Event(name="myEvent",type="flash.events.Event")]
	[DefaultProperty(defaultValue="dataProvider")]
	[Bindable]
	/**
	 * A class documentation comment
	 * with multiple lines.
	 * @see my.other.Class
	 * @author Mike Schmalle <mschmalle@teotigraphix.com>
	 */
	public class ClassA extends ClassB implements IInterfaceA, IInterfaceB {
		/**
		 * An integer field.
		 * @productversion 1.0
		 */
		public var field:int;
		public static var STATIC_FIELD:int = 42;
		protected static const CONSTANT_FIELD:int = 42;
		public function method(arg0:int, arg1:int = 42):String {
			//TODO implement method
			return null;
		}
		public function methodFinal():void {
		}
		public static function methodStatic():void {
		}
		public get function property():int {
			return -1;
		}
		public set function property(value:int):void {
		}
		private function complex():void {
			if (i < len && hasNext()) {
				const len:int = 2;
				for (var i:int = 0; i < len; i++) {
					switch (name) {
						case "one":
							break;
						case "two":
							if (i == 2) {
								//Trace the result
								trace('Hello Two');
							}
							break;
						default:
							throw new Error('Error here');
					}
				}
			}
		}
	}
}

Mike

Categories: Uncategorized Tags:

as3parser-framework :: Facelift – asblocks & asbuilder

September 6th, 2010 Michael Schmalle No comments

Hi,

Well the last 2 weeks have been very productive. The as3nodes framework is retired, with the metaas DOM implemented. I talked with David Holroyd and have his very encouraging consent to use his API. The metaas Java framework was designed to parse and create AS3 code using antlr and a Document Object Model designed by David.

Davids quote to me;

“There is a lovely symmetry to being able to manipulate the source code of a language within the language itself!”

There have been significant changes in the project within the last 2 weeks;

  • The as3parser and DOM has their repository changed to asblocks
  • The as3builder-framework was changed to asbuilder and now lives at asbuilder
  • The majority of the parser and actionscript read/write DOM implementation is located in the asblocks repository.
  • The asbuilder repository will hold all classes key to the AIR desktop implementation of the IASProject.

For now, the asbook package is missing, that will be reimplemented using the new DOM.

As it stands the asblocks code right now can almost create any type, method, member, expression or statement in ActionScript3! :)

Check it out; This wiki got deprecated, that will be updated as well with a new sub domain asblocks.

The focus has shifted to read-write actionscript instead of the “parser”.

In the spirit of metaas, the following API;

Code:

var factory:ASFactory = new ASFactory();
var project:ASProject = factory.newEmptyASProject(".") as ASProject;
var unit:ICompilationUnit = project.newClass("Test");
var clazz:IClassType = unit.typeNode as IClassType;
var method:IMethod = clazz.newMethod("test", Visibility.PUBLIC, "void");
method.addStatement("trace('Hello world')");
project.writeAll();

Output:

package {
	public class Test {
		public function test():void {
			trace('Hello world');
		}
	}
}

Oh yeah here is another fun one;

Code:

var statement:IBlock = factory.newBlock();
var ifst:IIfStatement = statement.newIf(factory.newExpression("test()"));
ifst.addStatement("trace('test succeeded')");
ifst.elseBlock.addStatement("trace('test failed')");
var ifstSub:IIfStatement = ifst.newIf(factory.newExpression("test2()"));
ifstSub.addStatement("trace('sub test succeeded')");
ifstSub.elseBlock.addStatement("trace('sub test failed')");

Output:

{
	if (test()) {
		trace('test succeeded');
		if (test2()) {
			trace('sub test succeeded');
		} else {
			trace('sub test failed');
		}
	} else {
		trace('test failed');
	}
}

Mike

PS There is a lot more to come now, the was a BIG hurdle, but it’s implemented now!

Categories: Uncategorized Tags: