Beispiel #1
0
        public ExpressionTreeConstructor(
            string functionName,
            D3NEGraph graph,
            FunctionsFacade functionFacade,
            Dictionary <string, LambdaExpression> cachedTrees          = null,
            Dictionary <string, ParameterExpression> callStackPointers = null
            )
        {
            FunctionName          = functionName;
            FunctionsFacade       = functionFacade;
            CachedTrees           = cachedTrees ?? new Dictionary <string, LambdaExpression>();
            CallStackTreePointers = callStackPointers ?? new Dictionary <string, ParameterExpression>();
            Validator             = new GraphValidator(graph, functionFacade);
            Validator.Validate();

            Nodes = graph.Nodes;

            LocalVars = new Dictionary <string, ParameterExpression>();
            foreach (var localVar in graph.LocalVariables)
            {
                LocalVars[localVar.Name] = Expression.Variable(DataTypes.GetType(localVar.Type), $"{functionName}-{localVar.Name}");
            }

            EntryParams = new ParameterExpression[graph.Inputs.Length];
            int index = 0;

            foreach (var param in graph.Inputs)
            {
                EntryParams[index++] = Expression.Parameter(DataTypes.GetType(param.Type), $"{functionName}-{param.Name}");
            }

            ReturnParam = Expression.Parameter(DataTypes.GetType(graph.Output.Type), $"{functionName}-{graph.Output.Name}");

            LoopVars = new Dictionary <Tuple <int, int>, ParameterExpression>();
            var loopNodes = graph.Nodes.Where(n => n.Type == FunctionNames.For || n.Type == FunctionNames.ForEach);

            foreach (var loopNode in loopNodes)
            {
                if (loopNode.Type == FunctionNames.For)
                {
                    LoopVars[Tuple.Create(loopNode.Id, 1)] = Expression.Variable(typeof(double?), $"{functionName}-LoopVar{loopNode.Id}");
                }
                else if (loopNode.Type == FunctionNames.ForEach)
                {
                    LoopVars[Tuple.Create(loopNode.Id, 1)] = Expression.Variable(typeof(double?), $"{functionName}-LoopVar{loopNode.Id}");
                    LoopVars[Tuple.Create(loopNode.Id, 2)] = Expression.Variable(typeof(double?), $"{functionName}-LoopVar{loopNode.Id}");
                }
            }

            Type[] typeArgs   = graph.Inputs.Select(p => DataTypes.GetType(p.Type)).Concat(new Type[] { DataTypes.GetType(graph.Output.Type) }).ToArray();
            Type   lambdaType = Expression.GetFuncType(typeArgs);

            Self = Expression.Variable(lambdaType, $"{functionName}-Self");

            ReturnTarget = Expression.Label(ReturnParam.Type, $"{functionName}-Return");
        }
Beispiel #2
0
        private Expression GetDefaultValueOfEmptyInput(string nodeType, int emptyInputIndex, string nodeValue)
        {
            if (FunctionsFacade.IsLocalScopeFunction(nodeType))
            {
                switch (nodeType)
                {
                case FunctionNames.Return:
                    return(Expression.Default(ReturnParam.Type));

                case FunctionNames.Set:
                    return(Expression.Default(LocalVars[nodeValue].Type));
                }
            }
            else
            {
                return(Expression.Default(FunctionsFacade.GetInputParameterType(nodeType, emptyInputIndex)));
            }

            throw new InvalidGraphException($"Couldn't recognize node {nodeType}");
        }
Beispiel #3
0
        private Expression GetControlExpression(int node, Dictionary <int, bool> visited)
        {
            if (visited.ContainsKey(node) && visited[node])
            {
                throw new InvalidGraphException("Infinite flow loop");
            }

            visited[node] = true;

            var currentNode = GetNode(node);

            var inputDataExpressions  = new Expression[currentNode.Inputs.Length];
            var outputFlowExpressions = new Expression[currentNode.Outputs.Length];

            // ASSUMPTION: first input socket is a flow socket, the rest are data sockets
            for (int i = 1; i < currentNode.Inputs.Length; i++)
            {
                var connection = currentNode.Inputs[i][0];
                if (connection == null)
                {
                    inputDataExpressions[i] = GetDefaultValueOfEmptyInput(currentNode.Type, i, currentNode.Data.Value);
                }
                else
                {
                    inputDataExpressions[i] = GetDataExpression(node, i);
                }
            }

            for (int i = 0; i < currentNode.Outputs.Length; i++)
            {
                var connection = currentNode.Outputs[i][0];
                if (connection != null && !FunctionsFacade.IsPureFunction(GetNode(connection.Node).Type))
                {
                    outputFlowExpressions[i] = GetControlExpression(connection.Node, visited);
                }
                else
                {
                    outputFlowExpressions[i] = Expression.Empty();
                }
            }

            visited[node] = false;

            switch (currentNode.Type)
            {
            case FunctionNames.If:
                return(Expression.IfThenElse(
                           Expression.Convert(inputDataExpressions.ElementAtOrDefault(1), typeof(bool)),
                           outputFlowExpressions.ElementAtOrDefault(0),
                           outputFlowExpressions.ElementAtOrDefault(1)
                           ));

            case FunctionNames.ForEach:
                return(Expression.Block(
                           ExpressionUtils.ForEach(
                               inputDataExpressions.ElementAtOrDefault(1),
                               LoopVars[Tuple.Create(node, 1)],
                               outputFlowExpressions.ElementAtOrDefault(0)
                               ),
                           outputFlowExpressions.ElementAtOrDefault(3)
                           ));

            case FunctionNames.For:
                throw new NotImplementedException();

            case FunctionNames.While:
                throw new NotImplementedException();

            case FunctionNames.Return:
                return(Expression.Return(ReturnTarget, inputDataExpressions.ElementAtOrDefault(1)));

            case FunctionNames.Set:
                return(Expression.Block(
                           Expression.Assign(LocalVars[currentNode.Data.Value], inputDataExpressions.ElementAtOrDefault(1)),
                           outputFlowExpressions[0]
                           ));

            default:
                throw new InvalidGraphException("Not a control function or is entry");
            }
        }
Beispiel #4
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}");
        }
 public GraphValidator(D3NEGraph graphModel, FunctionsFacade functionFacade)
 {
     Model  = graphModel;
     Facade = functionFacade;
 }