public LambdaExpression Construct() { var entry = Nodes.First(n => n.Type == FunctionNames.Entry); Dictionary <int, bool> visited = new Dictionary <int, bool>(); visited[entry.Id] = true; // Storing self pointer in case if there will be recursive calls CallStackTreePointers[FunctionName] = Self; Expression body = GetControlExpression(entry.Outputs[0][0].Node, visited); // Outside of the current function's scope self pointer is no longer usable CallStackTreePointers.Remove(FunctionName); ConstructedExpression = Expression.Lambda( Self.Type, Expression.Block( LocalVars.Values.Concat(new[] { Self }), Expression.Assign( Self, Expression.Lambda( Expression.Block( ReturnParam.Type, body, Expression.Label(ReturnTarget, Expression.Default(ReturnParam.Type)) ), EntryParams ) ), Expression.Invoke(Self, EntryParams) ), EntryParams ); CachedTrees[FunctionName] = ConstructedExpression; return(ConstructedExpression); }
private Expression GetDataExpression(int?node, int?output, Dictionary <int, bool> visited) { if (visited.ContainsKey(node.Value) && visited[node.Value]) { throw new InvalidGraphException("Infinite data loop"); } var currentNode = GetNode(node.Value); if (FunctionsFacade.IsPureFunction(currentNode.Type)) { visited[node.Value] = true; var inputExpressions = new Expression[currentNode.Inputs.Length]; for (int i = 0; i < currentNode.Inputs.Length; i++) { var connection = currentNode.Inputs[i][0]; if (connection == null) { inputExpressions[i] = GetDefaultValueOfEmptyInput(currentNode.Type, i, currentNode.Data.Value); } else { inputExpressions[i] = GetDataExpression(connection.Node, connection.Output, visited); } } visited[node.Value] = false; if (currentNode.Type == FunctionNames.Number) { return(Expression.Constant((double?)Convert.ToDouble(currentNode.Data.Value), typeof(double?))); } else if (currentNode.Type == FunctionNames.Boolean) { return(Expression.Constant((bool?)Convert.ToBoolean(currentNode.Data.Value), typeof(bool?))); } else if (currentNode.Type == FunctionNames.NumberArray) { return(Expression.Constant(JsonConvert.DeserializeObject <double?[]>(currentNode.Data.Value), typeof(double?[]))); } if (currentNode.Type == FunctionNames.Get) { return(LocalVars[currentNode.Data.Value]); } else { try { var tree = FunctionsFacade.GetExpressionTree(currentNode.Type, inputExpressions); return(tree); } catch (NeedToConstructExpressionTreeException) { // If the function has been constructed before use that if (CachedTrees.ContainsKey(currentNode.Type)) { return(Expression.Invoke(CachedTrees[currentNode.Type], inputExpressions)); } // If this is a recursive call of a function that hasn't been constructed yet use self pointer else if (CallStackTreePointers.ContainsKey(currentNode.Type)) { return(Expression.Invoke(CallStackTreePointers[currentNode.Type], inputExpressions)); } // Otherwise construct a tree for the function else { var graph = FunctionsFacade.GetFunctionGraph(currentNode.Type); var constructor = new ExpressionTreeConstructor(currentNode.Type, graph, FunctionsFacade, CachedTrees); var tree = constructor.Construct(); return(Expression.Invoke(tree, inputExpressions)); } } } } else { switch (currentNode.Type) { case FunctionNames.Entry: return(EntryParams[output.Value - 1]); case FunctionNames.ForEach: case FunctionNames.For: return(LoopVars[Tuple.Create(currentNode.Id, output.Value)]); case FunctionNames.Set: return(LocalVars[currentNode.Data.Value]); } } throw new InvalidGraphException($"Couldn't recognize node {currentNode.Type}"); }