예제 #1
0
        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);
        }
예제 #2
0
        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}");
        }