// AnalyzeLetStar returns a Block with vars, each initialized in the order // they appear. Each var's init expr can refer to vars initialized before it. // The Block's body is the Let*'s body. // public static Expression AnalyzeLetStarExpr(SymplLetStarExpr expr, AnalysisScope scope) { var letscope = new AnalysisScope(scope, "let*"); // Analyze bindings. List <Expression> inits = new List <Expression>(); List <ParameterExpression> varsInOrder = new List <ParameterExpression>(); foreach (var b in expr.Bindings) { // Need richer logic for mvbind var v = Expression.Parameter(typeof(object), b.Variable.Name); varsInOrder.Add(v); inits.Add( Expression.Assign( v, Expression.Convert(AnalyzeExpr(b.Value, letscope), v.Type)) ); // Add var to scope after analyzing init value so that init value // references to the same ID do not bind to his uninitialized var. letscope.Names[b.Variable.Name.ToLower()] = v; } List <Expression> body = new List <Expression>(); foreach (var e in expr.Body) { body.Add(AnalyzeExpr(e, letscope)); } // Order of vars to BlockExpr don't matter semantically, but may as well // keep them in the order the programmer specified in case they look at the // Expr Trees in the debugger or for meta-programming. inits.AddRange(body); return(Expression.Block(typeof(object), varsInOrder.ToArray(), inits)); }
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) )); }
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) ); }
// AnalyzeLetStar returns a Block with vars, each initialized in the order // they appear. Each var's init expr can refer to vars initialized before it. // The Block's body is the Let*'s body. // public static Expression AnalyzeLetStarExpr(SymplLetStarExpr expr, AnalysisScope scope) { var letscope = new AnalysisScope(scope, "let*"); // Analyze bindings. List<Expression> inits = new List<Expression>(); List<ParameterExpression> varsInOrder = new List<ParameterExpression>(); foreach (var b in expr.Bindings) { // Need richer logic for mvbind var v = Expression.Parameter(typeof(object), b.Variable.Name); varsInOrder.Add(v); inits.Add( Expression.Assign( v, Expression.Convert(AnalyzeExpr(b.Value, letscope), v.Type)) ); // Add var to scope after analyzing init value so that init value // references to the same ID do not bind to his uninitialized var. letscope.Names[b.Variable.Name.ToLower()] = v; } List<Expression> body = new List<Expression>(); foreach (var e in expr.Body) { body.Add(AnalyzeExpr(e, letscope)); } // Order of vars to BlockExpr don't matter semantically, but may as well // keep them in the order the programmer specified in case they look at the // Expr Trees in the debugger or for meta-programming. inits.AddRange(body); return Expression.Block(typeof(object), varsInOrder.ToArray(), inits); }