Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -70,34 +70,34 @@ Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) { if( isASTLayer(lay) ) return ast2table(e, (AST e){return eval(e,lay,ctx);}); - if( lay==ValueLayer ) - return new StrValue(e.data); - return lift(new StrValue(e.data), lay, ctx, e.pos); + if( isUserDefinedLayer(lay) ) + return lift(new StrValue(e.data), lay, ctx, e.pos); + return new StrValue(e.data); } Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) { if( isASTLayer(lay) ) return ast2table(e, (AST e){return eval(e,lay,ctx);}); - if( lay==ValueLayer ) - return new IntValue(e.data); - return lift(new IntValue(e.data), lay, ctx, e.pos); + if( isUserDefinedLayer(lay) ) + return lift(new IntValue(e.data), lay, ctx, e.pos); + return new IntValue(e.data); } Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) { if( isASTLayer(lay) ) if( isMacroLayer(lay) && ctx.has(e.name,MacroLayer) ) return ctx.get(e.name, MacroLayer, e.pos); else return ast2table(e, (AST e){return eval(e,lay,ctx);}); - if( lay==ValueLayer || ctx.has(e.name, lay) ) - return ctx.get(e.name, lay, e.pos); - return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos); + if( isUserDefinedLayer(lay) && !ctx.has(e.name, lay) ) + return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos); + return ctx.get(e.name, lay, e.pos); } Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) { Value f = eval( e.fun, lay, ctx ); @@ -136,11 +136,12 @@ Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) { Table newCtx = overwriteCtx ? ctx : new Table(ctx, Table.Kind.NotPropagateSet); if( isASTLayer(lay) ) return ast2table(e, (AST ee){ - if(ee is e.expr) // need this for correct scoping (outer scope macro variables must be hidden!) + // need this for correct scoping (outer scope macro variables must be hidden!) + if(ee is e.expr) newCtx.set(e.name, ValueLayer, new UndefinedValue); return eval(ee,lay,newCtx); }); else { @@ -253,18 +254,21 @@ Table defCtx; override const(Parameter[]) params() { return ast.params; } override Table definitionContext() { return defCtx; } this(Fun ast, Table defCtx) { this.ast=ast; this.defCtx=defCtx; } - override string toString() const { return sprintf!"(function:%x:%x)"(cast(void*)ast, cast(void*)defCtx); } + override string toString() const + { return sprintf!"(function:%x:%x)"(cast(void*)ast, cast(void*)defCtx); } override int opCmp(Object rhs) { if(auto r = cast(UserDefinedFunValue)rhs) { - if(auto i = this.ast.opCmp(r.ast)) - return i; + auto a = cast(void*)this.ast; + auto b = cast(void*)r.ast; + if(ab) return +1; // [TODO] avoid using pointer value... return this.defCtx.opCmp(r.defCtx); } - if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); + if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); throw genex!RuntimeException("comparison with value and something other"); } mixin SimpleToHash; AST afterMacroAST; @@ -296,11 +300,11 @@ override string toString() { return sprintf!"(native:%x)"(dg.funcptr); } override int opCmp(Object rhs) { if(auto r = cast(NativeFunValue)rhs) return typeid(typeof(dg)).compare(&dg,&r.dg); if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); - throw genex!RuntimeException(LexPosition.dummy, "comparison with value and something other"); + throw genex!RuntimeException("comparison with value and something other"); } mixin SimpleToHash; R delegate(T) dg; Parameter[] params_data; @@ -313,16 +317,18 @@ } override Value invoke(Layer lay, Table ctx, LexPosition pos) { if( lay != defLay ) - throw genex!RuntimeException(pos, text("only ", defLay, " layer can call native function: ", name)); + throw genex!RuntimeException(pos, + text("only ", defLay, " layer can call native function: ", name)); T typed_args; foreach(i, Ti; T) { typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer, pos); if( typed_args[i] is null ) - throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d of native function: %s"(i+1,name)); + throw genex!RuntimeException(pos, + sprintf!"type mismatch on the argument %d of native function: %s"(i+1,name)); } try { return dg(typed_args); } catch( RuntimeException e ) { throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e; Index: polemy/layer.d ================================================================== --- polemy/layer.d +++ polemy/layer.d @@ -15,43 +15,56 @@ { SystemLayer = "(system)", /// Predefined layer for internal data ValueLayer = "@value", /// Predefined layer for normal run MacroLayer = "@macro", /// Predefined layer for macro run (@lay() changes layer) RawMacroLayer = "(rawmacro)", /// Predefined layer for macro run (@lay() becomes AST) - AstLayer = "(ast)", /// Predefined layer for macro run (never invoke macro) +} + +/// True if it is a user-defined layer + +bool isUserDefinedLayer( Layer lay ) +{ + return lay!=SystemLayer && lay!=ValueLayer && lay!=MacroLayer && lay!=RawMacroLayer; +} + +unittest +{ + assert( !isUserDefinedLayer(SystemLayer) ); + assert( !isUserDefinedLayer(ValueLayer) ); + assert( !isUserDefinedLayer(MacroLayer) ); + assert( !isUserDefinedLayer(RawMacroLayer) ); + assert( isUserDefinedLayer("@foo") ); } /// True if it is macro-like layer that basically generates syntax tree bool isASTLayer( Layer lay ) { - return lay==MacroLayer || lay==RawMacroLayer || lay==AstLayer; + return lay==MacroLayer || lay==RawMacroLayer; } unittest { assert( !isASTLayer(SystemLayer) ); assert( !isASTLayer(ValueLayer) ); assert( isASTLayer(MacroLayer) ); assert( isASTLayer(RawMacroLayer) ); - assert( isASTLayer(AstLayer) ); } /// True if in the specified layer @lay(...) has no effect and merely produces a syntax tree bool isNoLayerChangeLayer( Layer lay ) { - return lay==RawMacroLayer || lay==AstLayer; + return lay==RawMacroLayer; } unittest { assert( !isNoLayerChangeLayer(SystemLayer) ); assert( !isNoLayerChangeLayer(ValueLayer) ); assert( !isNoLayerChangeLayer(MacroLayer) ); assert( isNoLayerChangeLayer(RawMacroLayer) ); - assert( isNoLayerChangeLayer(AstLayer) ); } /// True if do macro expanstion bool isMacroLayer( Layer lay ) @@ -63,7 +76,6 @@ { assert( !isMacroLayer(SystemLayer) ); assert( !isMacroLayer(ValueLayer) ); assert( isMacroLayer(MacroLayer) ); assert( isMacroLayer(RawMacroLayer) ); - assert( !isMacroLayer(AstLayer) ); } Index: polemy/parse.d ================================================================== --- polemy/parse.d +++ polemy/parse.d @@ -282,30 +282,11 @@ AST e = new App(pos, new Var(pos,"{}")); return parseTableSetAfterBrace(e); } if( tryEat("if") ) { - eat("(", "after if"); - auto cond = E(0); - eat(")", "after if condition"); - auto thenPos = lex.front.pos; - eat("{", "after if condition"); - auto th = Body(); - eat("}", "after if-then body"); - auto el = doNothingExpression(); - auto elsePos = (lex.empty ? LexPosition.dummy : lex.front.pos); - if( tryEat("else") ) { - eat("{", "after else"); - el = Body(); - eat("}", "after else body"); - } - return new App(pos, - new Var(pos, "if"), - cond, - new Fun(thenPos, [], th), - new Fun(elsePos, [], el) - ); + return parseIfAfterIf(pos); } if( tryEat("case") ) { return parsePatternMatch(pos); } @@ -315,10 +296,35 @@ return parseLambdaAfterOpenParen(pos); } scope(exit) lex.popFront; return new Var(pos, lex.front.str); } + + AST parseIfAfterIf(LexPosition pos) + { + eat("(", "after if"); + auto cond = E(0); + eat(")", "after if condition"); + auto thenPos = lex.front.pos; + AST th; + if( tryEat("{") ) { + th = Body(); + eat("}", "after if-then body"); + } else { + th = E(0); + } + auto el = doNothingExpression(); + auto elsePos = (lex.empty ? LexPosition.dummy : lex.front.pos); + if( tryEat("else") ) + if( tryEat("{") ) { + el = Body(); + eat("}", "after else body"); + } else { + el = E(0); + } + return new App(pos, new Var(pos,"if"), cond, new Fun(thenPos,[],th), new Fun(elsePos,[],el)); + } AST parsePatternMatch(LexPosition pos) { // case "(" pmExpr ")" CASES //==> @@ -666,6 +672,17 @@ assert_nothrow(parseString(` case( 1 ) when({aaaa:@value(x)}){1} when({aaaa:{bbb:_}, ccc:123}){1} `)); -} +} + +unittest +{ + // test for omitting { .. } + assert_nothrow(parseString(` + if(1) 2 else 3 + `)); + assert_nothrow(parseString(` + if(1) x{y:z} else 3 + `)); +} Index: polemy/valueconv.d ================================================================== --- polemy/valueconv.d +++ polemy/valueconv.d @@ -67,11 +67,11 @@ StrValue typ = cast(StrValue) t.access!StrValue(ValueLayer, "is"); if( typ is null ) throw genex!RuntimeException(callpos, text(`Invalid AST (no "is" field): `, _v)); foreach(AT; ListOfASTTypes) - if(typ.data == typeid(AT).name.split(".")[$-1].tolower()) + if(typ.data == typeid(AT).name.split(".")[$-1]) { typeof(AT.tupleof) mems; foreach(i,m; mems) { string name = AT.tupleof[i].stringof.split(".")[$-1]; @@ -144,11 +144,11 @@ static if(is(T : AST)) { assert( typeid(e) == typeid(T), text("abstracted: ", typeid(e), " vs ", typeid(T)) ); auto t = new Table; t.set("pos", ValueLayer, ast2table(e.pos,rec)); - t.set("is" , ValueLayer, new StrValue(typeid(e).name.split(".")[$-1].tolower())); + t.set("is" , ValueLayer, new StrValue(typeid(e).name.split(".")[$-1])); foreach(i,m; e.tupleof) static if(is(typeof(m) : AST)) t.set(e.tupleof[i].stringof.split(".")[$-1], ValueLayer, rec(m)); else t.set(e.tupleof[i].stringof.split(".")[$-1], ValueLayer, ast2table(m,rec)); Index: sample/ast.pmy ================================================================== --- sample/ast.pmy +++ sample/ast.pmy @@ -6,11 +6,11 @@ }; @macro reverseArgs(e) {@value( var ev = @macro(e); case(ev) - when( {is:"app", fun:f, args:a} ) + when( {is:"App", fun:f, args:a} ) { ev {args: reverse(a, {})} } when( _ ) {