@@ -166,9 +166,10 @@ ["<<", ">>"], ["+","-"], ["~"], ["*","/","%"], - ["^^","**"] + ["^^","**"], + [".",".?"] ]; AST E(size_t level) { @@ -181,8 +182,12 @@ auto pos = currentPosition(); foreach(op; operator_perferences[level]) if( tryEat(op) ) + if( op[0]=='.' ) + return rec( + new FuncallExpression(lhs.pos, new VarExpression(pos, op), lhs, parseId())); + else return rec( new FuncallExpression(lhs.pos, new VarExpression(pos, op), lhs, E(level+1))); return lhs; } @@ -244,8 +249,28 @@ { auto e = Body(); eat(")", "after parenthesized expression"); return e; + } + if( tryEat("{") ) + { + AST e = new FuncallExpression(pos, new VarExpression(pos,"{}")); + if( tryEat("}") ) + return e; + for(;;) + { + string key = eatId("for table key", AllowQuoted); + eat(":", "after table key"); + AST val = E(0); + e = new FuncallExpression(pos, new VarExpression(pos,".="), + e, new StrLiteral(pos,key), val); + if( !tryEat(",") ) + { + eat("}", "for the end of table literal"); + break; + } + } + return e; } if( tryEat("if") ) { eat("(", "after if"); @@ -276,8 +301,14 @@ } scope(exit) lex.popFront; return new VarExpression(pos, lex.front.str); } + + AST parseId() + { + scope(exit) lex.popFront; + return new StrLiteral(currentPosition(), lex.front.str); + } AST parseLambdaAfterOpenParen(immutable LexPosition pos) { Parameter[] params; @@ -437,5 +468,11 @@ ); assert_eq(parseString(`@@type ( x ) { x }`), let("@type", "(system)", fun(["x"], var("x")), var("@type")) ); + + assert_eq(parseString(`{}`), call(var("{}"))); + assert_eq(parseString(`{foo:1,"bar":2}`), + call(var(".="), call(var(".="), call(var("{}")), strl("foo"), intl(1)), strl("bar"), intl(2))); + assert_eq(parseString(`{}.foo`), call(var("."),call(var("{}")),strl("foo"))); + assert_eq(parseString(`{}.?foo`), call(var(".?"),call(var("{}")),strl("foo"))); }