Index: polemy/ast.d ================================================================== --- polemy/ast.d +++ polemy/ast.d @@ -4,12 +4,12 @@ * * Syntax tree for Polemy programming language. */ module polemy.ast; import polemy._common; -import polemy.lex : LexPosition; - +import polemy.lex; + alias Statement[] Program; abstract class Statement { immutable LexPosition pos; @@ -18,68 +18,77 @@ class DeclStatement : Statement { string var; Expression expr; - mixin SimpleConstructor; - mixin SimpleCompare; + mixin SimpleClass; } class ExprStatement : Statement { Expression expr; - mixin SimpleConstructor; - mixin SimpleCompare; + mixin SimpleClass; } abstract class Expression { immutable LexPosition pos; mixin SimpleConstructor; - mixin SimpleCompare; } class StrLiteralExpression : Expression { string data; - mixin SimpleConstructor; - mixin SimpleCompare; + mixin SimpleClass; } class IntLiteralExpression : Expression { BigInt data; - mixin SimpleConstructor; - mixin SimpleCompare; + mixin SimpleClass; } class VarExpression : Expression { string var; - mixin SimpleConstructor; - mixin SimpleCompare; + mixin SimpleClass; } class AssignExpression : Expression { Expression lhs; Expression rhs; - mixin SimpleConstructor; - mixin SimpleCompare; + mixin SimpleClass; } class FuncallExpression : Expression { Expression fun; Expression[] args; this(immutable LexPosition pos, Expression fun, Expression[] args...) { super(pos); this.fun=fun; this.args=args.dup; } - mixin SimpleCompare; + mixin SimpleClass; } class FunLiteralExpression : Expression { string[] params; - Program funbody; - mixin SimpleConstructor; - mixin SimpleCompare; + Program funbody; + mixin SimpleClass; } + +/// Handy Generator for AST nodes. To use this, mixin EasyAst; + +/*mixin*/ +template EasyAst() +{ + template genEast(T) + { T genEast(P...)(P ps) { return new T(LexPosition.dummy, ps); } } + + alias genEast!DeclStatement decl; + alias genEast!ExprStatement expr; + alias genEast!VarExpression var; + alias genEast!FuncallExpression funcall; + alias genEast!IntLiteralExpression intl; + alias genEast!StrLiteralExpression strl; + alias genEast!FunLiteralExpression fun; +} Index: polemy/lex.d ================================================================== --- polemy/lex.d +++ polemy/lex.d @@ -28,11 +28,14 @@ override string toString() const { return sprintf!"%s:%d:%d"(filename, lineno, column); } mixin SimpleConstructor; - mixin SimpleCompare; + mixin SimpleCompare; + + static immutable LexPosition dummy; + static this(){ dummy = new immutable(LexPosition)("",0,0); } } unittest { auto p = new LexPosition("hello.cpp", 123, 45); @@ -59,10 +62,11 @@ immutable string str; /// The token string itself immutable bool quoted; /// Was it a "quoted" token or unquoted? mixin SimpleConstructor; mixin SimpleCompare; + mixin SimpleToString; } unittest { auto p = new immutable(LexPosition)("hello.cpp", 123, 45); Index: polemy/parse.d ================================================================== --- polemy/parse.d +++ polemy/parse.d @@ -305,12 +305,13 @@ var zzz = 100; # comment zzz = zzz + zzz * "fo\no"; # comment 42; `); - auto s0 = new DeclStatement(null, "zzz", new IntLiteralExpression(null, BigInt(100))); - auto s1 = new ExprStatement(null, new AssignExpression(null, + mixin EasyAst; + auto s0 = decl("zzz", intl(BigInt(100))); + auto s1 = expr( new AssignExpression(null, new VarExpression(null, "zzz"), new FuncallExpression(null, new VarExpression(null,"+"), new VarExpression(null, "zzz"), new FuncallExpression(null, new VarExpression(null,"*"), new VarExpression(null, "zzz"), @@ -328,26 +329,23 @@ unittest { auto p = parserFromString(` var f = fun(x,y){x+y;}; f(1,fun(abc){}(4)); - `); + `); + mixin EasyAst; Program prog = p.parseProgram(); assert( prog.length == 2 ); - assert( prog[0] == new DeclStatement(null, "f", new FunLiteralExpression(null, - ["x","y"], [new ExprStatement(null, - new FuncallExpression(null, new VarExpression(null, "+"), - new VarExpression(null, "x"), new VarExpression(null, "y")))] - ))); - assert( prog[1] == new ExprStatement(null, new FuncallExpression(null, - new VarExpression(null, "f"), - new IntLiteralExpression(null, BigInt(1)), - new FuncallExpression(null, - new FunLiteralExpression(null, ["abc"], [ - ]), - new IntLiteralExpression(null, BigInt(4)) - )))); + assert( prog[0] == decl("f", fun( + ["x","y"], [expr(funcall(var("+"), var("x"), var("y")))] + ))); + assert( prog[1] == expr(funcall(var("f"), + intl(BigInt(1)), + funcall( + fun(["abc"], cast(Statement[])[]), + intl(BigInt(4)) + )))); } unittest { auto p = parserFromString(`var x = 1; var f = fun(){x=x+1;}; f(); f(); x;`); Index: polemy/tricks.d ================================================================== --- polemy/tricks.d +++ polemy/tricks.d @@ -115,11 +115,12 @@ /* [Todo] is there any way to clearnly implement "assert_compiles" and "assert_not_compile"? */ /// Mixing-in the bean constructor for a class -/*mixin*/ template SimpleConstructor() +/*mixin*/ +template SimpleConstructor() { static if( is(typeof(super) == Object) || super.tupleof.length==0 ) this( typeof(this.tupleof) params ) { static if(this.tupleof.length>0) @@ -171,11 +172,12 @@ }) ); } /// Mixing-in the MOST-DERIVED-member-wise comparator for a class -/*mixin*/ template SimpleCompare() +/*mixin*/ +template SimpleCompare() { override bool opEquals(Object rhs_) const { if( auto rhs = cast(typeof(this))rhs_ ) { @@ -236,11 +238,12 @@ assert_throw!AssertError( new Temp(1,"foo") <= new TempDummy(1,"foo") ); } /// Mixing-in a simple toString method -/*mixin*/ template SimpleToString() +/*mixin*/ +template SimpleToString() { override string toString() { string str = sprintf!"%s("(typeof(this).stringof); foreach(i,mem; this.tupleof) @@ -266,5 +269,15 @@ mixin SimpleConstructor; mixin SimpleToString; } assert_eq( (new Temp(1,"foo",BigInt(42))).toString(), "Temp(1,foo,42)" ); } + +/// Everything is in + +/*mixin*/ +template SimpleClass() +{ + mixin SimpleConstructor; + mixin SimpleCompare; + mixin SimpleToString; +}