Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -137,18 +137,19 @@ { Table newCtx = overwriteCtx ? ctx : new Table(ctx, Table.Kind.NotPropagateSet); if( isASTLayer(lay) ) return ast2table(e, (AST ee){ // need this for correct scoping (outer scope macro variables must be hidden!) - if(ee is e.expr) + if(e.name!="_" && ee is e.expr) newCtx.set(e.name, NoopLayer, null); return eval(ee,lay,newCtx); }); else { Value ri = eval(e.init, lay, newCtx); - newCtx.set(e.name, e.layer.empty ? lay : e.layer, ri); + if(e.name!="_") + newCtx.set(e.name, e.layer.empty ? lay : e.layer, ri); return eval(e.expr, lay, newCtx, OverwriteCtx); } } private: @@ -461,10 +462,15 @@ { auto e = new Evaluator; enrollRuntimeLibrary(e); assert_nothrow( e.evalString(`case 1`) ); assert_nothrow( e.evalString(`case 1 when 1: 2`) ); + + // this is a shorthand for + // @macro x = fun(){} in @macro(x) + // so it is ok to fail, but it is really incovenient on REPL + assert_nothrow( e.evalString(`@macro x=fun(){}`) ); } /* unittest { Index: polemy/parse.d ================================================================== --- polemy/parse.d +++ polemy/parse.d @@ -120,12 +120,18 @@ auto e = tryEat("(") ? parseLambdaAfterOpenParen(pos) // let var ( ... : (eat("=", "after "~kwd), E(0)); // let var = ... if( moreDeclarationExists() ) return new Let(pos, var, layer, e, Body()); - else - return new Let(pos, var, layer, e, new Var(varpos, var)); + else { + if( layer.empty ) + return new Let(pos, var, layer, e, new Var(varpos, var)); + else if( isMacroLayer(layer) ) + return new Let(pos, var, layer, e, new Str(varpos, "(macro definition)")); + else + return new Let(pos, var, layer, e, new Lay(varpos, layer, new Var(varpos, var))); + } } } AST TopLevelExpression() { @@ -569,18 +575,19 @@ assert_eq(parseString(`123`), intl(123)); assert_eq(parseString(`"foo"`), strl("foo")); assert_eq(parseString(`fun(){1}`), fun([],intl(1))); assert_eq(parseString(`fun(x){1}`), fun(["x"],intl(1))); assert_eq(parseString("\u03BB(){1}"), fun([],intl(1))); - assert_eq(parseString("\u03BB(x){1}"), fun(["x"],intl(1))); + assert_eq(parseString("\u03BB(x,y){1}"), fun(["x","y"],intl(1))); assert_eq(parseString(`1;2`), let("_","",intl(1),intl(2))); assert_eq(parseString(`1;2;`), let("_","",intl(1),intl(2))); assert_eq(parseString(`let x=1 in 2`), let("x","",intl(1),intl(2))); assert_eq(parseString(`var x=1;2;`), let("x","",intl(1),intl(2))); assert_eq(parseString(`def x=1`), let("x","",intl(1),var("x"))); - assert_eq(parseString(`@val x=1;`), let("x","@val",intl(1),var("x"))); - assert_eq(parseString(`@typ x="#int";`), let("x","@typ",strl("#int"),var("x"))); + assert_eq(parseString(`@val x=1;`), let("x","@val",intl(1),lay("@val",var("x")))); + assert_eq(parseString(`@typ x="#int";`), let("x","@typ",strl("#int"),lay("@typ",var("x")))); + assert_eq(parseString(`@macro x=1`), let("x","@macro",intl(1),strl("(macro definition)"))); assert_eq(parseString(`f(1,2)`), call(var("f"),intl(1),intl(2))); assert_eq(parseString(`if 1 then 2`), call(var("if"),intl(1),fun([],intl(2)),fun([],strl("(empty function body)")))); assert_eq(parseString(`if 1 then: 2 else(3)`), call(var("if"),intl(1),fun([],intl(2)),fun([],intl(3)))); assert_eq(parseString(`(if 1 then () else 3)()()`), call(call(call(var("if"),intl(1),fun([],strl("(empty function body)")),fun([],intl(3))))));