// _parseExpr parses an expression from the Lexer passed in. // private SymplExpr ParseExprAux(Lexer lexer) { Token token = lexer.GetToken(); SymplExpr res = null; if (token == SyntaxToken.EOF) { throw new SymplParseException( "Unexpected EOF encountered while parsing expression."); } if (token == SyntaxToken.Quote) { lexer.PutToken(token); res = ParseQuoteExpr(lexer); } else if (token == SyntaxToken.Paren) { lexer.PutToken(token); res = ParseForm(lexer); } else if (token is IdOrKeywordToken) { // If we encounter literal kwd constants, they get turned into ID // Exprs. Code that accepts Id Exprs, needs to check if the token is // kwd or not when it matters. if ((token is KeywordToken) && !(token == KeywordToken.Nil) && !(token == KeywordToken.True) && !(token == KeywordToken.False)) { throw new InvalidCastException("Keyword cannot be an expression"); } else { res = new SymplIdExpr((IdOrKeywordToken)token); } } else if (token is LiteralToken) { res = new SymplLiteralExpr(((LiteralToken)token).Value); } // check for dotted expr if (res != null) { Token next = lexer.GetToken(); lexer.PutToken(next); if (next == SyntaxToken.Dot) { return(ParseDottedExpr(lexer, res)); } else { return(res); } } throw new SymplParseException( "Unexpected token when expecting " + "beginning of expression -- " + token.ToString() + " ... " + lexer.GetToken().ToString() + lexer.GetToken().ToString() + lexer.GetToken().ToString() + lexer.GetToken().ToString()); }
public static Expression AnalyzeBinaryExpr(SymplBinaryExpr expr, AnalysisScope scope) { // The language has the following special logic to handle And and Or // x And y == if x then y // x Or y == if x then x else (if y then y) if (expr.Operation == ExpressionType.And) { return(AnalyzeIfExpr( new SymplIfExpr( expr.Left, expr.Right, null), scope)); } else if (expr.Operation == ExpressionType.Or) { // Use (LetStar (tmp expr) (if tmp tmp)) to represent (if expr expr) // to remore duplicate evaluation. // So x Or y is translated into // (Let* (tmp1 x) // (If tmp1 tmp1 // (Let* (tmp2 y) (If tmp2 tmp2)))) // IdOrKeywordToken tmp2 = new IdOrKeywordToken( // Real implementation needs to ensure unique ID in scope chain. "__tmpLetVariable2"); var tmpExpr2 = new SymplIdExpr(tmp2); var binding2 = new LetBinding(tmp2, expr.Right);; var ifExpr2 = new SymplIfExpr( tmpExpr2, tmpExpr2, null); var letExpr2 = new SymplLetStarExpr( new[] { binding2 }, new[] { ifExpr2 }); IdOrKeywordToken tmp1 = new IdOrKeywordToken( // Real implementation needs to ensure unique ID in scope chain. "__tmpLetVariable1"); var tmpExpr1 = new SymplIdExpr(tmp1); LetBinding binding1 = new LetBinding(tmp1, expr.Left);; SymplExpr ifExpr1 = new SymplIfExpr( tmpExpr1, tmpExpr1, letExpr2); return(AnalyzeLetStarExpr( new SymplLetStarExpr( new[] { binding1 }, new[] { ifExpr1 } ), scope )); } return(Expression.Dynamic( scope.GetRuntime().GetBinaryOperationBinder(expr.Operation), typeof(object), AnalyzeExpr(expr.Left, scope), AnalyzeExpr(expr.Right, scope) )); }
// _parseDottedExpr gathers infix dotted member access expressions. The // object expression can be anything and is passed in via expr. Successive // member accesses must be dotted identifier expressions or member invokes -- // a.b.(c 3).d. The member invokes cannot have dotted expressions for the // member name such as a.(b.c 3). // private SymplDottedExpr ParseDottedExpr(Lexer lexer, SymplExpr objExpr) { Token token = lexer.GetToken(); if (token != SyntaxToken.Dot) { throw new SymplParseException( "Internal: parsing dotted expressions?"); } List <SymplExpr> exprs = new List <SymplExpr>(); token = lexer.GetToken(); while (token is IdOrKeywordToken || token == SyntaxToken.Paren) { // Needs to be fun call or IDs SymplExpr expr; if (token is IdOrKeywordToken) { // Keywords are ok as member names. expr = new SymplIdExpr((IdOrKeywordToken)token); } else { lexer.PutToken(token); expr = ParseForm(lexer); SymplFunCallExpr funCall = expr as SymplFunCallExpr; if (funCall != null || !(funCall.Function is SymplIdExpr)) { throw new SymplParseException( "Dotted expressions must be identifiers or " + "function calls with identiers as the function " + "value -- " + expr.ToString()); } } exprs.Add(expr); token = lexer.GetToken(); if (token != SyntaxToken.Dot) { break; } token = lexer.GetToken(); } lexer.PutToken(token); return(new SymplDottedExpr(objExpr, exprs.ToArray())); }
// Return an Expression for referencing the ID. If we find the name in the // scope chain, then we just return the stored ParamExpr. Otherwise, the // reference is a dynamic member lookup on the root scope, a module object. // public static Expression AnalyzeIdExpr(SymplIdExpr expr, AnalysisScope scope) { if (expr.IdToken.IsKeywordToken) { if (expr.IdToken == KeywordToken.Nil) { return(Expression.Constant(null, typeof(object))); } else if (expr.IdToken == KeywordToken.True) { return(Expression.Constant(true)); } else if (expr.IdToken == KeywordToken.False) { return(Expression.Constant(false)); } else { throw new InvalidOperationException( "Internal: unrecognized keyword literal constant."); } } else { var param = FindIdDef(expr.IdToken.Name, scope); if (param != null) { return(param); } else { return(Expression.Dynamic( scope.GetRuntime().GetGetMemberBinder(expr.IdToken.Name), typeof(object), scope.GetModuleExpr() )); } } }