예제 #1
0
        public static void UpdateBinaryExpressionLocation(ProtoCore.AST.AssociativeAST.BinaryExpressionNode node)
        {
            if (null == node || (null == node.LeftNode) || (null == node.RightNode))
                return;

            SetNodeLocation(node, node.LeftNode, node.RightNode);
        }
예제 #2
0
        private static BinaryExpressionNode CreateAssignmentNode(AssociativeNode rhsNode)
        {

            IdentifierNode lhs = new IdentifierNode(string.Format("tVar_{0}", staticVariableIndex++));
            BinaryExpressionNode bNode = new BinaryExpressionNode(lhs, rhsNode, ProtoCore.DSASM.Operator.assign);
            return bNode;
        }
예제 #3
0
        private BinaryExpressionNode BuildSSAIdentListAssignmentNode(IdentifierListNode identList)
        {
            // Build the final binary expression 
            BinaryExpressionNode bnode = new BinaryExpressionNode();
            bnode.Optr = ProtoCore.DSASM.Operator.assign;

            // Left node
            var identNode = AstFactory.BuildIdentifier(CoreUtils.BuildSSATemp(core));
            bnode.LeftNode = identNode;

            //Right node
            bnode.RightNode = identList;
            bnode.isSSAAssignment = true;

            return bnode;
        }
예제 #4
0
        public void GraphILTest_Assign01_AstInput()
        {
            // Build the AST trees
            ProtoCore.AST.AssociativeAST.BinaryExpressionNode assign = new ProtoCore.AST.AssociativeAST.BinaryExpressionNode(
                new ProtoCore.AST.AssociativeAST.IdentifierNode("a"),
                new ProtoCore.AST.AssociativeAST.IntNode(10),
                ProtoCore.DSASM.Operator.assign);
            List<ProtoCore.AST.AssociativeAST.AssociativeNode> astList = new List<ProtoCore.AST.AssociativeAST.AssociativeNode>();
            astList.Add(assign);

            // Update graph using AST node input
            ProtoScript.Runners.ILiveRunner liveRunner = new ProtoScript.Runners.LiveRunner();
            liveRunner.UpdateGraph(assign);

            ProtoCore.Mirror.RuntimeMirror mirror = liveRunner.InspectNodeValue("a");
            Assert.IsTrue((Int64)mirror.GetData().Data == 10);
        }
예제 #5
0
        public static bool IsReturnExpressionNode(ProtoCore.AST.AssociativeAST.AssociativeNode node)
        {
            ProtoCore.AST.AssociativeAST.BinaryExpressionNode binaryNode =
                node as ProtoCore.AST.AssociativeAST.BinaryExpressionNode;

            if (null == binaryNode)
            {
                return(false);
            }

            ProtoCore.AST.AssociativeAST.IdentifierNode retNode = binaryNode.LeftNode as ProtoCore.AST.AssociativeAST.IdentifierNode;
            if (null == retNode)
            {
                return(false);
            }

            return(retNode.Value == ProtoCore.DSDefinitions.Keyword.Return);
        }
예제 #6
0
        protected virtual void EmitFunctionDefNode(ref ProtoCore.AST.AssociativeAST.FunctionDefinitionNode funcDefNode)
        {
            //EmitCode("def ");
            //EmitCode(funcDefNode.Name);

            if (funcDefNode.ReturnType.UID != ProtoCore.DSASM.Constants.kInvalidIndex)
            {
                //EmitCode(": " + funcDefNode.ReturnType.Name);
            }

            if (funcDefNode.Singnature != null)
            {
                //EmitCode(funcDefNode.Singnature.ToString());
            }
            else
            {
                //EmitCode("()\n");
            }

            if (null != funcDefNode.FunctionBody)
            {
                List <ProtoCore.AST.AssociativeAST.AssociativeNode> funcBody = funcDefNode.FunctionBody.Body;

                //EmitCode("{\n");
                foreach (ProtoCore.AST.AssociativeAST.AssociativeNode bodyNode in funcBody)
                {
                    if (bodyNode is ProtoCore.AST.AssociativeAST.BinaryExpressionNode)
                    {
                        AST.AssociativeAST.BinaryExpressionNode binaryEpr = bodyNode as AST.AssociativeAST.BinaryExpressionNode;
                        EmitBinaryNode(ref binaryEpr);
                    }

                    if (bodyNode is ProtoCore.AST.AssociativeAST.ReturnNode)
                    {
                        AST.AssociativeAST.ReturnNode returnNode = bodyNode as ProtoCore.AST.AssociativeAST.ReturnNode;
                        EmitReturnNode(ref returnNode);
                    }
                    //EmitCode(";\n");
                }
                //EmitCode("}");
            }
            //EmitCode("\n");
        }
예제 #7
0
        public void GraphILTest_Assign01a()
        {
            ////////////////////////////////////////////////////////////////////
            // Adds a node => a = 10;
            // Creates Subtree, Deletes the node,
            // Creates Subtree and sync data and executes it via delta execution
            ////////////////////////////////////////////////////////////////////

            // Build the AST trees
            ProtoCore.AST.AssociativeAST.BinaryExpressionNode assign = new ProtoCore.AST.AssociativeAST.BinaryExpressionNode(
                new ProtoCore.AST.AssociativeAST.IdentifierNode("a"),
                new ProtoCore.AST.AssociativeAST.IntNode(10),
                ProtoCore.DSASM.Operator.assign);
            List<ProtoCore.AST.AssociativeAST.AssociativeNode> astList = new List<ProtoCore.AST.AssociativeAST.AssociativeNode>();
            astList.Add(assign);

            // Instantiate GraphSyncData
            List<Subtree> addedList = new List<Subtree>();
            System.Guid guid1 = System.Guid.NewGuid();
            addedList.Add(new Subtree(astList, guid1));
            GraphSyncData syncData = new GraphSyncData(null, addedList, null);

            // emit the DS code from the AST tree
            ProtoScript.Runners.ILiveRunner liveRunner = new ProtoScript.Runners.LiveRunner();
            liveRunner.UpdateGraph(syncData);

            ProtoCore.Mirror.RuntimeMirror mirror = liveRunner.InspectNodeValue("a");
            Assert.IsTrue((Int64)mirror.GetData().Data == 10);

            astList = new List<ProtoCore.AST.AssociativeAST.AssociativeNode>();
            astList.Add(assign);
            List<Subtree> deletedList = new List<Subtree>();
            deletedList.Add(new Subtree(astList, guid1));

            syncData = new GraphSyncData(deletedList, null, null);
            // emit the DS code from the AST tree
            liveRunner.UpdateGraph(syncData);

            mirror = liveRunner.InspectNodeValue("a");
            Assert.IsTrue(mirror.GetData().IsNull);
        }
예제 #8
0
        public void GraphILTest_Assign01()
        {
            // Build the AST trees
            ProtoCore.AST.AssociativeAST.BinaryExpressionNode assign = new ProtoCore.AST.AssociativeAST.BinaryExpressionNode(
                new ProtoCore.AST.AssociativeAST.IdentifierNode("a"),
                new ProtoCore.AST.AssociativeAST.IntNode(10),
                ProtoCore.DSASM.Operator.assign);
            List<ProtoCore.AST.AssociativeAST.AssociativeNode> astList = new List<ProtoCore.AST.AssociativeAST.AssociativeNode>();
            astList.Add(assign);

            // Instantiate GraphSyncData
            List<Subtree> addedList = new List<Subtree>();
            addedList.Add(new Subtree(astList, System.Guid.NewGuid()));
            GraphSyncData syncData = new GraphSyncData(null, addedList, null);

            // emit the DS code from the AST tree
            ProtoScript.Runners.ILiveRunner liveRunner = new ProtoScript.Runners.LiveRunner();
            liveRunner.UpdateGraph(syncData);

            ProtoCore.Mirror.RuntimeMirror mirror = liveRunner.InspectNodeValue("a");
            Assert.IsTrue((Int64)mirror.GetData().Data == 10);
        }
예제 #9
0
        private AssociativeNode ContextDataMethodCallNode(IContextData data)
        {
            string appname          = data.ContextProvider.Name;
            string connectionstring = data.Name;
            string varname          = data.Name;
            //
            //Build a functioncall node for expression varname = ImportData(appname, connectionstring);

            var func = new ProtoCore.AST.AssociativeAST.IdentifierNode();

            func.Value = func.Name = ProtoCore.DSASM.Constants.kImportData;

            var paramAppName = new ProtoCore.AST.AssociativeAST.StringNode();

            paramAppName.Value = appname;

            var paramConnectionString = new ProtoCore.AST.AssociativeAST.StringNode();

            paramConnectionString.Value = connectionstring;

            var funcCall = new ProtoCore.AST.AssociativeAST.FunctionCallNode();

            funcCall.Function = func;
            funcCall.Name     = ProtoCore.DSASM.Constants.kImportData;
            funcCall.FormalArguments.Add(paramAppName);
            funcCall.FormalArguments.Add(paramConnectionString);

            var var = new ProtoCore.AST.AssociativeAST.IdentifierNode();

            var.Name = var.Value = varname;

            var assignExpr = new ProtoCore.AST.AssociativeAST.BinaryExpressionNode();

            assignExpr.LeftNode  = var;
            assignExpr.Optr      = ProtoCore.DSASM.Operator.assign;
            assignExpr.RightNode = funcCall;

            return(assignExpr);
        }
예제 #10
0
        private List<AssociativeNode> SplitBinaryExpression(BinaryExpressionNode node)
        {
            List<AssociativeNode> nodes = new List<AssociativeNode>();

            if (node.isMultipleAssign)
            {
                DFSEmitSplitAssign_AST(node, ref nodes);
                foreach (AssociativeNode anode in nodes)
                {
                    if (node.Kind == AstKind.BinaryExpression)
                    {
                        var binaryExpression = node as BinaryExpressionNode;
                        NodeUtils.SetNodeLocation(anode, binaryExpression.LeftNode, binaryExpression.RightNode);
                    }
                }
            }
            else
            {
                nodes.Add(node);
            }

            return nodes;
        }
예제 #11
0
        private void DFSEmitSSA_AST(AssociativeNode node, Stack<AssociativeNode> ssaStack, ref List<AssociativeNode> astlist)
        {
            Validity.Assert(null != astlist && null != ssaStack);
            if (node is BinaryExpressionNode)
            {
                BinaryExpressionNode astBNode = node as BinaryExpressionNode;
                AssociativeNode leftNode = null;
                AssociativeNode rightNode = null;
                bool isSSAAssignment = false;
                if (ProtoCore.DSASM.Operator.assign == astBNode.Optr)
                {
                    leftNode = astBNode.LeftNode;
                    DFSEmitSSA_AST(astBNode.RightNode, ssaStack, ref astlist);
                    AssociativeNode assocNode = ssaStack.Pop();

                    if (assocNode is BinaryExpressionNode)
                    {
                        rightNode = (assocNode as BinaryExpressionNode).LeftNode;
                    }
                    else
                    {
                        rightNode = assocNode;
                    }
                    isSSAAssignment = false;

                    // Handle SSA if the lhs is not an identifier
                    // A non-identifier LHS is any LHS that is not just an identifier name.
                    //  i.e. a[0], a.b, f(), f(x)
                    var isSingleIdentifier = (leftNode is IdentifierNode) && (leftNode as IdentifierNode).ArrayDimensions == null;
                    if (!isSingleIdentifier)
                    {
                        EmitSSALHS(ref leftNode, ssaStack, ref astlist);
                    }
                }
                else
                {
                    BinaryExpressionNode tnode = new BinaryExpressionNode();
                    tnode.Optr = astBNode.Optr;

                    DFSEmitSSA_AST(astBNode.LeftNode, ssaStack, ref astlist);
                    DFSEmitSSA_AST(astBNode.RightNode, ssaStack, ref astlist);

                    AssociativeNode lastnode = ssaStack.Pop();
                    AssociativeNode prevnode = ssaStack.Pop();

                    tnode.LeftNode = prevnode is BinaryExpressionNode ? (prevnode as BinaryExpressionNode).LeftNode : prevnode;
                    tnode.RightNode = lastnode is BinaryExpressionNode ? (lastnode as BinaryExpressionNode).LeftNode : lastnode;

                    // Left node
                    leftNode = AstFactory.BuildIdentifier(CoreUtils.BuildSSATemp(core));

                    // Right node
                    rightNode = tnode;

                    isSSAAssignment = true;
                }

                var bnode = AstFactory.BuildAssignment(leftNode, rightNode);
                bnode.isSSAAssignment = isSSAAssignment;
                bnode.IsInputExpression = astBNode.IsInputExpression;

                astlist.Add(bnode);
                ssaStack.Push(bnode);
            }
            else if (node is ArrayNode)
            {
                var arrayNode = node as ArrayNode;
                DFSEmitSSA_AST(arrayNode.Expr, ssaStack, ref astlist);

                var bnode = new BinaryExpressionNode { Optr = Operator.assign };

                // Left node
                var tmpIdent = AstFactory.BuildIdentifier(CoreUtils.BuildSSATemp(core));
                Validity.Assert(null != tmpIdent);
                bnode.LeftNode = tmpIdent;

                if (arrayNode.Expr == null && arrayNode.Type == null)
                {
                    // Right node
                    bnode.RightNode = new NullNode();
                    astlist.Add(bnode);
                    ssaStack.Push(bnode);
                    return;
                }

                // pop off the dimension
                var dimensionNode = ssaStack.Pop();
                ArrayNode currentDimensionNode;
                if (dimensionNode is BinaryExpressionNode)
                {
                    currentDimensionNode = new ArrayNode((dimensionNode as BinaryExpressionNode).LeftNode, null);
                }
                else
                {
                    currentDimensionNode = new ArrayNode(dimensionNode, null);
                }

                // Pop the prev SSA node where the current dimension will apply
                AssociativeNode nodePrev = ssaStack.Pop();
                if (nodePrev is BinaryExpressionNode)
                {
                    AssociativeNode rhsIdent =AstFactory.BuildIdentifier((nodePrev as BinaryExpressionNode).LeftNode.Name);
                    (rhsIdent as IdentifierNode).ArrayDimensions = currentDimensionNode;

                    bnode.RightNode = rhsIdent;

                    astlist.Add(bnode);
                    ssaStack.Push(bnode);

                    if (null != arrayNode.Type)
                    {
                        DFSEmitSSA_AST(arrayNode.Type, ssaStack, ref astlist);
                    }
                }
                else if (nodePrev is IdentifierListNode)
                {
                    IdentifierNode iNode = (nodePrev as IdentifierListNode).RightNode as IdentifierNode;
                    Validity.Assert(null != iNode);
                    iNode.ArrayDimensions = currentDimensionNode;


                    if (null != arrayNode.Type)
                    {
                        DFSEmitSSA_AST(arrayNode.Type, ssaStack, ref astlist);
                    }
                }
                else
                {
                    Validity.Assert(false);
                }
            }
            else if (node is IdentifierNode)
            {
                IdentifierNode ident = node as IdentifierNode;

                if (core.Options.GenerateSSA)
                {
                    string ssaTempName = string.Empty;
                    if (null == ident.ArrayDimensions)
                    {
                        BinaryExpressionNode bnode = new BinaryExpressionNode();
                        bnode.Optr = ProtoCore.DSASM.Operator.assign;

                        // Left node
                        ssaTempName = ProtoCore.Utils.CoreUtils.BuildSSATemp(core);
                        var identNode =AstFactory.BuildIdentifier(ssaTempName);
                        bnode.LeftNode = identNode;

                        // Right node
                        bnode.RightNode = ident;

                        bnode.isSSAAssignment = true;

                        astlist.Add(bnode);
                        ssaStack.Push(bnode);

                        // Associate the first pointer with each SSA temp
                        // It is acceptable to store firstVar even if it is not a pointer as ResolveFinalNodeRefs() will just ignore this entry 
                        // if this ssa temp is not treated as a pointer inside the function
                        string firstVar = ident.Name;
                        ssaTempToFirstPointerMap.Add(ssaTempName, firstVar);
                    }
                    else
                    {
                        EmitSSAArrayIndex(ident, ssaStack, ref astlist);
                    }
                }
                else
                {
                    BinaryExpressionNode bnode = new BinaryExpressionNode();
                    bnode.Optr = ProtoCore.DSASM.Operator.assign;

                    // Left node
                    var identNode =AstFactory.BuildIdentifier(ProtoCore.Utils.CoreUtils.BuildSSATemp(core));
                    bnode.LeftNode = identNode;

                    // Right node
                    bnode.RightNode = ident;


                    bnode.isSSAAssignment = true;

                    astlist.Add(bnode);
                    ssaStack.Push(bnode);
                }
            }
            else if (node is FunctionCallNode || node is FunctionDotCallNode)
            {
                FunctionCallNode fcNode = null;
                if (node is FunctionCallNode)
                {
                    fcNode = new FunctionCallNode(node as FunctionCallNode);

                    List<AssociativeNode> astlistArgs = new List<AssociativeNode>();

                    for (int idx = 0; idx < fcNode.FormalArguments.Count; idx++)
                    {
                        AssociativeNode arg = fcNode.FormalArguments[idx];
                        DFSEmitSSA_AST(arg, ssaStack, ref astlistArgs);
                        AssociativeNode argNode = ssaStack.Pop();

                        if (argNode is BinaryExpressionNode)
                        {
                            BinaryExpressionNode argBinaryExpr = argNode as BinaryExpressionNode;
                            var argLeftNode = argBinaryExpr.LeftNode as IdentifierNode;
                            argLeftNode.ReplicationGuides = GetReplicationGuides(arg);
                            argLeftNode.AtLevel = GetAtLevel(arg);
                            
                            fcNode.FormalArguments[idx] = argBinaryExpr.LeftNode;
                        }
                        else
                        {
                            fcNode.FormalArguments[idx] = argNode;
                        }
                        astlist.AddRange(astlistArgs);
                        astlistArgs.Clear();
                    }
                }

                // Left node
                var leftNode =AstFactory.BuildIdentifier(CoreUtils.BuildSSATemp(core));
                if (null != fcNode)
                {
                    leftNode.ReplicationGuides = GetReplicationGuides(fcNode);
                    leftNode.AtLevel = GetAtLevel(fcNode);
                }

                var bnode = AstFactory.BuildAssignment(leftNode, fcNode);
                bnode.isSSAAssignment = true;

                astlist.Add(bnode);
                ssaStack.Push(bnode);
            }
            else if (node is IdentifierListNode)
            {
                SSAIdentList(node, ref ssaStack, ref astlist);
                AssociativeNode lastNode = null;
                Validity.Assert(astlist.Count > 0);

                // Get the last identifierlist node and set its flag
                // This is required to reset the pointerlist for every identifierlist traversed
                // i.e. 
                //      a = p.x
                //      reset the flag after traversing p.x
                //
                //      b = p.x + g.y    
                //      reset the flag after traversing p.x and p.y
                //
                int lastIndex = astlist.Count - 1;
                for (int n = lastIndex; n >= 0 ; --n)
                {
                    lastNode = astlist[n];
                    Validity.Assert(lastNode is BinaryExpressionNode);
                    
                    BinaryExpressionNode bnode = lastNode as BinaryExpressionNode;
                    Validity.Assert(bnode.Optr == Operator.assign);
                    if (bnode.RightNode is IdentifierListNode)
                    {
                        IdentifierListNode identList = bnode.RightNode as IdentifierListNode;
                        identList.IsLastSSAIdentListFactor = true;
                        break;
                    }
                }
                
                // Assign the first ssa assignment flag
                BinaryExpressionNode firstBNode = astlist[0] as BinaryExpressionNode;
                Validity.Assert(null != firstBNode);
                Validity.Assert(firstBNode.Optr == Operator.assign);
                firstBNode.isSSAFirstAssignment = true;


                //
                // Get the first pointer
                // The first pointer is the lhs of the next dotcall
                //
                // Given:     
                //      a = x.y.z
                // SSA'd to:     
                //      t0 = x      -> 'x' is the lhs of the first dotcall (x.y)
                //      t1 = t0.y
                //      t2 = t1.z
                //      a = t2

                IdentifierNode lhsIdent = null;
                if (firstBNode.RightNode is IdentifierNode)
                {
                    // In this case the rhs of the ident list is an ident
                    // Get the ident name
                    lhsIdent = (firstBNode.RightNode as IdentifierNode);
                }
                else if(firstBNode.RightNode is FunctionCallNode)
                {
                    // In this case the rhs of the ident list is a function
                    // Get the function name
                    lhsIdent = (firstBNode.RightNode as FunctionCallNode).Function as IdentifierNode;
                }   
                else
                {

                    lhsIdent = null;
                }

                //=========================================================
                //
                // 1. Backtrack and convert all identlist nodes to dot calls
                //    This can potentially be optimized by performing the dotcall transform in SSAIdentList
                //
                // 2. Associate the first pointer with each SSA temp
                //
                //=========================================================
                AssociativeNode prevNode = null;
                for (int n = 0; n <= lastIndex; n++)
                {
                    lastNode = astlist[n];

                    BinaryExpressionNode bnode = lastNode as BinaryExpressionNode;
                    Validity.Assert(bnode.Optr == Operator.assign);

                    // Get the ssa temp name
                    Validity.Assert(bnode.LeftNode is IdentifierNode);
                    string ssaTempName = (bnode.LeftNode as IdentifierNode).Name;
                    Validity.Assert(CoreUtils.IsSSATemp(ssaTempName));

                    if (bnode.RightNode is IdentifierListNode)
                    {
                        IdentifierListNode identList = bnode.RightNode as IdentifierListNode;
                        if (identList.RightNode is IdentifierNode)
                        {
                            IdentifierNode identNode = identList.RightNode as IdentifierNode;

                            ProtoCore.AST.AssociativeAST.FunctionCallNode rcall = new ProtoCore.AST.AssociativeAST.FunctionCallNode();
                            rcall.Function = new IdentifierNode(identNode);
                            rcall.Function.Name = ProtoCore.DSASM.Constants.kGetterPrefix + rcall.Function.Name;

                            ProtoCore.Utils.CoreUtils.CopyDebugData(identList.LeftNode, lhsIdent);
                            FunctionDotCallNode dotCall = ProtoCore.Utils.CoreUtils.GenerateCallDotNode(identList.LeftNode, rcall, core);
                            dotCall.isLastSSAIdentListFactor = identList.IsLastSSAIdentListFactor;
                            bnode.RightNode = dotCall;
                            ProtoCore.Utils.CoreUtils.CopyDebugData(bnode, lhsIdent);

                            // Update the LHS of the next dotcall
                            //      a = x.y.z
                            //      t0 = x      
                            //      t1 = t0.y   'y' is the lhs of the next dotcall (y.z)
                            //      t2 = t1.z
                            //      a = t2
                            //
                            Validity.Assert(rcall.Function is IdentifierNode);
                            lhsIdent = rcall.Function as IdentifierNode;
                        }
                        else if (identList.RightNode is FunctionCallNode)
                        {
                            FunctionCallNode fCallNode = identList.RightNode as FunctionCallNode;


                            ProtoCore.Utils.CoreUtils.CopyDebugData(identList.LeftNode, lhsIdent);
                            FunctionDotCallNode dotCall = ProtoCore.Utils.CoreUtils.GenerateCallDotNode(identList.LeftNode, fCallNode, core);
                            dotCall.isLastSSAIdentListFactor = identList.IsLastSSAIdentListFactor;
                            bnode.RightNode = dotCall;

                            ProtoCore.Utils.CoreUtils.CopyDebugData(bnode, lhsIdent);

                            // Update the LHS of the next dotcall
                            //      a = x.y.z
                            //      t0 = x      
                            //      t1 = t0.y   'y' is the lhs of the next dotcall (y.z)
                            //      t2 = t1.z
                            //      a = t2
                            //
                            Validity.Assert(fCallNode.Function is IdentifierNode);
                            lhsIdent = fCallNode.Function as IdentifierNode;
                        }
                        else
                        {
                            Validity.Assert(false);
                        }
                    }
                    prevNode = bnode.RightNode;
                }
            }
            else if (node is ExprListNode)
            {
                ExprListNode exprList = node as ExprListNode;
                for (int n = 0; n < exprList.Exprs.Count; n++)
                {
                    List<AssociativeNode> currentElementASTList = new List<AssociativeNode>();
                    DFSEmitSSA_AST(exprList.Exprs[n], ssaStack, ref currentElementASTList);

                    astlist.AddRange(currentElementASTList);
                    currentElementASTList.Clear();
                    AssociativeNode argNode = ssaStack.Pop();
                    exprList.Exprs[n] = argNode is BinaryExpressionNode ? (argNode as BinaryExpressionNode).LeftNode : argNode;
                }

                var leftNode = AstFactory.BuildIdentifier(CoreUtils.BuildSSATemp(core));
                var bnode = AstFactory.BuildAssignment(leftNode, exprList);
                bnode.isSSAAssignment = true;

                astlist.Add(bnode);
                ssaStack.Push(bnode);
            }
            else if (node is InlineConditionalNode)
            {
                InlineConditionalNode ilnode = node as InlineConditionalNode;

                List<AssociativeNode> inlineExpressionASTList = new List<AssociativeNode>();

                // Emit the boolean condition
                DFSEmitSSA_AST(ilnode.ConditionExpression, ssaStack, ref inlineExpressionASTList);
                AssociativeNode cexpr = ssaStack.Pop();
                ilnode.ConditionExpression = cexpr is BinaryExpressionNode ? (cexpr as BinaryExpressionNode).LeftNode : cexpr;
                var namenode = ilnode.ConditionExpression as ArrayNameNode;
                if (namenode != null)
                {
                    var rightNode = (cexpr is BinaryExpressionNode) ? (cexpr as BinaryExpressionNode).RightNode : cexpr; 
                    namenode.ReplicationGuides = GetReplicationGuides(rightNode);
                    namenode.AtLevel = GetAtLevel(rightNode);
                }
                astlist.AddRange(inlineExpressionASTList);
                inlineExpressionASTList.Clear();

                DFSEmitSSA_AST(ilnode.TrueExpression, ssaStack, ref inlineExpressionASTList);
                cexpr = ssaStack.Pop();
                ilnode.TrueExpression = cexpr is BinaryExpressionNode ? (cexpr as BinaryExpressionNode).LeftNode : cexpr;
                namenode = ilnode.TrueExpression as ArrayNameNode;
                if (namenode != null)
                {
                    var rightNode = (cexpr is BinaryExpressionNode) ? (cexpr as BinaryExpressionNode).RightNode : cexpr; 
                    namenode.ReplicationGuides = GetReplicationGuides(rightNode);
                    namenode.AtLevel = GetAtLevel(rightNode);
                }
                astlist.AddRange(inlineExpressionASTList);
                inlineExpressionASTList.Clear();

                DFSEmitSSA_AST(ilnode.FalseExpression, ssaStack, ref inlineExpressionASTList);
                cexpr = ssaStack.Pop();
                ilnode.FalseExpression = cexpr is BinaryExpressionNode ? (cexpr as BinaryExpressionNode).LeftNode : cexpr;
                namenode = ilnode.FalseExpression as ArrayNameNode;
                if (namenode != null)
                {
                    var rightNode = (cexpr is BinaryExpressionNode) ? (cexpr as BinaryExpressionNode).RightNode : cexpr; 
                    namenode.ReplicationGuides = GetReplicationGuides(rightNode);
                    namenode.AtLevel = GetAtLevel(rightNode);
                }
                astlist.AddRange(inlineExpressionASTList);
                inlineExpressionASTList.Clear();

                var leftNode = AstFactory.BuildIdentifier(CoreUtils.BuildSSATemp(core));
                var bnode = AstFactory.BuildAssignment(leftNode, ilnode);
                bnode.isSSAAssignment = true;

                astlist.Add(bnode);
                ssaStack.Push(bnode);
            }
            else if (node is RangeExprNode)
            {
                RangeExprNode rangeNode = node as RangeExprNode;

                DFSEmitSSA_AST(rangeNode.From, ssaStack, ref astlist);
                AssociativeNode fromExpr = ssaStack.Pop();
                rangeNode.From = fromExpr is BinaryExpressionNode ? (fromExpr as BinaryExpressionNode).LeftNode : fromExpr;

                DFSEmitSSA_AST(rangeNode.To, ssaStack, ref astlist);
                AssociativeNode toExpr = ssaStack.Pop();
                rangeNode.To = toExpr is BinaryExpressionNode ? (toExpr as BinaryExpressionNode).LeftNode : toExpr;

                if (rangeNode.Step != null)
                {
                    DFSEmitSSA_AST(rangeNode.Step, ssaStack, ref astlist);
                    AssociativeNode stepExpr = ssaStack.Pop();
                    rangeNode.Step = stepExpr is BinaryExpressionNode ? (stepExpr as BinaryExpressionNode).LeftNode : stepExpr;
                }

                var leftNode = AstFactory.BuildIdentifier(CoreUtils.BuildSSATemp(core));
                var bnode = AstFactory.BuildAssignment(leftNode, rangeNode);
                bnode.isSSAAssignment = true;

                astlist.Add(bnode);
                ssaStack.Push(bnode);
            }
            else if (node is GroupExpressionNode)
            {
                if (core.Options.GenerateSSA)
                {
                    GroupExpressionNode groupExpr = node as GroupExpressionNode;
                    if (null == groupExpr.ArrayDimensions)
                    {
                        DFSEmitSSA_AST(groupExpr.Expression, ssaStack, ref astlist);

                        var leftNode =AstFactory.BuildIdentifier(CoreUtils.BuildSSATemp(core));
                        AssociativeNode groupExprBinaryStmt = ssaStack.Pop();
                        var rightNode = (groupExprBinaryStmt as BinaryExpressionNode).LeftNode;

                        var bnode = AstFactory.BuildAssignment(leftNode, rightNode);
                        bnode.isSSAAssignment = true;

                        astlist.Add(bnode);
                        ssaStack.Push(bnode);
                    }
                    else
                    {
                        EmitSSAArrayIndex(groupExpr, ssaStack, ref astlist);
                    }
                }
                else
                {
                    // We never supported SSA on grouped expressions
                    // Keep it that way if SSA flag is off
                    ssaStack.Push(node);
                }
            }
            // We allow a null to be generated an SSA variable
            // TODO Jun: Generalize this into genrating SSA temps for all literals
            else if (node is NullNode)
            {
                var leftNode = AstFactory.BuildIdentifier(CoreUtils.BuildSSATemp(core));
                var bnode = AstFactory.BuildAssignment(leftNode, node);
                bnode.isSSAAssignment = true;

                astlist.Add(bnode);
                ssaStack.Push(bnode);
            }
            else
            {
                ssaStack.Push(node);
            }
        }
예제 #12
0
        private void EmitConstructorDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone)
        {
            ConstructorDefinitionNode funcDef = node as ConstructorDefinitionNode;
            ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType;
            codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction;

            if (IsParsingMemberFunctionSig())
            {
                Debug.Assert(null == localProcedure);
                localProcedure = new ProtoCore.DSASM.ProcedureNode();

                localProcedure.name = funcDef.Name;
                localProcedure.pc = ProtoCore.DSASM.Constants.kInvalidIndex;
                localProcedure.localCount = 0;// Defer till all locals are allocated
                localProcedure.returntype.UID = globalClassIndex;
                localProcedure.returntype.IsIndexable = false;
                localProcedure.isConstructor = true;
                localProcedure.runtimeIndex = 0;
                localProcedure.isExternal = funcDef.IsExternLib;
                Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class");
                localProcedure.localCount = 0;
                localProcedure.classScope = globalClassIndex;

                int peekFunctionindex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count;

                // Append arg symbols
                List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>();
                if (null != funcDef.Signature)
                {
                    int argNumber = 0;
                    foreach (VarDeclNode argNode in funcDef.Signature.Arguments)
                    {
                        ++argNumber;

                        IdentifierNode paramNode = null;
                        bool aIsDefault = false;
                        ProtoCore.AST.Node aDefaultExpression = null;
                        if (argNode.NameNode is IdentifierNode)
                        {
                            paramNode = argNode.NameNode as IdentifierNode;
                        }
                        else if (argNode.NameNode is BinaryExpressionNode)
                        {
                            BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode;
                            paramNode = bNode.LeftNode as IdentifierNode;
                            aIsDefault = true;
                            aDefaultExpression = bNode;
                            //buildStatus.LogSemanticError("Default parameters are not supported");
                            //throw new BuildHaltException();
                        }
                        else
                        {
                            Debug.Assert(false, "Check generated AST");
                        }

                        ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode);
                        argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(paramNode.Value, argType));
                        localProcedure.argTypeList.Add(argType);
                        ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { Name = paramNode.Value, isDefault = aIsDefault, defaultExpression = aDefaultExpression };
                        localProcedure.argInfoList.Add(argInfo);
                    }
                }

                int findex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.Append(localProcedure);

                // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur
                if (ProtoCore.DSASM.Constants.kInvalidIndex != findex)
                {
                    Debug.Assert(peekFunctionindex == localProcedure.procId);
                    argsToBeAllocated.ForEach(arg =>
                    {
                        int symbolIndex = AllocateArg(arg.Key, findex, arg.Value);
                        if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex)
                        {
                            throw new BuildHaltException("44B557F1");
                        }
                    });
                }
                else
                {
                    string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodAlreadyDefined, localProcedure.name);
                    buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col);
                    funcDef.skipMe = true;
                }
            }
            else if (IsParsingMemberFunctionBody())
            {
                EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature, true));
                // Build arglist for comparison
                List<ProtoCore.Type> argList = new List<ProtoCore.Type>();
                if (null != funcDef.Signature)
                {
                    foreach (VarDeclNode argNode in funcDef.Signature.Arguments)
                    {
                        ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode);
                        argList.Add(argType);
                    }
                }

                globalProcIndex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList);

                Debug.Assert(null == localProcedure);
                localProcedure = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex];

                Debug.Assert(null != localProcedure);
                localProcedure.Attributes = PopulateAttributes(funcDef.Attributes);
                // Its only on the parse body pass where the real pc is determined. Update this procedures' pc
                //Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc);
                localProcedure.pc = pc;

                EmitInstrConsole(ProtoCore.DSASM.kw.allocc, localProcedure.name);
                EmitAllocc(globalClassIndex);
                setConstructorStartPC = true;

                EmitCallingForBaseConstructor(globalClassIndex, funcDef.baseConstr);

                ProtoCore.FunctionEndPoint fep = null;
                if (!funcDef.IsExternLib)
                {
                    // Traverse default assignment for the class
                    emitDebugInfo = false;
                    foreach (BinaryExpressionNode bNode in compileStateTracker.ClassTable.ClassNodes[globalClassIndex].defaultArgExprList)
                    {

                        ProtoCore.AssociativeGraph.GraphNode graphNode = new ProtoCore.AssociativeGraph.GraphNode();
                        graphNode.isParent = true;
                        graphNode.exprUID = bNode.exprUID;
                        graphNode.modBlkUID = bNode.modBlkUID;
                        graphNode.procIndex = globalProcIndex;
                        graphNode.classIndex = globalClassIndex;
                        graphNode.isAutoGenerated = true;

                        EmitBinaryExpressionNode(bNode, ref inferedType, false, graphNode, subPass);
                    }

                    //Traverse default argument for the constructor
                    foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList)
                    {
                        if (!argNode.isDefault)
                        {
                            continue;
                        }
                        BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode;
                        // build a temporay node for statement : temp = defaultarg;
                        var iNodeTemp = nodeBuilder.BuildIdentfier(Constants.kTempDefaultArg);
                        BinaryExpressionNode bNodeTemp = new BinaryExpressionNode();
                        bNodeTemp.LeftNode = iNodeTemp;
                        bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign;
                        bNodeTemp.RightNode = bNode.LeftNode;
                        EmitBinaryExpressionNode(bNodeTemp, ref inferedType);
                        //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp;
                        InlineConditionalNode icNode = new InlineConditionalNode();
                        icNode.IsAutoGenerated = true;
                        BinaryExpressionNode cExprNode = new BinaryExpressionNode();
                        cExprNode.Optr = ProtoCore.DSASM.Operator.eq;
                        cExprNode.LeftNode = iNodeTemp;
                        cExprNode.RightNode = new DefaultArgNode();
                        icNode.ConditionExpression = cExprNode;
                        icNode.TrueExpression = bNode.RightNode;
                        icNode.FalseExpression = iNodeTemp;
                        bNodeTemp.LeftNode = bNode.LeftNode;
                        bNodeTemp.RightNode = icNode;
                        EmitBinaryExpressionNode(bNodeTemp, ref inferedType);
                    }
                    emitDebugInfo = true;

                    // Traverse definition
                    foreach (AssociativeNode bnode in funcDef.FunctionBody.Body)
                    {
                        inferedType.UID = (int)PrimitiveType.kTypeVoid;
                        inferedType.rank = 0;

                        if (bnode is LanguageBlockNode)
                        {
                            // Build a binaryn node with a temporary lhs for every stand-alone language block
                            var iNode = nodeBuilder.BuildIdentfier(compileStateTracker.GenerateTempLangageVar());
                            BinaryExpressionNode langBlockNode = new BinaryExpressionNode();
                            langBlockNode.LeftNode = iNode;
                            langBlockNode.Optr = ProtoCore.DSASM.Operator.assign;
                            langBlockNode.RightNode = bnode;
                            DfsTraverse(langBlockNode, ref inferedType, false, null, subPass);
                        }
                        else
                        {
                            DfsTraverse(bnode, ref inferedType, false, null, subPass);
                        }
                    }

                    // All locals have been stack allocated, update the local count of this function
                    localProcedure.localCount = compileStateTracker.BaseOffset;
                    compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex].localCount = compileStateTracker.BaseOffset;

                    // Update the param stack indices of this function
                    foreach (ProtoCore.DSASM.SymbolNode symnode in compileStateTracker.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList.Values)
                    {
                        if (symnode.functionIndex == globalProcIndex && symnode.isArgument)
                        {
                            symnode.index -= localProcedure.localCount;
                        }
                    }

                    // JIL FEP
                    ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord();
                    record.pc = localProcedure.pc;
                    record.locals = localProcedure.localCount;
                    record.classIndex = globalClassIndex;
                    record.funcIndex = globalProcIndex;

                    // Construct the fep arguments
                    fep = new ProtoCore.Lang.JILFunctionEndPoint(record);
                }
                else
                {
                    ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord();
                    jRecord.pc = localProcedure.pc;
                    jRecord.locals = localProcedure.localCount;
                    jRecord.classIndex = globalClassIndex;
                    jRecord.funcIndex = localProcedure.procId;

                    ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord();
                    record.JILRecord = jRecord;
                    record.FunctionName = funcDef.Name;
                    record.ModuleName = funcDef.ExternLibName;
                    record.ModuleType = "dll";
                    record.IsDNI = false;
                    record.ReturnType = funcDef.ReturnType;
                    record.ParameterTypes = localProcedure.argTypeList;
                    fep = new ProtoCore.Lang.FFIFunctionEndPoint(record);
                }

                // Construct the fep arguments
                fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count];
                fep.procedureNode = localProcedure;
                localProcedure.argTypeList.CopyTo(fep.FormalParams, 0);

                // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables
                // Determine whether this still needs to be aligned to the actual 'classIndex' variable
                // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged
                int classIndexAtCallsite = globalClassIndex + 1;
                compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep);

                int startpc = pc;

                // Constructors auto return
                EmitInstrConsole(ProtoCore.DSASM.kw.retc);

                // Stepping out of a constructor body will have the execution cursor
                // placed right at the closing curly bracket of the constructor definition.
                //
                int closeCurlyBracketLine = 0, closeCurlyBracketColumn = -1;
                if (null != funcDef.FunctionBody)
                {
                    closeCurlyBracketLine = funcDef.FunctionBody.endLine;
                    closeCurlyBracketColumn = funcDef.FunctionBody.endCol;
                }

                // The execution cursor covers exactly one character -- the closing
                // curly bracket. Note that we decrement the start-column by one here
                // because end-column of "FunctionBody" here is *after* the closing
                // curly bracket, so we want one before that.
                //
                EmitRetc(closeCurlyBracketLine, closeCurlyBracketColumn - 1,
                    closeCurlyBracketLine, closeCurlyBracketColumn);

                // Build and append a graphnode for this return statememt
                ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode();
                returnNode.name = ProtoCore.DSDefinitions.Keyword.Return;

                ProtoCore.AssociativeGraph.GraphNode retNode = new ProtoCore.AssociativeGraph.GraphNode();
                //retNode.symbol = returnNode;
                retNode.PushSymbolReference(returnNode);
                retNode.procIndex = globalProcIndex;
                retNode.classIndex = globalClassIndex;
                retNode.updateBlock.startpc = startpc;
                retNode.updateBlock.endpc = pc - 1;

                codeBlock.instrStream.dependencyGraph.Push(retNode);
                EmitCompileLogFunctionEnd();
            }

            // Constructors have no return statemetns, reset variables here
            compileStateTracker.ProcNode = localProcedure = null;
            globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope;
            compileStateTracker.BaseOffset = 0;
            argOffset = 0;
            classOffset = 0;
            codeBlock.blockType = originalBlockType;
        }
예제 #13
0
        private void EmitFunctionCall(int depth, 
                                      int type,
                                      List<ProtoCore.Type> arglist, 
                                      ProcedureNode procNode, 
                                      FunctionCallNode funcCall, 
                                      bool isGetter = false, 
                                      BinaryExpressionNode parentExpression = null)
        {
            int blockId = procNode.RuntimeIndex;

            //push value-not-provided default argument
            for (int i = arglist.Count; i < procNode.ArgumentInfos.Count; i++)
            {
                EmitDefaultArgNode();
            }

            // Push the function declaration block and indexed array
            // Jun TODO: Implementeation of indexing into a function call:
            //  x = f()[0][1]
            int dimensions = 0;
            EmitPushVarData(dimensions);

            // Emit depth
            EmitInstrConsole(kw.push, depth + "[depth]");
            EmitPush(StackValue.BuildInt(depth));

            // The function call
            EmitInstrConsole(ProtoCore.DSASM.kw.callr, procNode.Name);

            if (isGetter)
            {
                EmitCall(procNode.ID, blockId, type, 
                         Constants.kInvalidIndex, Constants.kInvalidIndex,
                         Constants.kInvalidIndex, Constants.kInvalidIndex, 
                         procNode.PC);
            }
            // Break at function call inside dynamic lang block created for a 'true' or 'false' expression inside an inline conditional
            else if (core.DebuggerProperties.breakOptions.HasFlag(DebugProperties.BreakpointOptions.EmitInlineConditionalBreakpoint))
            {
                ProtoCore.CodeModel.CodePoint startInclusive = core.DebuggerProperties.highlightRange.StartInclusive;
                ProtoCore.CodeModel.CodePoint endExclusive = core.DebuggerProperties.highlightRange.EndExclusive;

                EmitCall(procNode.ID, blockId, type, startInclusive.LineNo, startInclusive.CharNo, endExclusive.LineNo, endExclusive.CharNo, procNode.PC);
            }
            else if (parentExpression != null)
            {
                EmitCall(procNode.ID, blockId, type, parentExpression.line, parentExpression.col, parentExpression.endLine, parentExpression.endCol, procNode.PC);
            }
            else
            {
                EmitCall(procNode.ID, blockId, type, funcCall.line, funcCall.col, funcCall.endLine, funcCall.endCol, procNode.PC);
            }

            // The function return value
            EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX);
            StackValue opReturn = StackValue.BuildRegister(Registers.RX);
            EmitPush(opReturn);
        }
예제 #14
0
        private void BuildThisFunctionBody(ThisPointerProcOverload procOverload)
        {
            BinaryExpressionNode thisFunctionBody = new BinaryExpressionNode();
            IdentifierNode leftNode = new IdentifierNode();
            leftNode.Name = leftNode.Value = ProtoCore.DSDefinitions.Keyword.Return;
            thisFunctionBody.LeftNode = leftNode;

            thisFunctionBody.Optr = Operator.assign;


            // Build the function call and pass it the arguments including the this pointer
            FunctionCallNode fcall = new FunctionCallNode();
            IdentifierNode identNode = new IdentifierNode();
            identNode.Name = procOverload.procNode.Name;
            fcall.Function = identNode;

            // Set the arguments passed into the function excluding the 'this' argument
            List<AssociativeNode> args = new List<AssociativeNode>();
            for (int n = 1; n < procOverload.procNode.Signature.Arguments.Count; ++n)
            {
                VarDeclNode varDecl = procOverload.procNode.Signature.Arguments[n];
                args.Add(varDecl.NameNode);
            }
            fcall.FormalArguments = args;


            // Build the dotcall node
            procOverload.procNode.FunctionBody.Body = new List<AssociativeNode>();
            procOverload.procNode.FunctionBody.Body.Add(thisFunctionBody);

            thisFunctionBody.RightNode = CoreUtils.GenerateCallDotNode(procOverload.procNode.Signature.Arguments[0].NameNode, fcall, core);
        }
예제 #15
0
        /// <summary>
        /// Emits a block of code for the following cases:
        ///     Language block body
        ///     Function body
        ///     Constructor body
        /// </summary>
        /// <param name="astList"></param>
        /// <param name="inferedType"></param>
        /// <param name="subPass"></param>
        private bool EmitCodeBlock(
            List<AssociativeNode> astList, 
            ref ProtoCore.Type inferedType, 
            ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass,
            bool isProcedureOwned
            )
        {
            bool hasReturnStatement = false;
            foreach (AssociativeNode bnode in astList)
            {
                inferedType.UID = (int)PrimitiveType.kTypeVar;
                inferedType.rank = 0;

                if (bnode is LanguageBlockNode)
                {
                    // Build a binaryn node with a temporary lhs for every stand-alone language block
                    var iNode =AstFactory.BuildIdentifier(core.GenerateTempLangageVar());
                    BinaryExpressionNode langBlockNode = new BinaryExpressionNode();
                    langBlockNode.LeftNode = iNode;
                    langBlockNode.Optr = ProtoCore.DSASM.Operator.assign;
                    langBlockNode.RightNode = bnode;
                    langBlockNode.IsProcedureOwned = isProcedureOwned;
                    DfsTraverse(langBlockNode, ref inferedType, false, null, subPass);
                }
                else
                {
                    bnode.IsProcedureOwned = isProcedureOwned;
                    DfsTraverse(bnode, ref inferedType, false, null, subPass);
                }

                if (NodeUtils.IsReturnExpressionNode(bnode))
                {
                    hasReturnStatement = true;
                }
            }

            return hasReturnStatement;
        }
예제 #16
0
        private void EmitConstructorDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, GraphNode gNode = null)
        {
            ConstructorDefinitionNode funcDef = node as ConstructorDefinitionNode;
            ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType;
            codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction;

            if (IsParsingMemberFunctionSig())
            {
                Validity.Assert(null == localProcedure);
                localProcedure = new ProtoCore.DSASM.ProcedureNode();

                localProcedure.Name = funcDef.Name;
                localProcedure.PC = ProtoCore.DSASM.Constants.kInvalidIndex;
                localProcedure.LocalCount = 0;// Defer till all locals are allocated
                ProtoCore.Type returnType = localProcedure.ReturnType; 
                if (globalClassIndex != -1)
                    returnType.Name = core.ClassTable.ClassNodes[globalClassIndex].Name;
                returnType.UID = globalClassIndex;
                returnType.rank = 0;
                localProcedure.ReturnType = returnType;
                localProcedure.IsConstructor = true;
                localProcedure.RuntimeIndex = 0;
                localProcedure.IsExternal = funcDef.IsExternLib;
                Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class");
                localProcedure.LocalCount = 0;
                localProcedure.ClassID = globalClassIndex;

                localProcedure.MethodAttribute = funcDef.MethodAttributes;

                int peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures.Count;

                // Append arg symbols
                List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>();
                if (null != funcDef.Signature)
                {
                    foreach (VarDeclNode argNode in funcDef.Signature.Arguments)
                    {
                        var argInfo = BuildArgumentInfoFromVarDeclNode(argNode); 
                        localProcedure.ArgumentInfos.Add(argInfo);

                        var argType = BuildArgumentTypeFromVarDeclNode(argNode, gNode);
                        localProcedure.ArgumentTypes.Add(argType);

                        argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(argInfo.Name, argType));
                    }

                    localProcedure.IsVarArg = funcDef.Signature.IsVarArg;
                }

                int findex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Append(localProcedure);

                // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur
                if (ProtoCore.DSASM.Constants.kInvalidIndex != findex)
                {
                    Validity.Assert(peekFunctionindex == localProcedure.ID);
                    argsToBeAllocated.ForEach(arg =>
                    {
                        int symbolIndex = AllocateArg(arg.Key, findex, arg.Value);
                        if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex)
                        {
                            throw new BuildHaltException("44B557F1");
                        }
                    });
                }
                else
                {
                    string message = String.Format(ProtoCore.Properties.Resources.kMethodAlreadyDefined, localProcedure.Name);
                    buildStatus.LogWarning(WarningID.kFunctionAlreadyDefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, gNode);
                    funcDef.skipMe = true;
                }
            }
            else if (IsParsingMemberFunctionBody())
            {
                EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature, true));
                // Build arglist for comparison
                List<ProtoCore.Type> argList = new List<ProtoCore.Type>();
                if (null != funcDef.Signature)
                {
                    foreach (VarDeclNode argNode in funcDef.Signature.Arguments)
                    {
                        ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, gNode);
                        argList.Add(argType);
                    }
                }

                var procNode = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.GetFunctionBySignature(funcDef.Name, argList);
                globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID;

                Validity.Assert(null == localProcedure);
                localProcedure = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex];

                Validity.Assert(null != localProcedure);
                localProcedure.Attributes = PopulateAttributes(funcDef.Attributes);
                // Its only on the parse body pass where the real pc is determined. Update this procedures' pc
                //Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc);
                localProcedure.PC = pc;

                EmitInstrConsole(ProtoCore.DSASM.kw.allocc, localProcedure.Name);
                EmitAllocc(globalClassIndex);
                setConstructorStartPC = true;

                EmitCallingForBaseConstructor(globalClassIndex, funcDef.BaseConstructor);

                ProtoCore.FunctionEndPoint fep = null;
                if (!funcDef.IsExternLib)
                {
                    // Traverse default assignment for the class
                    emitDebugInfo = false;

                    List<AssociativeNode> defaultArgList = core.ClassTable.ClassNodes[globalClassIndex].DefaultArgExprList;
                    defaultArgList = BuildSSA(defaultArgList, context);
                    foreach (BinaryExpressionNode bNode in defaultArgList)
                    {
                        ProtoCore.AssociativeGraph.GraphNode graphNode = new ProtoCore.AssociativeGraph.GraphNode();
                        graphNode.exprUID = bNode.ExpressionUID;
                        graphNode.ssaExpressionUID = bNode.SSAExpressionUID;
                        graphNode.procIndex = globalProcIndex;
                        graphNode.classIndex = globalClassIndex;
                        graphNode.languageBlockId = codeBlock.codeBlockId;
                        graphNode.isAutoGenerated = true;
                        bNode.IsProcedureOwned = graphNode.ProcedureOwned = true;

                        EmitBinaryExpressionNode(bNode, ref inferedType, false, graphNode, subPass);
                    }

                    //Traverse default argument for the constructor
                    foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.ArgumentInfos)
                    {
                        if (!argNode.IsDefault)
                        {
                            continue;
                        }
                        BinaryExpressionNode bNode = argNode.DefaultExpression as BinaryExpressionNode;
                        // build a temporay node for statement : temp = defaultarg;
                        var iNodeTemp =AstFactory.BuildIdentifier(Constants.kTempDefaultArg);
                        BinaryExpressionNode bNodeTemp = new BinaryExpressionNode();
                        bNodeTemp.LeftNode = iNodeTemp;
                        bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign;
                        bNodeTemp.RightNode = bNode.LeftNode;
                        EmitBinaryExpressionNode(bNodeTemp, ref inferedType);
                        //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp;
                        InlineConditionalNode icNode = new InlineConditionalNode();
                        icNode.IsAutoGenerated = true;
                        BinaryExpressionNode cExprNode = new BinaryExpressionNode();
                        cExprNode.Optr = ProtoCore.DSASM.Operator.eq;
                        cExprNode.LeftNode = iNodeTemp;
                        cExprNode.RightNode = new DefaultArgNode();
                        icNode.ConditionExpression = cExprNode;
                        icNode.TrueExpression = bNode.RightNode;
                        icNode.FalseExpression = iNodeTemp;
                        bNodeTemp.LeftNode = bNode.LeftNode;
                        bNodeTemp.RightNode = icNode;
                        EmitBinaryExpressionNode(bNodeTemp, ref inferedType);
                    }
                    emitDebugInfo = true;

                    EmitCodeBlock(funcDef.FunctionBody.Body, ref inferedType, subPass, true);

                    // Build dependency within the function
                    ProtoCore.AssociativeEngine.Utils.BuildGraphNodeDependencies(
                        codeBlock.instrStream.dependencyGraph.GetGraphNodesAtScope(globalClassIndex, globalProcIndex));

                    // All locals have been stack allocated, update the local count of this function
                    localProcedure.LocalCount = core.BaseOffset;
                    core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex].LocalCount = core.BaseOffset;

                    // Update the param stack indices of this function
                    foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[globalClassIndex].Symbols.symbolList.Values)
                    {
                        if (symnode.functionIndex == globalProcIndex && symnode.isArgument)
                        {
                            symnode.index -= localProcedure.LocalCount;
                        }
                    }

                    // JIL FEP
                    ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord();
                    record.pc = localProcedure.PC;
                    record.locals = localProcedure.LocalCount;
                    record.classIndex = globalClassIndex;
                    record.funcIndex = globalProcIndex;

                    // Construct the fep arguments
                    fep = new ProtoCore.Lang.JILFunctionEndPoint(record);
                }
                else
                {
                    ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord();
                    jRecord.pc = localProcedure.PC;
                    jRecord.locals = localProcedure.LocalCount;
                    jRecord.classIndex = globalClassIndex;
                    jRecord.funcIndex = localProcedure.ID;

                    ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord();
                    record.JILRecord = jRecord;
                    record.FunctionName = funcDef.Name;
                    record.ModuleName = funcDef.ExternLibName;
                    record.ModuleType = "dll";
                    record.IsDNI = false;
                    record.ReturnType = funcDef.ReturnType;
                    record.ParameterTypes = localProcedure.ArgumentTypes;
                    fep = new ProtoCore.Lang.FFIFunctionEndPoint(record);
                }

                // Construct the fep arguments
                fep.FormalParams = new ProtoCore.Type[localProcedure.ArgumentTypes.Count];
                fep.procedureNode = localProcedure;
                localProcedure.ArgumentTypes.CopyTo(fep.FormalParams, 0);

                // 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables
                int classIndexAtCallsite = globalClassIndex + 1;
                core.FunctionTable.InitGlobalFunctionEntry(classIndexAtCallsite);

                Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite];
                if (!fgroup.ContainsKey(funcDef.Name))
                {
                    // Create a new function group in this class
                    ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup();
                    funcGroup.FunctionEndPoints.Add(fep);

                    // Add this group to the class function tables
                    core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup);
                }
                else
                {
                    // Add this fep into the exisitng function group
                    core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep);
                }

                int startpc = pc;

                // Constructors auto return
                EmitInstrConsole(ProtoCore.DSASM.kw.retc);

                // Stepping out of a constructor body will have the execution cursor 
                // placed right at the closing curly bracket of the constructor definition.
                // 
                int closeCurlyBracketLine = 0, closeCurlyBracketColumn = -1;
                if (null != funcDef.FunctionBody)
                {
                    closeCurlyBracketLine = funcDef.FunctionBody.endLine;
                    closeCurlyBracketColumn = funcDef.FunctionBody.endCol;
                }

                // The execution cursor covers exactly one character -- the closing 
                // curly bracket. Note that we decrement the start-column by one here 
                // because end-column of "FunctionBody" here is *after* the closing 
                // curly bracket, so we want one before that.
                // 
                EmitRetc(closeCurlyBracketLine, closeCurlyBracketColumn - 1,
                    closeCurlyBracketLine, closeCurlyBracketColumn);

                // Build and append a graphnode for this return statememt
                ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode();
                returnNode.name = ProtoCore.DSDefinitions.Keyword.Return;

                ProtoCore.AssociativeGraph.GraphNode retNode = new ProtoCore.AssociativeGraph.GraphNode();
                //retNode.symbol = returnNode;
                retNode.PushSymbolReference(returnNode);
                retNode.procIndex = globalProcIndex;
                retNode.classIndex = globalClassIndex;
                retNode.updateBlock.startpc = startpc;
                retNode.updateBlock.endpc = pc - 1;

                PushGraphNode(retNode);
                EmitCompileLogFunctionEnd();
            }

            // Constructors have no return statemetns, reset variables here
            core.ProcNode = localProcedure = null;
            globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope;
            core.BaseOffset = 0;
            argOffset = 0;
            classOffset = 0;
            codeBlock.blockType = originalBlockType;
        }
예제 #17
0
        private void EmitIdentifierNode(AssociativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, BinaryExpressionNode parentNode = null)
        {
            IdentifierNode t = node as IdentifierNode;
            if (t.Name.Equals(ProtoCore.DSDefinitions.Keyword.This))
            {
                if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone)
                {
                    return;
                }

                if (localProcedure != null)
                {
                    if (localProcedure.IsStatic)
                    {
                        string message = ProtoCore.Properties.Resources.kUsingThisInStaticFunction;
                        core.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode);
                        EmitPushNull();
                        return;
                    }
                    else if (localProcedure.ClassID == Constants.kGlobalScope)
                    {
                        string message = ProtoCore.Properties.Resources.kInvalidThis;
                        core.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode);
                        EmitPushNull();
                        return;
                    }
                    else
                    {
                        EmitThisPointerNode(subPass);
                        return;
                    }
                }
                else
                {
                    string message = ProtoCore.Properties.Resources.kInvalidThis;
                    core.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode);
                    EmitPushNull();
                    return;
                }
            }

            int dimensions = 0;

            ProtoCore.DSASM.SymbolNode symbolnode = null;
            int runtimeIndex = codeBlock.symbolTable.RuntimeIndex;

            ProtoCore.Type type = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0);

            bool isAccessible = false;
            bool isAllocated = VerifyAllocation(t.Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible);
            if (!isAllocated && null == t.ArrayDimensions)
            {
                //check if it is a function instance
                ProtoCore.DSASM.ProcedureNode procNode = null;
                procNode = CoreUtils.GetFunctionByName(t.Name, codeBlock);
                if (null != procNode)
                {
                    if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.ID)
                    {
                        // A global function
                        inferedType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeFunctionPointer, 0);
                        if (ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier != subPass)
                        {
                            int fptr = core.FunctionPointerTable.functionPointerDictionary.Count;
                            var fptrNode = new FunctionPointerNode(procNode);
                            core.FunctionPointerTable.functionPointerDictionary.TryAdd(fptr, fptrNode);
                            core.FunctionPointerTable.functionPointerDictionary.TryGetBySecond(fptrNode, out fptr);

                            EmitPushVarData(0);

                            EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Name);
                            StackValue opFunctionPointer = StackValue.BuildFunctionPointer(fptr);
                            EmitPush(opFunctionPointer, runtimeIndex, t.line, t.col);
                        }
                        return;
                    }
         
                }
            }            

            if (ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier == subPass)
            {
                if (symbolnode == null)
                {
                    // The variable is unbound
                    ProtoCore.DSASM.SymbolNode unboundVariable = null;
                    if (ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter != core.Options.RunMode)
                    {
                        inferedType.UID = (int)ProtoCore.PrimitiveType.kTypeNull;

                        // Jun Comment: Specification 
                        //      If resolution fails at this point a com.Design-Script.Imperative.Core.UnboundIdentifier 
                        //      warning is emitted during pre-execute phase, and at the ID is bound to null. (R1 - Feb)

                        // Set the first symbol that triggers the cycle to null
                        ProtoCore.AssociativeGraph.GraphNode nullAssignGraphNode = new ProtoCore.AssociativeGraph.GraphNode();
                        nullAssignGraphNode.updateBlock.startpc = pc;


                        EmitPushNull();

                        // Push the identifier local block  
                        dimensions = 0;
                        EmitPushVarData(dimensions);
                        ProtoCore.Type varType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0);

                        // TODO Jun: Refactor Allocate() to just return the symbol node itself
                        unboundVariable = Allocate(globalClassIndex, globalClassIndex, globalProcIndex, t.Value, varType, ProtoCore.DSASM.Constants.kPrimitiveSize,
                            false, ProtoCore.CompilerDefinitions.AccessModifier.kPublic, ProtoCore.DSASM.MemoryRegion.kMemStack, t.line, t.col, graphNode);
                        Validity.Assert(unboundVariable != null);

                        int symbolindex = unboundVariable.symbolTableIndex;
                        if (ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex)
                        {
                            symbolnode = core.ClassTable.ClassNodes[globalClassIndex].Symbols.symbolList[symbolindex];
                        }
                        else
                        {
                            symbolnode = codeBlock.symbolTable.symbolList[symbolindex];
                        }

                        EmitInstrConsole(ProtoCore.DSASM.kw.pop, t.Value);
                        EmitPopForSymbol(unboundVariable, runtimeIndex);


                        nullAssignGraphNode.PushSymbolReference(symbolnode);
                        nullAssignGraphNode.procIndex = globalProcIndex;
                        nullAssignGraphNode.classIndex = globalClassIndex;
                        nullAssignGraphNode.updateBlock.endpc = pc - 1;

                        PushGraphNode(nullAssignGraphNode);
                        EmitDependency(ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, false);
                    }

                    if (isAllocated)
                    {
                        string message = String.Format(ProtoCore.Properties.Resources.kPropertyIsInaccessible, t.Value);
                        if (localProcedure != null && localProcedure.IsStatic)
                        {
                            SymbolNode tempSymbolNode;

                            VerifyAllocation(
                                t.Name,
                                globalClassIndex,
                                Constants.kGlobalScope,
                                out tempSymbolNode,
                                out isAccessible);

                            if (tempSymbolNode != null && !tempSymbolNode.isStatic && isAccessible)
                            {
                                message = String.Format(ProtoCore.Properties.Resources.kUsingNonStaticMemberInStaticContext, t.Value);
                            }
                        }
                        buildStatus.LogWarning(
                            WarningID.kAccessViolation,
                            message,
                            core.CurrentDSFileName,
                            t.line,
                            t.col,
                            graphNode);
                    }
                    else
                    {
                        string message = String.Format(ProtoCore.Properties.Resources.kUnboundIdentifierMsg, t.Value);
                        buildStatus.LogUnboundVariableWarning(unboundVariable, message, core.CurrentDSFileName, t.line, t.col, graphNode);
                    }
                }

                if (null != t.ArrayDimensions)
                {
                    dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions, graphNode, parentNode, subPass);
                }
            }
            else
            {
                if (core.Options.RunMode == ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter &&
                    !isAllocated)
                {
                    // It happens when the debugger try to watch a variable 
                    // which has been out of scope (as watch is done through
                    // execute an expression "t = v;" where v is the variable
                    // to be watched.
                    EmitPushNull();
                    return;
                }

                Validity.Assert(isAllocated);

                if (graphNode != null 
                    && IsAssociativeArrayIndexing 
                    && !CoreUtils.IsAutoGeneratedVar(symbolnode.name))
                {
                    UpdateNode updateNode = new UpdateNode();
                    updateNode.symbol = symbolnode;
                    updateNode.nodeType = UpdateNodeType.kSymbol;

                    if (graphNode.isIndexingLHS)
                    {
                        graphNode.dimensionNodeList.Add(updateNode);
                    }
                    else
                    {
                        int curDepIndex = graphNode.dependentList.Count - 1;
                        if (curDepIndex >= 0)
                        {
                            var curDep = graphNode.dependentList[curDepIndex].updateNodeRefList[0].nodeList[0];
                            curDep.dimensionNodeList.Add(updateNode);

                            if (core.Options.GenerateSSA)
                            {
                                if (null != firstSSAGraphNode)
                                {
                                    curDepIndex = firstSSAGraphNode.dependentList.Count - 1;
                                    if (curDepIndex >= 0)
                                    {
                                        ProtoCore.AssociativeGraph.UpdateNode firstSSAUpdateNode = firstSSAGraphNode.dependentList[curDepIndex].updateNodeRefList[0].nodeList[0];
                                        firstSSAUpdateNode.dimensionNodeList.Add(updateNode);
                                    }
                                }
                            }
                        }
                    }
                }

                // If it is a property, replaced it with getter: %get_prop()
                if (symbolnode.classScope != ProtoCore.DSASM.Constants.kInvalidIndex &&
                    symbolnode.functionIndex == ProtoCore.DSASM.Constants.kGlobalScope &&
                    localProcedure != null)
                {
                    string getterName = ProtoCore.DSASM.Constants.kGetterPrefix + t.Name;
                    if (!string.Equals(localProcedure.Name, getterName))
                    {
                        var thisNode =AstFactory.BuildIdentifier(ProtoCore.DSDefinitions.Keyword.This);
                        var identListNode = AstFactory.BuildIdentList(thisNode, t);
                        EmitIdentifierListNode(identListNode, ref inferedType, false, graphNode, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone);

                        if (null != graphNode)
                        {
                            PushSymbolAsDependent(symbolnode, graphNode);
                        }

                        return;
                    }
                }

                type = symbolnode.datatype;
                runtimeIndex = symbolnode.runtimeTableIndex;

                // The graph node always depends on this identifier
                GraphNode dependendNode = null;
                if (null != graphNode)
                {
                    dependendNode = PushSymbolAsDependent(symbolnode, graphNode);
                }


                // Flags if the variable is allocated in the current scope
                bool isAllocatedWithinCurrentBlock = symbolnode.codeBlockId == codeBlock.codeBlockId;
                bool isValidDependent = dependendNode != null && !CoreUtils.IsSSATemp(symbolnode.name);
                if (!isAllocatedWithinCurrentBlock && isValidDependent)
                {
                    /*
                    a = 1;
                    i = [Associative]
                    {
                        // In an inner language block:
                        //  Add all rhs to the parent graphnode dependency list if the rhs was not allocated at the current scope
                        //  Only those not allocated are added to the parent.
                        //  This is because external nodes should not be able to update the local block if the affected variable is local to the block
                        //  Variable 'x' is local and the outer block statement x = 2 (where x is allocated globally), should not update this inner block
                        x = 10;
                        b = x + 1;
                        return = a + b + 10; 
                    }
                    x = 2;
                    a = 2;
                    */
                    context.DependentVariablesInScope.Add(dependendNode);
                }

                bool emitReplicationGuideFlag = emitReplicationGuide;
                emitReplicationGuide = false;
                if (null != t.ArrayDimensions)
                {
                    dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions, graphNode, parentNode, subPass);
                }
                emitReplicationGuide = emitReplicationGuideFlag;

                //fix type's rank   
                if (type.rank >= 0)
                {
                    type.rank -= dimensions;
                    if (type.rank < 0)
                    {
                        //throw new Exception("Exceed maximum rank!");
                        type.rank = 0;
                    }
                }

                EmitPushVarData(dimensions);

                if (ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter == core.Options.RunMode)
                {
                    EmitInstrConsole(ProtoCore.DSASM.kw.pushw, t.Value);
                    EmitPushForSymbolW(symbolnode, runtimeIndex, t.line, t.col);
                }
                else
                {
                    EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Value);
                    EmitPushForSymbol(symbolnode, runtimeIndex, t);

                    if (emitReplicationGuide)
                    {
                        EmitAtLevel(t.AtLevel);
                        EmitReplicationGuides(t.ReplicationGuides);
                    }
                }

                if (core.TypeSystem.IsHigherRank(type.UID, inferedType.UID))
                {
                    inferedType = type;
                }
                // We need to get inferedType for boolean variable so that we can perform type check
                inferedType.UID = (isBooleanOp || (type.UID == (int)PrimitiveType.kTypeBool)) ? (int)PrimitiveType.kTypeBool : inferedType.UID;
            }

        }
예제 #18
0
        //
        //  proc SSAIdentList(node, ssastack, ast)
        //  {
        //      if node is ident
        //          t = SSATemp()
        //          tmpIdent = new Ident(t)
        //          binexpr = new BinaryExpr(tmpIdent, node)
        //          ast.push(binexpr)
        //          ssastack.push(tmpIdent)
        //      else if node is identlist
        //          SSAIdentList(node.left, ssastack, ast)
        //          rhs = new identlist(new Ident(ssastack.pop), node.right)
        //          t = SSATemp()
        //          tmpIdent = new Ident(t)
        //          binexpr = new BinaryExpr(tmpIdent, rhs)
        //          ast.push(binexpr)
        //          ssastack.push(tmpIdent)
        //      end
        //  }
        //
        private void SSAIdentList(AssociativeNode node, ref Stack<AssociativeNode> ssaStack, ref List<AssociativeNode> astlist)
        {
            if (node is IdentifierNode)
            {
                IdentifierNode ident = node as IdentifierNode;
                if (null == ident.ArrayDimensions)
                {
                    // Build the temp pointer
                    BinaryExpressionNode bnode = new BinaryExpressionNode();
                    bnode.Optr = ProtoCore.DSASM.Operator.assign;
                    bnode.isSSAAssignment = true;
                    bnode.isSSAPointerAssignment = true;

                    // Left node
                    var identNode = nodeBuilder.BuildIdentfier(ProtoCore.Utils.CoreUtils.GetSSATemp(compileStateTracker));
                    (identNode as IdentifierNode).ReplicationGuides = GetReplicationGuidesFromASTNode(ident);
                    bnode.LeftNode = identNode;

                    // Right node
                    bnode.RightNode = ident;

                    astlist.Add(bnode);
                    ssaStack.Push(bnode);
                }
                else
                {
                    EmitSSAArrayIndex(ident, ssaStack, ref astlist, true);
                }

            }
            else if (node is FunctionCallNode)
            {
                FunctionCallNode fcall = node as FunctionCallNode;
                if (null == fcall.ArrayDimensions)
                {
                    // Build the temp pointer
                    BinaryExpressionNode bnode = new BinaryExpressionNode();
                    bnode.Optr = ProtoCore.DSASM.Operator.assign;
                    bnode.isSSAAssignment = true;
                    bnode.isSSAPointerAssignment = true;

                    // Left node
                    var identNode = nodeBuilder.BuildIdentfier(ProtoCore.Utils.CoreUtils.GetSSATemp(compileStateTracker));
                    (identNode as IdentifierNode).ReplicationGuides = fcall.ReplicationGuides;
                    bnode.LeftNode = identNode;

                    // Right node
                    bnode.RightNode = fcall;

                    astlist.Add(bnode);
                    ssaStack.Push(bnode);
                }
                else
                {
                    EmitSSAArrayIndex(fcall, ssaStack, ref astlist, true);
                }

            }
            else if (node is IdentifierListNode)
            {
                IdentifierListNode identList = node as IdentifierListNode;

                // Recursively traversse the left of the ident list
                SSAIdentList(identList.LeftNode, ref ssaStack, ref astlist);

                // Build the rhs identifier list containing the temp pointer
                IdentifierListNode rhsIdentList = new IdentifierListNode();
                rhsIdentList.Optr = Operator.dot;

                AssociativeNode lhsNode = ssaStack.Pop();
                if (lhsNode is BinaryExpressionNode)
                {
                    rhsIdentList.LeftNode = (lhsNode as BinaryExpressionNode).LeftNode;
                }
                else
                {
                    rhsIdentList.LeftNode = lhsNode;
                }

                ArrayNode arrayDimension = null;

                AssociativeNode rnode = null;
                if (identList.RightNode is IdentifierNode)
                {
                    IdentifierNode identNode = identList.RightNode as IdentifierNode;
                    arrayDimension = identNode.ArrayDimensions;
                    rnode = identNode;
                }
                else if (identList.RightNode is FunctionCallNode)
                {
                    FunctionCallNode fCallNode = identList.RightNode as FunctionCallNode;
                    arrayDimension = fCallNode.ArrayDimensions;
                    rnode = fCallNode;
                }
                else
                {
                    Validity.Assert(false);
                }

                Validity.Assert(null != rnode);
                rhsIdentList.RightNode = rnode;

                if (null == arrayDimension)
                {
                    // New SSA expr for the current dot call
                    string ssatemp = ProtoCore.Utils.CoreUtils.GetSSATemp(compileStateTracker);
                    var tmpIdent = nodeBuilder.BuildIdentfier(ssatemp);
                    BinaryExpressionNode bnode = new BinaryExpressionNode(tmpIdent, rhsIdentList, Operator.assign);
                    bnode.isSSAPointerAssignment = true;
                    astlist.Add(bnode);
                    //ssaStack.Push(tmpIdent);
                    ssaStack.Push(bnode);
                }
                else
                {
                    EmitSSAArrayIndex(rhsIdentList, ssaStack, ref astlist, true);
                }
            }
        }
예제 #19
0
        private void EmitUnaryExpressionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone)
        {
            UnaryExpressionNode u = node as UnaryExpressionNode;
            bool isPrefixOperation = ProtoCore.DSASM.UnaryOperator.Increment == u.Operator || ProtoCore.DSASM.UnaryOperator.Decrement == u.Operator;

            //(Ayush) In case of prefix, apply prefix operation first
            if (isPrefixOperation)
            {
                if (u.Expression is IdentifierListNode || u.Expression is IdentifierNode)
                {
                    BinaryExpressionNode binRight = new BinaryExpressionNode();
                    BinaryExpressionNode bin = new BinaryExpressionNode();
                    binRight.LeftNode = u.Expression;
                    binRight.RightNode = new IntNode { value = "1" };
                    binRight.Optr = (ProtoCore.DSASM.UnaryOperator.Increment == u.Operator) ? ProtoCore.DSASM.Operator.add : ProtoCore.DSASM.Operator.sub;
                    bin.LeftNode = u.Expression; bin.RightNode = binRight; bin.Optr = ProtoCore.DSASM.Operator.assign;
                    EmitBinaryExpressionNode(bin, ref inferedType, false, graphNode, subPass);
                }
                else
                    throw new BuildHaltException("Invalid use of prefix operation (DCDDEEF1).");
            }

            DfsTraverse(u.Expression, ref inferedType, false, graphNode, subPass);

            if (!isPrefixOperation && subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier)
            {
                EmitInstrConsole(ProtoCore.DSASM.kw.pop, ProtoCore.DSASM.kw.regAX);
                ProtoCore.DSASM.StackValue opAX = new ProtoCore.DSASM.StackValue();
                opAX.optype = ProtoCore.DSASM.AddressType.Register;
                opAX.opdata = (int)ProtoCore.DSASM.Registers.AX;
                EmitPop(opAX, Constants.kGlobalScope);

                string op = Op.GetUnaryOpName(u.Operator);
                EmitInstrConsole(op, ProtoCore.DSASM.kw.regAX);
                EmitUnary(Op.GetUnaryOpCode(u.Operator), opAX);

                EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regAX);
                ProtoCore.DSASM.StackValue opRes = new ProtoCore.DSASM.StackValue();
                opRes.optype = ProtoCore.DSASM.AddressType.Register;
                opRes.opdata = (int)ProtoCore.DSASM.Registers.AX;
                EmitPush(opRes);
            }
        }
예제 #20
0
        /// <summary>
        /// This function applies SSA tranform to an array indexed identifier or identifier list
        /// 
        /// The transform applies as such:
        ///     i = 0
        ///     j = 1
        ///     x = a[i][j]
        ///     
        ///     t0 = a
        ///     t1 = i
        ///     t2 = t0[t1]
        ///     t3 = j
        ///     t4 = t2[t3]
        ///     x = t4
        /// 
        /// </summary>
        /// <param name="idendNode"></param>
        /// <param name="ssaStack"></param>
        /// <param name="astlist"></param>
        private void EmitSSAArrayIndex(AssociativeNode node, Stack<AssociativeNode> ssaStack, ref List<AssociativeNode> astlist, bool isSSAPointerAssignment = false)
        {
            //
            // Build the first SSA binary assignment of the identifier without its indexing
            //  x = a[i][j] -> t0 = a
            //
            BinaryExpressionNode bnode = new BinaryExpressionNode();
            bnode.Optr = ProtoCore.DSASM.Operator.assign;

            // Left node
            var tmpName = nodeBuilder.BuildIdentfier(ProtoCore.Utils.CoreUtils.GetSSATemp(compileStateTracker));
            bnode.LeftNode = tmpName;
            bnode.isSSAAssignment = true;
            bnode.isSSAPointerAssignment = isSSAPointerAssignment;
            bnode.isSSAFirstAssignment = true;

            IdentifierNode identNode = null;
            if (node is IdentifierNode)
            {
                identNode = node as IdentifierNode;

                // Right node - Array indexing will be applied to this new identifier
                bnode.RightNode = nodeBuilder.BuildIdentfier(identNode.Name);
            }
            else if (node is FunctionCallNode)
            {
                FunctionCallNode fcall = node as FunctionCallNode;
                Validity.Assert(fcall.Function is IdentifierNode);
                identNode = fcall.Function as IdentifierNode;

                // Assign the function array and guide properties to the new ident node
                identNode.ArrayDimensions = fcall.ArrayDimensions;
                identNode.ReplicationGuides = fcall.ReplicationGuides;

                // Right node - Remove the function array indexing.
                // The array indexing to this function will be applied downstream
                fcall.ArrayDimensions = null;
                bnode.RightNode = fcall;
            }
            else if (node is IdentifierListNode)
            {
                // Apply array indexing to the right node of the ident list
                //      a = p.x[i] -> apply it to x
                IdentifierListNode identList = node as IdentifierListNode;
                AssociativeNode rhsNode = identList.RightNode;

                Validity.Assert(rhsNode is IdentifierNode);
                identNode = rhsNode as IdentifierNode;

                // Replace the indexed identifier with a new ident with the same name
                //      i.e. replace x[i] with x
                AssociativeNode nonIndexedIdent = nodeBuilder.BuildIdentfier(identNode.Name);
                identList.RightNode = nonIndexedIdent;

                // Right node
                bnode.RightNode = identList;

                bnode.isSSAPointerAssignment = true;
            }
            else
            {
                Validity.Assert(false);
            }

            // Push the first SSA stmt
            astlist.Add(bnode);
            ssaStack.Push(bnode);

            // Traverse the array index
            //      t1 = i
            DFSEmitSSA_AST(identNode.ArrayDimensions.Expr, ssaStack, ref astlist);

            //
            // Build the indexing statement
            //      t2 = t0[t1]
            BinaryExpressionNode indexedStmt = new BinaryExpressionNode();
            indexedStmt.Optr = ProtoCore.DSASM.Operator.assign;

            // Build the left node of the indexing statement
            #region SSA_INDEX_STMT_LEFT
            AssociativeNode tmpIdent = nodeBuilder.BuildIdentfier(ProtoCore.Utils.CoreUtils.GetSSATemp(compileStateTracker));
            Validity.Assert(null != tmpIdent);
            indexedStmt.LeftNode = tmpIdent;
            #endregion

            // Build the right node of the indexing statement
            #region SSA_INDEX_STMT_RIGHT

            ArrayNode arrayNode = null;

            // pop off the dimension
            AssociativeNode dimensionNode = ssaStack.Pop();
            if (dimensionNode is BinaryExpressionNode)
            {
                arrayNode = new ArrayNode((dimensionNode as BinaryExpressionNode).LeftNode, null);
            }
            else
            {
                arrayNode = new ArrayNode(dimensionNode, null);
            }

            // pop off the prev SSA variable
            AssociativeNode prevSSAStmt = ssaStack.Pop();

            // Assign the curent dimension to the prev SSA variable
            Validity.Assert(prevSSAStmt is BinaryExpressionNode);
            AssociativeNode rhsIdent = nodeBuilder.BuildIdentfier((prevSSAStmt as BinaryExpressionNode).LeftNode.Name);
            (rhsIdent as IdentifierNode).ArrayDimensions = arrayNode;

            // Right node of the indexing statement
            indexedStmt.RightNode = rhsIdent;

            astlist.Add(indexedStmt);
            ssaStack.Push(indexedStmt);

            // Traverse the next dimension
            //      [j]
            if (null != identNode.ArrayDimensions.Type)
            {
                DFSEmitSSA_AST(identNode.ArrayDimensions.Type, ssaStack, ref astlist);
            }
            #endregion
        }
예제 #21
0
        private void EmitInlineConditionalNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, ProtoCore.AST.AssociativeAST.BinaryExpressionNode parentNode = null)
        {
            if (subPass == AssociativeSubCompilePass.kUnboundIdentifier)
            {
                return;
            }

            bool isInlineConditionalFlag = false;
            int startPC = pc;
            bool isReturn = false;
            if (graphNode != null)
            {
                isInlineConditionalFlag = graphNode.isInlineConditional;
                graphNode.isInlineConditional = true;
                startPC = graphNode.updateBlock.startpc;
                isReturn = graphNode.isReturn;
            }

            InlineConditionalNode inlineConditionalNode = node as InlineConditionalNode;
            // TODO: Jun, this 'if' condition needs to be removed as it was the old implementation - pratapa
            if (inlineConditionalNode.IsAutoGenerated)
            {
                // Normal inline conditional

                IfStatementNode ifNode = new IfStatementNode();
                ifNode.ifExprNode = inlineConditionalNode.ConditionExpression;
                List<AssociativeNode> ifBody = new List<AssociativeNode>();
                List<AssociativeNode> elseBody = new List<AssociativeNode>();
                ifBody.Add(inlineConditionalNode.TrueExpression);
                elseBody.Add(inlineConditionalNode.FalseExpression);
                ifNode.IfBody = ifBody;
                ifNode.ElseBody = elseBody;

                EmitIfStatementNode(ifNode, ref inferedType, graphNode);
            }
            else
            {
                // CPS inline conditional

                FunctionCallNode inlineCall = new FunctionCallNode();
                IdentifierNode identNode = new IdentifierNode();
                identNode.Name = ProtoCore.DSASM.Constants.kInlineConditionalMethodName;
                inlineCall.Function = identNode;

                DebugProperties.BreakpointOptions oldOptions = compileStateTracker.DebugProps.breakOptions;
                DebugProperties.BreakpointOptions newOptions = oldOptions;
                newOptions |= DebugProperties.BreakpointOptions.EmitInlineConditionalBreakpoint;
                compileStateTracker.DebugProps.breakOptions = newOptions;

                compileStateTracker.DebugProps.highlightRange = new ProtoCore.CodeModel.CodeRange
                {
                    StartInclusive = new ProtoCore.CodeModel.CodePoint
                    {
                        LineNo = parentNode.line,
                        CharNo = parentNode.col
                    },

                    EndExclusive = new ProtoCore.CodeModel.CodePoint
                    {
                        LineNo = parentNode.endLine,
                        CharNo = parentNode.endCol
                    }
                };

                // True condition language block
                BinaryExpressionNode bExprTrue = new BinaryExpressionNode();
                bExprTrue.LeftNode = nodeBuilder.BuildReturn();
                bExprTrue.Optr = Operator.assign;
                bExprTrue.RightNode = inlineConditionalNode.TrueExpression;

                LanguageBlockNode langblockT = new LanguageBlockNode();
                int trueBlockId = ProtoCore.DSASM.Constants.kInvalidIndex;
                langblockT.codeblock.language = ProtoCore.Language.kAssociative;
                langblockT.codeblock.fingerprint = "";
                langblockT.codeblock.version = "";
                compileStateTracker.AssocNode = bExprTrue;
                EmitDynamicLanguageBlockNode(langblockT, bExprTrue, ref inferedType, ref trueBlockId, graphNode, AssociativeSubCompilePass.kNone);
                compileStateTracker.AssocNode = null;
                ProtoCore.AST.AssociativeAST.DynamicBlockNode dynBlockT = new ProtoCore.AST.AssociativeAST.DynamicBlockNode(trueBlockId);

                // False condition language block
                BinaryExpressionNode bExprFalse = new BinaryExpressionNode();
                bExprFalse.LeftNode = nodeBuilder.BuildReturn();
                bExprFalse.Optr = Operator.assign;
                bExprFalse.RightNode = inlineConditionalNode.FalseExpression;

                LanguageBlockNode langblockF = new LanguageBlockNode();
                int falseBlockId = ProtoCore.DSASM.Constants.kInvalidIndex;
                langblockF.codeblock.language = ProtoCore.Language.kAssociative;
                langblockF.codeblock.fingerprint = "";
                langblockF.codeblock.version = "";
                compileStateTracker.AssocNode = bExprFalse;
                EmitDynamicLanguageBlockNode(langblockF, bExprFalse, ref inferedType, ref falseBlockId, graphNode, AssociativeSubCompilePass.kNone);
                compileStateTracker.AssocNode = null;
                ProtoCore.AST.AssociativeAST.DynamicBlockNode dynBlockF = new ProtoCore.AST.AssociativeAST.DynamicBlockNode(falseBlockId);

                compileStateTracker.DebugProps.breakOptions = oldOptions;
                compileStateTracker.DebugProps.highlightRange = new ProtoCore.CodeModel.CodeRange
                {
                    StartInclusive = new ProtoCore.CodeModel.CodePoint
                    {
                        LineNo = Constants.kInvalidIndex,
                        CharNo = Constants.kInvalidIndex
                    },

                    EndExclusive = new ProtoCore.CodeModel.CodePoint
                    {
                        LineNo = Constants.kInvalidIndex,
                        CharNo = Constants.kInvalidIndex
                    }
                };

                inlineCall.FormalArguments.Add(inlineConditionalNode.ConditionExpression);
                inlineCall.FormalArguments.Add(dynBlockT);
                inlineCall.FormalArguments.Add(dynBlockF);

                // Save the pc and store it after the call
                EmitFunctionCallNode(inlineCall, ref inferedType, false, graphNode, AssociativeSubCompilePass.kUnboundIdentifier);
                EmitFunctionCallNode(inlineCall, ref inferedType, false, graphNode, AssociativeSubCompilePass.kNone, parentNode);

                // Need to restore those settings.
                if (graphNode != null)
                {
                    graphNode.isInlineConditional = isInlineConditionalFlag;
                    graphNode.updateBlock.startpc = startPC;
                    graphNode.isReturn = isReturn;
                }
            }
        }
예제 #22
0
        /*
         proc EmitIdentNode(identnode, graphnode)
            if ssa
                // Check an if this identifier is array indexed
                // The array index is a secondary property and is not the original array property of the AST. this is required because this array index is meant only to resolve graphnode dependency with arrays
                if node.arrayindex.secondary is valid
                    dimension = traverse(node.arrayindex.secondary)

                    // Create a new dependent with the array indexing
                    dependent = new GraphNode(identnode.name, dimension)
                    graphnode.pushdependent(dependent)
                end
            end
        end

         */
        private void EmitIdentifierNode(AssociativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, BinaryExpressionNode parentNode = null)
        {
            IdentifierNode t = node as IdentifierNode;
            if (t.Name.Equals(ProtoCore.DSDefinitions.Keyword.This))
            {
                if (subPass != AssociativeSubCompilePass.kNone)
                {
                    return;
                }

                if (localProcedure != null)
                {
                    if (localProcedure.isStatic)
                    {
                        string message = ProtoCore.BuildData.WarningMessage.kUsingThisInStaticFunction;
                        compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col);
                        EmitPushNull();
                        return;
                    }
                    else if (localProcedure.classScope == Constants.kGlobalScope)
                    {
                        string message = ProtoCore.BuildData.WarningMessage.kInvalidThis;
                        compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col);
                        EmitPushNull();
                        return;
                    }
                    else
                    {
                        EmitThisPointerNode(subPass);
                        return;
                    }
                }
                else
                {
                    string message = ProtoCore.BuildData.WarningMessage.kInvalidThis;
                    compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col);
                    EmitPushNull();
                    return;
                }
            }

            int dimensions = 0;

            ProtoCore.DSASM.SymbolNode symbolnode = null;
            int runtimeIndex = codeBlock.symbolTable.runtimeIndex;

            ProtoCore.Type type = new ProtoCore.Type();
            type.UID = (int)ProtoCore.PrimitiveType.kTypeVoid;
            type.IsIndexable = false;

            bool isAccessible = false;

            if (null == t.ArrayDimensions)
            {
                //check if it is a function instance
                ProtoCore.DSASM.ProcedureNode procNode = null;
                procNode = compileStateTracker.GetFirstVisibleProcedure(t.Name, null, codeBlock);
                if (null != procNode)
                {
                    if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId)
                    {
                        // A global function
                        inferedType.IsIndexable = false;
                        inferedType.UID = (int)PrimitiveType.kTypeFunctionPointer;
                        if (ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier != subPass)
                        {
                            int fptr = compileStateTracker.FunctionPointerTable.functionPointerDictionary.Count;
                            ProtoCore.DSASM.FunctionPointerNode fptrNode = new ProtoCore.DSASM.FunctionPointerNode(procNode.procId, procNode.runtimeIndex);
                            compileStateTracker.FunctionPointerTable.functionPointerDictionary.TryAdd(fptr, fptrNode);
                            compileStateTracker.FunctionPointerTable.functionPointerDictionary.TryGetBySecond(fptrNode, out fptr);

                            EmitPushVarData(runtimeIndex, 0);

                            EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Name);
                            ProtoCore.DSASM.StackValue opFunctionPointer = new ProtoCore.DSASM.StackValue();
                            opFunctionPointer.optype = ProtoCore.DSASM.AddressType.FunctionPointer;
                            opFunctionPointer.opdata = fptr;
                            opFunctionPointer.opdata_d = fptr;
                            EmitPush(opFunctionPointer, t.line, t.col);
                        }
                        return;
                    }
                }
            }

            bool isAllocated = VerifyAllocation(t.Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible);

            // If its executing in interpreter mode - attempt to find and anubond identifer in a child block
            // Remove this, because if we are watching cases like:
            //c1 = [Imperative]
            //{
            //    a = 1;
            //    b = 2;
            //}
            //
            //c2 = [Associative]
            //{
            //    a = 3;
            //    b = 4;
            //}
            //After c2 is executed, the watch value for a, b will be 1, 2.
            //if (ProtoCore.DSASM.ExecutionMode.kExpressionInterpreter == core.ExecMode)
            //{
            //    if (!isAllocated)
            //    {
            //        isAllocated = VerifyAllocationIncludingChildBlock(t.Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible);
            //    }
            //}

            if (AssociativeSubCompilePass.kUnboundIdentifier == subPass)
            {
                if (symbolnode == null)
                {
                    if (isAllocated)
                    {
                        string message = String.Format(WarningMessage.kPropertyIsInaccessible, t.Value);
                        if (localProcedure != null && localProcedure.isStatic)
                        {
                            SymbolNode tempSymbolNode;

                            VerifyAllocation(
                                t.Name,
                                globalClassIndex,
                                Constants.kGlobalScope,
                                out tempSymbolNode,
                                out isAccessible);

                            if (tempSymbolNode != null && !tempSymbolNode.isStatic && isAccessible)
                            {
                                message = String.Format(WarningMessage.kUsingNonStaticMemberInStaticContext, t.Value);
                            }
                        }
                        buildStatus.LogWarning(
                            ProtoCore.BuildData.WarningID.kAccessViolation,
                            message,
                            compileStateTracker.CurrentDSFileName,
                            t.line,
                            t.col);
                    }
                    else
                    {
                        string message = String.Format(WarningMessage.kUnboundIdentifierMsg, t.Value);
                        buildStatus.LogWarning(WarningID.kIdUnboundIdentifier, message, compileStateTracker.CurrentDSFileName, t.line, t.col);
                    }

                    if (ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter != compileStateTracker.ExecMode)
                    {
                        inferedType.UID = (int)ProtoCore.PrimitiveType.kTypeNull;

                        // Jun Comment: Specification
                        //      If resolution fails at this point a com.Design-Script.Imperative.Core.UnboundIdentifier
                        //      warning is emitted during pre-execute phase, and at the ID is bound to null. (R1 - Feb)

                        int startpc = pc;
                        EmitPushNull();

                        // Push the identifier local block
                        dimensions = 0;
                        EmitPushVarData(runtimeIndex, dimensions);

                        ProtoCore.Type varType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, false, 0);

                        // TODO Jun: Refactor Allocate() to just return the symbol node itself
                        ProtoCore.DSASM.SymbolNode symnode = Allocate(globalClassIndex, globalClassIndex, globalProcIndex, t.Value, varType, ProtoCore.DSASM.Constants.kPrimitiveSize,
                            false, ProtoCore.DSASM.AccessSpecifier.kPublic, ProtoCore.DSASM.MemoryRegion.kMemStack, t.line, t.col, graphNode);
                        Debug.Assert(symnode != null);

                        int symbolindex = symnode.symbolTableIndex;
                        if (ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex)
                        {
                            symbolnode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList[symbolindex];
                        }
                        else
                        {
                            symbolnode = codeBlock.symbolTable.symbolList[symbolindex];
                        }

                        EmitInstrConsole(ProtoCore.DSASM.kw.pop, t.Value);
                        EmitPopForSymbol(symnode);

                        // Comment it out. It doesn't work for the following
                        // case:
                        //
                        //     x = foo.X;
                        //     x = bar.X;
                        //
                        // where bar hasn't defined yet, so a null assign
                        // graph is generated for this case:
                        //
                        //    bar = null;
                        //    x = %dot(.., {bar}, ...);
                        //
                        // unfortunately the expression UID of this null graph
                        // node is 0, which is wrong. Some update routines have
                        // the assumption that the exprUID of graph node is
                        // incremental.
                        //
                        // We may generate SSA for all expressions to fix this
                        // issue. -Yu Ke
                        /*
                        ProtoCore.AssociativeGraph.GraphNode nullAssignGraphNode = new ProtoCore.AssociativeGraph.GraphNode();
                        nullAssignGraphNode.PushSymbolReference(symbolnode);
                        nullAssignGraphNode.procIndex = globalProcIndex;
                        nullAssignGraphNode.classIndex = globalClassIndex;
                        nullAssignGraphNode.updateBlock.startpc = startpc;
                        nullAssignGraphNode.updateBlock.endpc = pc - 1;

                        codeBlock.instrStream.dependencyGraph.Push(nullAssignGraphNode);
                        */
                    }
                }

                if (null != t.ArrayDimensions)
                {
                    dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions, graphNode, parentNode, subPass);
                }
            }
            else
            {
                if (compileStateTracker.ExecMode == ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter &&
                    !isAllocated)
                {
                    // It happens when the debugger try to watch a variable
                    // which has been out of scope (as watch is done through
                    // execute an expression "t = v;" where v is the variable
                    // to be watched.
                    EmitPushNull();
                    return;
                }

                Validity.Assert(isAllocated);

                if (graphNode != null
                    && IsAssociativeArrayIndexing
                    && !CoreUtils.IsAutoGeneratedVar(symbolnode.name))
                {
                    ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode();
                    updateNode.symbol = symbolnode;
                    updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol;

                    if (graphNode.isIndexingLHS)
                    {
                        graphNode.dimensionNodeList.Add(updateNode);
                    }
                    else
                    {
                        int curDepIndex = graphNode.dependentList.Count - 1;
                        if (curDepIndex >= 0)
                        {
                            var curDep = graphNode.dependentList[curDepIndex].updateNodeRefList[0].nodeList[0];
                            curDep.dimensionNodeList.Add(updateNode);

                            if (null != firstSSAGraphNode)
                            {
                                curDepIndex = firstSSAGraphNode.dependentList.Count - 1;
                                if (curDepIndex >= 0)
                                {
                                    ProtoCore.AssociativeGraph.UpdateNode firstSSAUpdateNode = firstSSAGraphNode.dependentList[curDepIndex].updateNodeRefList[0].nodeList[0];
                                    firstSSAUpdateNode.dimensionNodeList.Add(updateNode);
                                }
                            }
                        }
                    }
                }

                // If it is a property, replaced it with getter: %get_prop()
                if (symbolnode.classScope != ProtoCore.DSASM.Constants.kInvalidIndex &&
                    symbolnode.functionIndex == ProtoCore.DSASM.Constants.kGlobalScope &&
                    localProcedure != null)
                {
                    string getterName = ProtoCore.DSASM.Constants.kGetterPrefix + t.Name;
                    if (!string.Equals(localProcedure.name, getterName))
                    {
                        var thisNode = nodeBuilder.BuildIdentfier(ProtoCore.DSDefinitions.Keyword.This);
                        var identListNode = nodeBuilder.BuildIdentList(thisNode, t);
                        EmitIdentifierListNode(identListNode, ref inferedType, false, graphNode, ProtoCore.DSASM.AssociativeSubCompilePass.kNone);

                        if (null != graphNode)
                        {
                            ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode();
                            dependentNode.PushSymbolReference(symbolnode);
                            graphNode.PushDependent(dependentNode);
                        }

                        return;
                    }
                }

                type = symbolnode.datatype;
                runtimeIndex = symbolnode.runtimeTableIndex;

                // The graph node always depends on this identifier
                if (null != graphNode)
                {
                    ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode();
                    dependentNode.PushSymbolReference(symbolnode);
                    graphNode.PushDependent(dependentNode);
                }

                bool emitReplicationGuideFlag = emitReplicationGuide;
                emitReplicationGuide = false;
                if (null != t.ArrayDimensions)
                {
                    dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions, graphNode, parentNode, subPass);
                }
                emitReplicationGuide = emitReplicationGuideFlag;

                //fix type's rank
                if (type.rank >= 0)
                {
                    type.rank -= dimensions;
                    if (type.rank < 0)
                    {
                        //throw new Exception("Exceed maximum rank!");
                        type.rank = 0;
                    }
                }

                //check whether the value is an array
                if (type.rank == 0)
                {
                    type.IsIndexable = false;
                }

                EmitPushVarData(runtimeIndex, dimensions);

                if (ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter == compileStateTracker.ExecMode)
                {
                    EmitInstrConsole(ProtoCore.DSASM.kw.pushw, t.Value);
                    EmitPushForSymbolW(symbolnode, t.line, t.col);
                }
                else
                {
                    EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Value);
                    EmitPushForSymbol(symbolnode, t);

                    if (compileStateTracker.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide)
                    {
                        int guides = EmitReplicationGuides(t.ReplicationGuides);
                        EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, guides + "[guide]");
                        EmitPushReplicationGuide(guides);
                    }
                }

                if (ignoreRankCheck || compileStateTracker.TypeSystem.IsHigherRank(type.UID, inferedType.UID))
                {
                    inferedType = type;
                }
                // We need to get inferedType for boolean variable so that we can perform type check
                inferedType.UID = (isBooleanOp || (type.UID == (int)PrimitiveType.kTypeBool)) ? (int)PrimitiveType.kTypeBool : inferedType.UID;
            }
        }
예제 #23
0
        private void EmitFunctionDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone)
        {
            bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.DSASM.AssociativeCompilePass.kGlobalFuncBody == compilePass;
            bool parseMemberFunctionBody = ProtoCore.DSASM.Constants.kGlobalScope != globalClassIndex && ProtoCore.DSASM.AssociativeCompilePass.kClassMemFuncBody == compilePass;

            FunctionDefinitionNode funcDef = node as FunctionDefinitionNode;
            localFunctionDefNode = funcDef;

            if (funcDef.IsAssocOperator)
            {
                isAssocOperator = true;
            }
            else
            {
                isAssocOperator = false;
            }

            bool hasReturnStatement = false;
            ProtoCore.DSASM.CodeBlockType origCodeBlockType = codeBlock.blockType;
            codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction;
            if (IsParsingGlobalFunctionSig() || IsParsingMemberFunctionSig())
            {
                Debug.Assert(null == localProcedure);
                localProcedure = new ProtoCore.DSASM.ProcedureNode();

                localProcedure.name = funcDef.Name;
                localProcedure.pc = ProtoCore.DSASM.Constants.kInvalidIndex;
                localProcedure.localCount = 0; // Defer till all locals are allocated
                localProcedure.returntype.UID = compileStateTracker.TypeSystem.GetType(funcDef.ReturnType.Name);
                if (localProcedure.returntype.UID == (int)PrimitiveType.kInvalidType)
                {
                    string message = String.Format(ProtoCore.BuildData.WarningMessage.kReturnTypeUndefined, funcDef.ReturnType.Name, funcDef.Name);
                    buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kTypeUndefined, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col);
                    localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar;
                }
                localProcedure.returntype.IsIndexable = funcDef.ReturnType.IsIndexable;
                localProcedure.returntype.rank = funcDef.ReturnType.rank;
                localProcedure.isConstructor = false;
                localProcedure.isStatic = funcDef.IsStatic;
                localProcedure.runtimeIndex = codeBlock.codeBlockId;
                localProcedure.access = funcDef.access;
                localProcedure.isExternal = funcDef.IsExternLib;
                localProcedure.isAutoGenerated = funcDef.IsAutoGenerated;
                localProcedure.classScope = globalClassIndex;
                localProcedure.isAssocOperator = funcDef.IsAssocOperator;
                localProcedure.isAutoGeneratedThisProc = funcDef.IsAutoGeneratedThisProc;

                int peekFunctionindex = ProtoCore.DSASM.Constants.kInvalidIndex;

                if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex)
                {
                    peekFunctionindex = codeBlock.procedureTable.procList.Count;
                }
                else
                {
                    peekFunctionindex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count;
                }

                // Append arg symbols
                List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>();
                if (null != funcDef.Singnature)
                {
                    int argNumber = 0;
                    foreach (VarDeclNode argNode in funcDef.Singnature.Arguments)
                    {
                        ++argNumber;

                        IdentifierNode paramNode = null;
                        bool aIsDefault = false;
                        ProtoCore.AST.Node aDefaultExpression = null;
                        if (argNode.NameNode is IdentifierNode)
                        {
                            paramNode = argNode.NameNode as IdentifierNode;
                        }
                        else if (argNode.NameNode is BinaryExpressionNode)
                        {
                            BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode;
                            paramNode = bNode.LeftNode as IdentifierNode;
                            aIsDefault = true;
                            aDefaultExpression = bNode;
                            //buildStatus.LogSemanticError("Defualt parameters are not supported");
                            //throw new BuildHaltException();
                        }
                        else
                        {
                            Debug.Assert(false, "Check generated AST");
                        }

                        ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode);
                        // We dont directly allocate arguments now
                        argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(paramNode.Value, argType));

                        localProcedure.argTypeList.Add(argType);
                        ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { Name = paramNode.Value, isDefault = aIsDefault, defaultExpression = aDefaultExpression };
                        localProcedure.argInfoList.Add(argInfo);
                    }
                }

                if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex)
                {
                    globalProcIndex = codeBlock.procedureTable.Append(localProcedure);
                }
                else
                {
                    globalProcIndex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.Append(localProcedure);
                }

                // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur
                if (ProtoCore.DSASM.Constants.kInvalidIndex != globalProcIndex)
                {
                    Debug.Assert(peekFunctionindex == localProcedure.procId);

                    argsToBeAllocated.ForEach(arg =>
                    {
                        int symbolIndex = AllocateArg(arg.Key, globalProcIndex, arg.Value);
                        if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex)
                        {
                            throw new BuildHaltException("B2CB2093");
                        }
                    });

                    // TODO Jun: Remove this once agree that alltest cases assume the default assoc block is block 0
                    // NOTE: Only affects mirror, not actual execution
                    if (null == codeBlock.parent && pc <= 0)
                    {
                        // The first node in the top level block is a function
                        compileStateTracker.DSExecutable.isSingleAssocBlock = false;
                    }

            #if ENABLE_EXCEPTION_HANDLING
                    core.ExceptionHandlingManager.Register(codeBlock.codeBlockId, globalProcIndex, globalClassIndex);
            #endif
                }
                else
                {
                    string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodAlreadyDefined, localProcedure.name);
                    buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col);
                    funcDef.skipMe = true;
                }
            }
            else if (parseGlobalFunctionBody || parseMemberFunctionBody)
            {
                if (compileStateTracker.Options.DisableDisposeFunctionDebug)
                {
                    if (node.Name.Equals(ProtoCore.DSDefinitions.Keyword.Dispose))
                    {
                        compileStateTracker.Options.EmitBreakpoints = false;
                    }
                }

                // Build arglist for comparison
                List<ProtoCore.Type> argList = new List<ProtoCore.Type>();
                if (null != funcDef.Singnature)
                {
                    foreach (VarDeclNode argNode in funcDef.Singnature.Arguments)
                    {
                        ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode);
                        argList.Add(argType);
                    }
                }

                // Get the exisitng procedure that was added on the previous pass
                if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex)
                {
                    globalProcIndex = codeBlock.procedureTable.IndexOfExact(funcDef.Name, argList);
                    localProcedure = codeBlock.procedureTable.procList[globalProcIndex];
                }
                else
                {
                    globalProcIndex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList);
                    localProcedure = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex];
                }

                Debug.Assert(null != localProcedure);

                // code gen the attribute
                localProcedure.Attributes = PopulateAttributes(funcDef.Attributes);
                // Its only on the parse body pass where the real pc is determined. Update this procedures' pc
                //Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc);
                localProcedure.pc = pc;

                // Copy the active function to the core so nested language blocks can refer to it
                compileStateTracker.ProcNode = localProcedure;

                ProtoCore.FunctionEndPoint fep = null;
                if (!funcDef.IsExternLib)
                {
                    //Traverse default argument
                    emitDebugInfo = false;
                    foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList)
                    {
                        if (!argNode.isDefault)
                        {
                            continue;
                        }
                        BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode;
                        // build a temporay node for statement : temp = defaultarg;
                        var iNodeTemp = nodeBuilder.BuildTempVariable();
                        var bNodeTemp = nodeBuilder.BuildBinaryExpression(iNodeTemp, bNode.LeftNode) as BinaryExpressionNode;
                        EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, AssociativeSubCompilePass.kUnboundIdentifier);
                        //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp;
                        InlineConditionalNode icNode = new InlineConditionalNode();
                        icNode.IsAutoGenerated = true;
                        BinaryExpressionNode cExprNode = new BinaryExpressionNode();
                        cExprNode.Optr = ProtoCore.DSASM.Operator.eq;
                        cExprNode.LeftNode = iNodeTemp;
                        cExprNode.RightNode = new DefaultArgNode();
                        icNode.ConditionExpression = cExprNode;
                        icNode.TrueExpression = bNode.RightNode;
                        icNode.FalseExpression = iNodeTemp;
                        bNodeTemp.LeftNode = bNode.LeftNode;
                        bNodeTemp.RightNode = icNode;
                        EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, AssociativeSubCompilePass.kUnboundIdentifier);
                    }
                    emitDebugInfo = true;

                    EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Singnature));

                    // Traverse definition
                    foreach (AssociativeNode bnode in funcDef.FunctionBody.Body)
                    {

                        //
                        // TODO Jun:    Handle stand alone language blocks
                        //              Integrate the subPass into a proper pass
                        //

                        ProtoCore.Type itype = new ProtoCore.Type();
                        itype.UID = (int)PrimitiveType.kTypeVar;

                        if (bnode is LanguageBlockNode)
                        {
                            // Build a binaryn node with a temporary lhs for every stand-alone language block
                            BinaryExpressionNode langBlockNode = new BinaryExpressionNode();
                            langBlockNode.LeftNode = nodeBuilder.BuildIdentfier(compileStateTracker.GenerateTempLangageVar());
                            langBlockNode.Optr = ProtoCore.DSASM.Operator.assign;
                            langBlockNode.RightNode = bnode;

                            //DfsTraverse(bnode, ref itype, false, null, ProtoCore.DSASM.AssociativeSubCompilePass.kNone);
                            DfsTraverse(langBlockNode, ref itype, false, null, subPass);
                        }
                        else
                        {
                            DfsTraverse(bnode, ref itype, false, null, subPass);
                        }

                        if (NodeUtils.IsReturnExpressionNode(bnode))
                            hasReturnStatement = true;
                    }
                    EmitCompileLogFunctionEnd();

                    // All locals have been stack allocated, update the local count of this function
                    localProcedure.localCount = compileStateTracker.BaseOffset;

                    if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex)
                    {
                        localProcedure.localCount = compileStateTracker.BaseOffset;

                        // Update the param stack indices of this function
                        foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values)
                        {
                            if (symnode.functionIndex == localProcedure.procId && symnode.isArgument)
                            {
                                symnode.index -= localProcedure.localCount;
                            }
                        }
                    }
                    else
                    {
                        compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[localProcedure.procId].localCount = compileStateTracker.BaseOffset;

                        // Update the param stack indices of this function
                        foreach (ProtoCore.DSASM.SymbolNode symnode in compileStateTracker.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList.Values)
                        {
                            if (symnode.functionIndex == localProcedure.procId && symnode.isArgument)
                            {
                                symnode.index -= localProcedure.localCount;
                            }
                        }
                    }

                    ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord();
                    record.pc = localProcedure.pc;
                    record.locals = localProcedure.localCount;
                    record.classIndex = globalClassIndex;
                    record.funcIndex = localProcedure.procId;
                    fep = new ProtoCore.Lang.JILFunctionEndPoint(record);
                }
                else if (funcDef.BuiltInMethodId != ProtoCore.Lang.BuiltInMethods.MethodID.kInvalidMethodID)
                {
                    fep = new ProtoCore.Lang.BuiltInFunctionEndPoint(funcDef.BuiltInMethodId);
                }
                else
                {
                    ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord();
                    jRecord.pc = localProcedure.pc;
                    jRecord.locals = localProcedure.localCount;
                    jRecord.classIndex = globalClassIndex;
                    jRecord.funcIndex = localProcedure.procId;

                    // TODO Jun/Luke: Wrap this into Core.Options and extend if needed
                  /*  bool isCSFFI = false;
                    if (isCSFFI)
                    {
                        ProtoCore.Lang.CSFFIActivationRecord record = new ProtoCore.Lang.CSFFIActivationRecord();
                        record.JILRecord = jRecord;
                        record.FunctionName = funcDef.Name;
                        record.ModuleName = funcDef.ExternLibName;
                        record.ModuleType = "dll";
                        record.IsDNI = funcDef.IsDNI;
                        record.ReturnType = funcDef.ReturnType;
                        record.ParameterTypes = localProcedure.argTypeList;
                        fep = new ProtoCore.Lang.CSFFIFunctionEndPoint(record);
                    }
                    else
                    {*/
                        ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord();
                        record.JILRecord = jRecord;
                        record.FunctionName = funcDef.Name;
                        record.ModuleName = funcDef.ExternLibName;
                        record.ModuleType = "dll";
                        record.IsDNI = funcDef.IsDNI;
                        record.ReturnType = funcDef.ReturnType;
                        record.ParameterTypes = localProcedure.argTypeList;
                        fep = new ProtoCore.Lang.FFIFunctionEndPoint(record);
                    //}
                }

                // Construct the fep arguments
                fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count];
                fep.BlockScope = codeBlock.codeBlockId;
                fep.ClassOwnerIndex = localProcedure.classScope;
                fep.procedureNode = localProcedure;
                localProcedure.argTypeList.CopyTo(fep.FormalParams, 0);

                // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables
                // Determine whether this still needs to be aligned to the actual 'classIndex' variable
                // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged
                int classIndexAtCallsite = globalClassIndex + 1;
                FunctionGroup functionGroup = compileStateTracker.FunctionTable.GetFunctionGroup(classIndexAtCallsite, funcDef.Name);
                if (functionGroup != null)
                {
                    functionGroup.FunctionEndPoints.Add(fep);
                }
                else
                {
                    // If any functions in the base class have the same name, append them here
                    FunctionGroup basegroup = null;

                    int ci = classIndexAtCallsite - 1;
                    if (ci != Constants.kInvalidIndex)
                    {
                        ProtoCore.DSASM.ClassNode cnode = compileStateTracker.ClassTable.ClassNodes[ci];
                        if (cnode.baseList.Count > 0)
                        {
                            Validity.Assert(1 == cnode.baseList.Count, "We don't support multiple inheritance yet");
                            basegroup = compileStateTracker.FunctionTable.GetFunctionGroup(cnode.baseList[0] + 1, funcDef.Name);
                        }
                    }

                    if (basegroup == null)
                    {
                        compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep);
                    }
                    else
                    {
                        // Copy all non-private feps from the basegroup into this the new group
                        FunctionGroup newGroup = new FunctionGroup();
                        newGroup.CopyVisible(basegroup.FunctionEndPoints);
                        newGroup.FunctionEndPoints.Add(fep);

                        foreach (var newfep in newGroup.FunctionEndPoints)
                        {
                            compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, newfep);
                        }

                    }
                }

                if (!hasReturnStatement && !funcDef.IsExternLib)
                {
                    if (!compileStateTracker.Options.SuppressFunctionResolutionWarning)
                    {
                        string message = String.Format(ProtoCore.BuildData.WarningMessage.kFunctionNotReturnAtAllCodePaths, localProcedure.name);
                        buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col);
                    }
                    EmitReturnNull();
                }

                if (compileStateTracker.Options.DisableDisposeFunctionDebug)
                {
                    if (node.Name.Equals(ProtoCore.DSDefinitions.Keyword.Dispose))
                    {
                        compileStateTracker.Options.EmitBreakpoints = true;
                    }
                }
            }

            compileStateTracker.ProcNode = localProcedure = null;
            codeBlock.blockType = origCodeBlockType;
            globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope;
            localFunctionDefNode = null;
            compileStateTracker.BaseOffset = 0;
            argOffset = 0;
            isAssocOperator = false;
        }
예제 #24
0
        private void SetExecutionFlagForNode(BinaryExpressionNode bnode, int expressionUID)
        { 
            if (core.Options.IsDeltaExecution)
            {
                Validity.Assert(null != bnode);
                Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != expressionUID);
                bool executionflag = true;

                // Get the lhs of the node in the execFlagList ? if it exists
                if (context != null && 
                    context.execFlagList != null && 
                    context.execFlagList.TryGetValue(bnode.LeftNode.Name, out executionflag))
                {
                    if (context.exprExecutionFlags.ContainsKey(expressionUID))
                    {
                        context.exprExecutionFlags[expressionUID] = executionflag;
                    }
                    else
                    {
                        context.exprExecutionFlags.Add(expressionUID, executionflag);
                    }
                }
            }
        }
예제 #25
0
        /// <summary>
        /// Converts lhs ident lists to a function call
        /// a.x = 10 
        ///     -> t = a.%set_x(10)
        ///     
        /// a.x.y = b + c 
        ///     -> a.x.%set_y(b + c)
        ///     
        /// a.x[0] = 10
        ///     ->  tval = a.%get_x()
        ///         tval[0] = 10         
        ///         tmp = a.%set_x(tval)
        /// </summary>
        /// <param name="astList"></param>
        /// <returns></returns>
        private List<AssociativeNode> TransformLHSIdentList(List<AssociativeNode> astList)
        {
            List<AssociativeNode> newAstList = new List<AssociativeNode>();
            foreach (AssociativeNode node in astList)
            {
                BinaryExpressionNode bNode = node as BinaryExpressionNode;
                if (bNode == null)
                {
                    newAstList.Add(node);
                }
                else
                {
                    bool isLHSIdentList = bNode.LeftNode is IdentifierListNode;
                    if (!isLHSIdentList)
                    {
                        newAstList.Add(node);
                    }
                    else
                    {
                        IdentifierNode lhsTemp = new IdentifierNode(Constants.kTempVar);

                        IdentifierListNode identList = bNode.LeftNode as IdentifierListNode;
                        Validity.Assert(identList != null);

                        AssociativeNode argument = bNode.RightNode;

                        IdentifierNode identFunctionCall = identList.RightNode as IdentifierNode;
                        string setterName = ProtoCore.DSASM.Constants.kSetterPrefix + identList.RightNode.Name;
                        bool isArrayIndexed = identFunctionCall.ArrayDimensions != null;
                        if (isArrayIndexed)
                        {
                            // a.x[0] = 10
                            //      tval = a.%get_x()
                            string getterName = ProtoCore.DSASM.Constants.kGetterPrefix + identList.RightNode.Name;
                            ProtoCore.AST.AssociativeAST.FunctionCallNode fcall = new ProtoCore.AST.AssociativeAST.FunctionCallNode();
                            fcall.Function = new IdentifierNode(identList.RightNode.Name);
                            fcall.Function.Name = getterName;

                            IdentifierListNode identList1 = new IdentifierListNode();
                            identList1.LeftNode = identList.LeftNode;
                            identList1.RightNode = fcall;
                            BinaryExpressionNode bnodeGet = new BinaryExpressionNode(
                                lhsTemp,
                                identList1, 
                                Operator.assign
                                );
                            newAstList.Add(bnodeGet);

                            //      tval[0] = 10     
                            IdentifierNode lhsTempIndexed = new IdentifierNode(Constants.kTempVar);
                            lhsTempIndexed.ArrayDimensions = identFunctionCall.ArrayDimensions;
                            BinaryExpressionNode bnodeAssign = new BinaryExpressionNode(
                                lhsTempIndexed,
                                argument,
                                Operator.assign
                                );
                            newAstList.Add(bnodeAssign);

                            //      tmp = a.%set_x(tval)
                            ProtoCore.AST.AssociativeAST.FunctionCallNode fcallSet = new ProtoCore.AST.AssociativeAST.FunctionCallNode();
                            fcallSet.Function = identFunctionCall;
                            fcallSet.Function.Name = setterName;
                            List<AssociativeNode> args = new List<AssociativeNode>();
                            IdentifierNode lhsTempAssignBack = new IdentifierNode(Constants.kTempVar);
                            args.Add(lhsTempAssignBack);
                            fcallSet.FormalArguments = args;

                            IdentifierListNode identList2 = new IdentifierListNode();
                            identList2.LeftNode = identList.LeftNode;
                            identList2.RightNode = fcallSet;

                            IdentifierNode lhsTempAssign = new IdentifierNode(Constants.kTempPropertyVar);

                            BinaryExpressionNode bnodeSet = new BinaryExpressionNode(
                                lhsTempAssign,
                                identList2,
                                Operator.assign
                                );
                            newAstList.Add(bnodeSet);
                        }
                        else
                        {
                            List<AssociativeNode> args = new List<AssociativeNode>();
                            args.Add(argument);

                            ProtoCore.AST.AssociativeAST.FunctionCallNode fcall = new ProtoCore.AST.AssociativeAST.FunctionCallNode();
                            fcall.Function = identFunctionCall;
                            fcall.Function.Name = setterName;
                            fcall.FormalArguments = args;

                            identList.RightNode = fcall;
                            BinaryExpressionNode convertedAssignNode = new BinaryExpressionNode(lhsTemp, identList, Operator.assign);

                            NodeUtils.CopyNodeLocation(convertedAssignNode, bNode);
                            newAstList.Add(convertedAssignNode);
                        }
                    }
                }
            }
            return newAstList;
        }
예제 #26
0
        private void EmitPostFixNode(AssociativeNode node, ref ProtoCore.Type inferedType)
        {
            bool parseGlobal = null == localProcedure && ProtoCore.DSASM.AssociativeCompilePass.kAll == compilePass;
            bool parseGlobalFunction = null != localProcedure && ProtoCore.DSASM.AssociativeCompilePass.kGlobalFuncBody == compilePass;
            bool parseMemberFunction = ProtoCore.DSASM.Constants.kGlobalScope != classIndex && ProtoCore.DSASM.AssociativeCompilePass.kClassMemFuncBody == compilePass;

            if (parseGlobal || parseGlobalFunction || parseMemberFunction)
            {
                PostFixNode pfNode = node as PostFixNode;

                //convert post fix operation to a binary operation
                BinaryExpressionNode binRight = new BinaryExpressionNode();
                BinaryExpressionNode bin = new BinaryExpressionNode();

                binRight.LeftNode = pfNode.Identifier;
                binRight.RightNode = new IntNode() { value = "1" };
                binRight.Optr = (ProtoCore.DSASM.UnaryOperator.Increment == pfNode.Operator) ? ProtoCore.DSASM.Operator.add : ProtoCore.DSASM.Operator.sub;
                bin.LeftNode = pfNode.Identifier;
                bin.RightNode = binRight;
                bin.Optr = ProtoCore.DSASM.Operator.assign;
                EmitBinaryExpressionNode(bin, ref inferedType);
            }
        }
예제 #27
0
        private void EmitMemberVariables(ClassDeclNode classDecl, GraphNode graphNode = null)
        {
            // Class member variable pass
            // Populating each class entry symbols with their respective member variables

            int thisClassIndex = core.ClassTable.GetClassId(classDecl.ClassName);
            globalClassIndex = thisClassIndex;

            if (!unPopulatedClasses.ContainsKey(thisClassIndex))
            {
                return;
            }
            ProtoCore.DSASM.ClassNode thisClass = core.ClassTable.ClassNodes[thisClassIndex];

            // Handle member vars from base class
            if (null != classDecl.BaseClasses)
            {
                for (int n = 0; n < classDecl.BaseClasses.Count; ++n)
                {
                    int baseClassIndex = core.ClassTable.GetClassId(classDecl.BaseClasses[n]);
                    if (ProtoCore.DSASM.Constants.kInvalidIndex != baseClassIndex)
                    {
                        // To handle the case that a base class is defined after
                        // this class.
                        if (unPopulatedClasses.ContainsKey(baseClassIndex))
                        {
                            EmitMemberVariables(unPopulatedClasses[baseClassIndex], graphNode);
                            globalClassIndex = thisClassIndex;
                        }

                        ClassNode baseClass = core.ClassTable.ClassNodes[baseClassIndex];
                        // Append the members variables of every class that this class inherits from
                        foreach (ProtoCore.DSASM.SymbolNode symnode in baseClass.Symbols.symbolList.Values)
                        {
                            // It is a member variables
                            if (ProtoCore.DSASM.Constants.kGlobalScope == symnode.functionIndex)
                            {
                                Validity.Assert(!symnode.isArgument);
                                int symbolIndex = AllocateMemberVariable(thisClassIndex, symnode.isStatic ? symnode.classScope : baseClassIndex, symnode.name, symnode.datatype.rank, symnode.access, symnode.isStatic);

                                if (symbolIndex != ProtoCore.DSASM.Constants.kInvalidIndex)
                                    thisClass.Size += ProtoCore.DSASM.Constants.kPointerSize;
                            }
                        }
                    }
                    else
                    {
                        Validity.Assert(false, "n-pass compile error, fixme Jun....");
                    }
                }
            }

            // This list will store all static properties initialization
            // expression (say x = 1).
            List<BinaryExpressionNode> staticPropertyInitList = new List<BinaryExpressionNode>();

            foreach (VarDeclNode vardecl in classDecl.Variables)
            {
                IdentifierNode varIdent = null;
                if (vardecl.NameNode is IdentifierNode)
                {   
                    varIdent = vardecl.NameNode as IdentifierNode;

                    BinaryExpressionNode bNode = new BinaryExpressionNode();

                    var thisNode =AstFactory.BuildIdentifier(ProtoCore.DSDefinitions.Keyword.This);
                    var propNode =AstFactory.BuildIdentifier(varIdent.Value);
                    bNode.LeftNode = AstFactory.BuildIdentList(thisNode, propNode);

                    NodeUtils.CopyNodeLocation(bNode, vardecl);
                    bNode.Optr = ProtoCore.DSASM.Operator.assign;

                    bool skipInitialization = false;

                    // Initialize it to default value by manually add the right hand side node
                    if (vardecl.ArgumentType.rank == 0)
                    {
                        switch (vardecl.ArgumentType.Name)
                        {
                            case "double": bNode.RightNode = new DoubleNode(0); break;
                            case "int": bNode.RightNode = new IntNode(0); break;
                            case "bool": bNode.RightNode = new BooleanNode(false); break;
                            default: skipInitialization = true; break;
                        }
                    }
                    else if (vardecl.ArgumentType.rank > 0)
                    {
                        if (!vardecl.ArgumentType.Name.Equals("var"))
                            bNode.RightNode = new ExprListNode();
                        else
                            skipInitialization = true;
                    }
                    else if(vardecl.ArgumentType.rank.Equals(ProtoCore.DSASM.Constants.kArbitraryRank))
                    {
                        if (!vardecl.ArgumentType.Name.Equals("var"))
                            bNode.RightNode = new NullNode();
                        else
                            skipInitialization = true;
                    }

                    if (!skipInitialization)
                    {
                        if (vardecl.IsStatic)
                            staticPropertyInitList.Add(bNode);
                        else
                            thisClass.DefaultArgExprList.Add(bNode);
                    }
                }
                else if (vardecl.NameNode is BinaryExpressionNode)
                {
                    BinaryExpressionNode bNode = vardecl.NameNode as BinaryExpressionNode;
                    varIdent = bNode.LeftNode as IdentifierNode;

                    bNode.endCol = vardecl.endCol;
                    bNode.endLine = vardecl.endLine;

                    if (vardecl.IsStatic)
                        staticPropertyInitList.Add(bNode);
                    else
                        thisClass.DefaultArgExprList.Add(bNode);
                }
                else
                {
                    Validity.Assert(false, "Check generated AST");
                }

                // It is possible that fail to allocate variable. In that 
                // case we should remove initializing expression from 
                // cnode's defaultArgExprList
                int symbolIndex = AllocateMemberVariable(thisClassIndex, thisClassIndex, varIdent.Value, vardecl.ArgumentType.rank, vardecl.Access, vardecl.IsStatic);
                if (symbolIndex == ProtoCore.DSASM.Constants.kInvalidIndex)
                {
                    Validity.Assert(thisClass.DefaultArgExprList.Count > 0);
                    thisClass.DefaultArgExprList.RemoveAt(thisClass.DefaultArgExprList.Count - 1);
                }
                // Only generate getter/setter for non-ffi class
                else if (!classDecl.IsExternLib)
                {
                    ProtoCore.DSASM.SymbolNode prop =
                        vardecl.IsStatic
                        ? core.CodeBlockList[0].symbolTable.symbolList[symbolIndex]
                        : core.ClassTable.ClassNodes[thisClassIndex].Symbols.symbolList[symbolIndex];
                    string typeName = vardecl.ArgumentType.Name;
                    if (String.IsNullOrEmpty(typeName))
                    {
                        prop.datatype = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, Constants.kArbitraryRank);
                    }
                    else
                    {
                        int type = core.TypeSystem.GetType(typeName);
                        if (type == (int)PrimitiveType.kInvalidType)
                        {
                            string message = String.Format(ProtoCore.Properties.Resources.kTypeUndefined, typeName);
                            core.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kTypeUndefined, message, core.CurrentDSFileName, vardecl.line, vardecl.col, graphNode);
                            prop.datatype = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0);
                        }
                        else
                        {
                            int rank = vardecl.ArgumentType.rank;
                            prop.datatype = core.TypeSystem.BuildTypeObject(type, rank);
                            if (type != (int)PrimitiveType.kTypeVar || prop.datatype.IsIndexable)
                            {
                                prop.staticType = prop.datatype;
                            }
                        }
                    }

                    EmitGetterForProperty(classDecl, prop);
                    EmitSetterForProperty(classDecl, prop);
                }
            }
            classOffset = 0;

            // Now we are going to create a static function __init_static_properties()
            // which will initialize all static properties. We will emit a 
            // call to this function after all classes have been compiled.
            if (staticPropertyInitList.Count > 0 && !classDecl.IsExternLib)
            {
                FunctionDefinitionNode initFunc = new FunctionDefinitionNode
                {
                    Name = ProtoCore.DSASM.Constants.kStaticPropertiesInitializer,
                    Signature = new ArgumentSignatureNode(),
                    Pattern = null,
                    ReturnType = new ProtoCore.Type { Name = core.TypeSystem.GetType((int)PrimitiveType.kTypeNull), UID = (int)PrimitiveType.kTypeNull },
                    FunctionBody = new CodeBlockNode(),
                    IsExternLib = false,
                    IsDNI = false,
                    ExternLibName = null,
                    Access = ProtoCore.CompilerDefinitions.AccessModifier.kPublic,
                    IsStatic = true
                };
                classDecl.Procedures.Add(initFunc);

                staticPropertyInitList.ForEach(bNode => initFunc.FunctionBody.Body.Add(bNode));
                initFunc.FunctionBody.Body.Add(AstFactory.BuildReturnStatement(new NullNode()));
            }

            unPopulatedClasses.Remove(thisClassIndex);
        }
예제 #28
0
        public void TestBuildAST_01()
        {
            //==============================================
            //
            // import("ProtoGeometry.dll");
            // p = Point.Bycoordinates(0.0, 2.0, 1.0);
            // xval = p.X;
            //
            //==============================================


            //==============================================
            // Build the import Nodes
            //==============================================
            ProtoScript.Runners.ILiveRunner liveRunner = new ProtoScript.Runners.LiveRunner();

            List <string> libs = new List <string>();

            libs.Add("ProtoGeometry.dll");
            liveRunner.ResetVMAndImportLibrary(libs);

            string        type            = "Point";
            long          hostInstancePtr = 0;
            string        functionName    = "ByCoordinates";
            List <IntPtr> userDefinedArgs = null;
            List <string> primitiveArgs   = new List <string>();

            primitiveArgs.Add("0");
            primitiveArgs.Add("2");
            primitiveArgs.Add("1");
            string formatString = "ddd";
            string symbolName   = "";
            string code         = "";

            AssociativeNode assign1 = ASTCompilerUtils.BuildAST(type, hostInstancePtr, functionName, userDefinedArgs, primitiveArgs, formatString, liveRunner.Core,
                                                                ref symbolName, ref code);

            liveRunner.UpdateGraph(assign1);

            primitiveArgs.Clear();
            primitiveArgs.Add("10");
            primitiveArgs.Add("0");
            primitiveArgs.Add("0");

            functionName = "Translate";
            AssociativeNode assign2 = ASTCompilerUtils.BuildAST(symbolName, hostInstancePtr, functionName, userDefinedArgs, primitiveArgs, formatString, liveRunner.Core,
                                                                ref symbolName, ref code);

            liveRunner.UpdateGraph(assign2);

            //==============================================
            // Build a binary expression to retirieve the x property
            // xval = p.X;
            //==============================================
            List <ProtoCore.AST.AssociativeAST.AssociativeNode> astList = new List <ProtoCore.AST.AssociativeAST.AssociativeNode>();

            ProtoCore.AST.AssociativeAST.IdentifierListNode identListNode = new ProtoCore.AST.AssociativeAST.IdentifierListNode();
            identListNode.LeftNode  = new ProtoCore.AST.AssociativeAST.IdentifierNode(symbolName);
            identListNode.Optr      = ProtoCore.DSASM.Operator.dot;
            identListNode.RightNode = new ProtoCore.AST.AssociativeAST.IdentifierNode("X");
            ProtoCore.AST.AssociativeAST.BinaryExpressionNode stmt2 = new ProtoCore.AST.AssociativeAST.BinaryExpressionNode(
                new ProtoCore.AST.AssociativeAST.IdentifierNode("xval"),
                identListNode,
                ProtoCore.DSASM.Operator.assign);
            astList.Add(stmt2);
            //==============================================
            //
            // import("ProtoGeometry.dll");
            // p = Point.Bycoordinates(0.0, 20.0, 1.0);
            // q = p.Translate(10.0, 0.0, 0.0);
            // xval = p.X;
            //
            //==============================================

            // update graph
            CodeBlockNode cNode = new CodeBlockNode();

            cNode.Body = astList;
            liveRunner.UpdateGraph(cNode);

            ProtoCore.Mirror.RuntimeMirror mirror = liveRunner.InspectNodeValue("xval");
            Assert.IsTrue((double)mirror.GetData().Data == 10.0);
        }
예제 #29
0
        private void EmitFunctionDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, GraphNode graphNode = null)
        {
            bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.CompilerDefinitions.Associative.CompilePass.kGlobalFuncBody == compilePass;
            bool parseMemberFunctionBody = ProtoCore.DSASM.Constants.kGlobalScope != globalClassIndex && ProtoCore.CompilerDefinitions.Associative.CompilePass.kClassMemFuncBody == compilePass;

            FunctionDefinitionNode funcDef = node as FunctionDefinitionNode;
            localFunctionDefNode = funcDef;

            if (funcDef.IsAssocOperator)
            {
                isAssocOperator = true;
            }
            else
            {
                isAssocOperator = false;
            }

            bool hasReturnStatement = false;
            ProtoCore.DSASM.CodeBlockType origCodeBlockType = codeBlock.blockType;
            codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction;
            if (IsParsingGlobalFunctionSig() || IsParsingMemberFunctionSig())
            {
                Validity.Assert(null == localProcedure);
                localProcedure = new ProtoCore.DSASM.ProcedureNode();

                localProcedure.Name = funcDef.Name;
                localProcedure.PC = ProtoCore.DSASM.Constants.kInvalidIndex;
                localProcedure.LocalCount = 0; // Defer till all locals are allocated
                var uid = core.TypeSystem.GetType(funcDef.ReturnType.Name);
                var rank = funcDef.ReturnType.rank;
                var returnType = core.TypeSystem.BuildTypeObject(uid, rank); 
                if (returnType.UID == (int)PrimitiveType.kInvalidType)
                {
                    string message = String.Format(ProtoCore.Properties.Resources.kReturnTypeUndefined, funcDef.ReturnType.Name, funcDef.Name);
                    buildStatus.LogWarning(WarningID.kTypeUndefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode);
                    returnType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, rank);
                }
                localProcedure.ReturnType = returnType;
                localProcedure.IsConstructor = false;
                localProcedure.IsStatic = funcDef.IsStatic;
                localProcedure.RuntimeIndex = codeBlock.codeBlockId;
                localProcedure.AccessModifier = funcDef.Access;
                localProcedure.IsExternal = funcDef.IsExternLib;
                localProcedure.IsAutoGenerated = funcDef.IsAutoGenerated;
                localProcedure.ClassID = globalClassIndex;
                localProcedure.IsAssocOperator = funcDef.IsAssocOperator;
                localProcedure.IsAutoGeneratedThisProc = funcDef.IsAutoGeneratedThisProc;

                localProcedure.MethodAttribute = funcDef.MethodAttributes;

                int peekFunctionindex = ProtoCore.DSASM.Constants.kInvalidIndex;

                if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex)
                {
                    peekFunctionindex = codeBlock.procedureTable.Procedures.Count;
                }
                else
                {
                    peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures.Count;
                }

                // Append arg symbols
                List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>();
                string functionDescription = localProcedure.Name;
                if (null != funcDef.Signature)
                {
                    foreach (VarDeclNode argNode in funcDef.Signature.Arguments)
                    {
                        var argInfo = BuildArgumentInfoFromVarDeclNode(argNode);
                        localProcedure.ArgumentInfos.Add(argInfo);

                        var argType = BuildArgumentTypeFromVarDeclNode(argNode, graphNode);
                        localProcedure.ArgumentTypes.Add(argType);

                        argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(argInfo.Name, argType));

                        functionDescription += argNode.ArgumentType.ToString();
                    }
                    localProcedure.HashID = functionDescription.GetHashCode();
                    localProcedure.IsVarArg = funcDef.Signature.IsVarArg;
                }

                if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex)
                {
                    globalProcIndex = codeBlock.procedureTable.Append(localProcedure);
                }
                else
                {
                    globalProcIndex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Append(localProcedure);
                }

                // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur
                if (ProtoCore.DSASM.Constants.kInvalidIndex != globalProcIndex)
                {
                    argsToBeAllocated.ForEach(arg =>
                    {
                        int symbolIndex = AllocateArg(arg.Key, globalProcIndex, arg.Value);
                        if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex)
                        {
                            throw new BuildHaltException("B2CB2093");
                        }
                    });                   
                }
                else
                {
                    string message = String.Format(ProtoCore.Properties.Resources.kMethodAlreadyDefined, localProcedure.Name);
                    buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode);
                    funcDef.skipMe = true;
                }
            }
            else if (parseGlobalFunctionBody || parseMemberFunctionBody)
            {
                if (CoreUtils.IsDisposeMethod(node.Name))
                {
                    core.Options.EmitBreakpoints = false;
                }

                // Build arglist for comparison
                List<ProtoCore.Type> argList = new List<ProtoCore.Type>();
                if (null != funcDef.Signature)
                {
                    foreach (VarDeclNode argNode in funcDef.Signature.Arguments)
                    {
                        ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, graphNode);
                        argList.Add(argType);
                    }
                }

                // Get the exisitng procedure that was added on the previous pass
                if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex)
                {
                    var procNode = codeBlock.procedureTable.GetFunctionBySignature(funcDef.Name, argList);
                    globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID;
                    localProcedure = codeBlock.procedureTable.Procedures[globalProcIndex];
                }
                else
                {
                    var procNode = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.GetFunctionBySignature(funcDef.Name, argList);
                    globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID;
                    localProcedure = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex];
                }

                Validity.Assert(null != localProcedure);

                // code gen the attribute 
                localProcedure.Attributes = PopulateAttributes(funcDef.Attributes);
                // Its only on the parse body pass where the real pc is determined. Update this procedures' pc
                //Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc);
                localProcedure.PC = pc;

                // Copy the active function to the core so nested language blocks can refer to it
                core.ProcNode = localProcedure;

                ProtoCore.FunctionEndPoint fep = null;
                if (!funcDef.IsExternLib)
                {
                    //Traverse default argument
                    emitDebugInfo = false;
                    foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.ArgumentInfos)
                    {
                        if (!argNode.IsDefault)
                        {
                            continue;
                        }
                        BinaryExpressionNode bNode = argNode.DefaultExpression as BinaryExpressionNode;
                        // build a temporay node for statement : temp = defaultarg;
                        var iNodeTemp = AstFactory.BuildIdentifier(core.GenerateTempVar());
                        var bNodeTemp = AstFactory.BuildAssignment(iNodeTemp, bNode.LeftNode);
                        bNodeTemp.IsProcedureOwned = true;
                        EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier);
                        //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp;
                        InlineConditionalNode icNode = new InlineConditionalNode();
                        icNode.IsAutoGenerated = true;
                        BinaryExpressionNode cExprNode = new BinaryExpressionNode();
                        cExprNode.Optr = ProtoCore.DSASM.Operator.eq;
                        cExprNode.LeftNode = iNodeTemp;
                        cExprNode.RightNode = new DefaultArgNode();
                        icNode.ConditionExpression = cExprNode;
                        icNode.TrueExpression = bNode.RightNode;
                        icNode.FalseExpression = iNodeTemp;
                        bNodeTemp.LeftNode = bNode.LeftNode;
                        bNodeTemp.RightNode = icNode;
                        EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier);
                    }
                    emitDebugInfo = true;

                    EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature));

                    ProtoCore.Type itype = new ProtoCore.Type();

                    hasReturnStatement = EmitCodeBlock(funcDef.FunctionBody.Body, ref itype, subPass, true);

                    // Build dependency within the function
                    ProtoCore.AssociativeEngine.Utils.BuildGraphNodeDependencies(
                        codeBlock.instrStream.dependencyGraph.GetGraphNodesAtScope(globalClassIndex, globalProcIndex));


                    EmitCompileLogFunctionEnd();

                    // All locals have been stack allocated, update the local count of this function
                    localProcedure.LocalCount = core.BaseOffset;

                    if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex)
                    {
                        localProcedure.LocalCount = core.BaseOffset;

                        // Update the param stack indices of this function
                        foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values)
                        {
                            if (symnode.functionIndex == localProcedure.ID && symnode.isArgument)
                            {
                                symnode.index -= localProcedure.LocalCount;
                            }
                        }
                    }
                    else
                    {
                        core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[localProcedure.ID].LocalCount = core.BaseOffset;

                        // Update the param stack indices of this function
                        foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[globalClassIndex].Symbols.symbolList.Values)
                        {
                            if (symnode.functionIndex == localProcedure.ID && symnode.isArgument)
                            {
                                symnode.index -= localProcedure.LocalCount;
                            }
                        }
                    }

                    ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord();
                    record.pc = localProcedure.PC;
                    record.locals = localProcedure.LocalCount;
                    record.classIndex = globalClassIndex;
                    record.funcIndex = localProcedure.ID;
                    fep = new ProtoCore.Lang.JILFunctionEndPoint(record);
                }
                else if (funcDef.BuiltInMethodId != ProtoCore.Lang.BuiltInMethods.MethodID.kInvalidMethodID)
                {
                    fep = new ProtoCore.Lang.BuiltInFunctionEndPoint(funcDef.BuiltInMethodId);
                }
                else
                {
                    ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord();
                    jRecord.pc = localProcedure.PC;
                    jRecord.locals = localProcedure.LocalCount;
                    jRecord.classIndex = globalClassIndex;
                    jRecord.funcIndex = localProcedure.ID;

                    ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord();
                    record.JILRecord = jRecord;
                    record.FunctionName = funcDef.Name;
                    record.ModuleName = funcDef.ExternLibName;
                    record.ModuleType = "dll";
                    record.IsDNI = funcDef.IsDNI;
                    record.ReturnType = funcDef.ReturnType;
                    record.ParameterTypes = localProcedure.ArgumentTypes;
                    fep = new ProtoCore.Lang.FFIFunctionEndPoint(record);
                }

                // Construct the fep arguments
                fep.FormalParams = new ProtoCore.Type[localProcedure.ArgumentTypes.Count];
                fep.BlockScope = codeBlock.codeBlockId;
                fep.ClassOwnerIndex = localProcedure.ClassID;
                fep.procedureNode = localProcedure;
                localProcedure.ArgumentTypes.CopyTo(fep.FormalParams, 0);

                // 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables
                int classIndexAtCallsite = globalClassIndex + 1;
                core.FunctionTable.InitGlobalFunctionEntry(classIndexAtCallsite);

                // Get the function group of the current class and see if the current function exists
                Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite];
                if (!fgroup.ContainsKey(funcDef.Name))
                {
                    // If any functions in the base class have the same name, append them here
                    int ci = classIndexAtCallsite - 1;
                    if (ProtoCore.DSASM.Constants.kInvalidIndex != ci)
                    {
                        ProtoCore.DSASM.ClassNode cnode = core.ClassTable.ClassNodes[ci];
                        if (cnode.Bases.Count > 0)
                        {
                            Validity.Assert(1 == cnode.Bases.Count, "We don't support multiple inheritance yet");

                            ci = cnode.Bases[0];

                            Dictionary<string, FunctionGroup> tgroup = new Dictionary<string, FunctionGroup>();
                            int callsiteCI = ci + 1;
                            bool bSucceed = core.FunctionTable.GlobalFuncTable.TryGetValue(callsiteCI, out tgroup);
                            if (bSucceed)
                            {
                                if (tgroup.ContainsKey(funcDef.Name))
                                {
                                    // Get that base group - the group of function from the baseclass
                                    FunctionGroup basegroup = new FunctionGroup();
                                    bSucceed = tgroup.TryGetValue(funcDef.Name, out basegroup);
                                    if (bSucceed)
                                    {
                                        // Copy all non-private feps from the basegroup into this the new group
                                        FunctionGroup newGroup = new FunctionGroup();
                                        newGroup.CopyVisible(basegroup.FunctionEndPoints);

                                        // Append the new fep 
                                        newGroup.FunctionEndPoints.Add(fep);

                                        // Copy the new group to this class table
                                        core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, newGroup);
                                    }
                                }
                                else
                                {
                                    // Create a new function group in this class
                                    ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup();
                                    funcGroup.FunctionEndPoints.Add(fep);

                                    // Add this group to the class function tables
                                    core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup);
                                }
                            }
                            else
                            {
                                // Create a new function group in this class
                                ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup();
                                funcGroup.FunctionEndPoints.Add(fep);

                                // Add this group to the class function tables
                                core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup);
                            }
                            cnode = core.ClassTable.ClassNodes[ci];
                        }
                        else
                        {
                            // Create a new function group in this class
                            ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup();
                            funcGroup.FunctionEndPoints.Add(fep);

                            // Add this group to the class function tables
                            core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup);
                        }
                    }
                    else
                    {
                        // Create a new function group in this class
                        ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup();
                        funcGroup.FunctionEndPoints.Add(fep);

                        // Add this group to the class function tables
                        core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup);
                    }
                }
                else
                {
                    // Add this fep into the exisitng function group
                    core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep);
                }

                if (!hasReturnStatement && !funcDef.IsExternLib)
                {
                    if (!core.Options.SuppressFunctionResolutionWarning)
                    {
                        string message = String.Format(ProtoCore.Properties.Resources.kFunctionNotReturnAtAllCodePaths, localProcedure.Name);
                        buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode);
                    }
                    EmitReturnNull();
                }

                if (CoreUtils.IsDisposeMethod(node.Name))
                {
                    core.Options.EmitBreakpoints = true;
                }
            }

            core.ProcNode = localProcedure = null;
            codeBlock.blockType = origCodeBlockType;
            globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope;
            localFunctionDefNode = null;
            core.BaseOffset = 0;
            argOffset = 0;
            isAssocOperator = false;
        }
예제 #30
0
        /// <summary>
        /// Create BinaryExpressionNode
        /// </summary>
        /// <param name="node"></param>
        /// <param name="outnode"></param>
        private void EmitBlockNode(Block node, out AssociativeNode outnode)
        {
            Validity.Assert(node != null);

            // TODO: Confirm that these children are returned in the order that they
            // appear in the code
            Dictionary <int, Node> childNodes = node.GetChildrenWithIndices();

            // Parse program statement in node.Name
            string code = node.Name + ";";

            ProtoCore.AST.AssociativeAST.CodeBlockNode commentNode   = null;
            ProtoCore.AST.AssociativeAST.CodeBlockNode codeBlockNode = (ProtoCore.AST.AssociativeAST.CodeBlockNode)GraphUtilities.Parse(code, out commentNode);
            Validity.Assert(codeBlockNode != null);

            List <ProtoCore.AST.AssociativeAST.AssociativeNode> astList = codeBlockNode.Body;

            Validity.Assert(astList.Count == 1);

            if (astList[0] is ProtoCore.AST.AssociativeAST.IdentifierNode)
            {
                ProtoCore.AST.AssociativeAST.BinaryExpressionNode ben = new ProtoCore.AST.AssociativeAST.BinaryExpressionNode();
                ben.LeftNode = astList[0];
                ben.Optr     = ProtoCore.DSASM.Operator.assign;
                ProtoCore.AST.AssociativeAST.AssociativeNode statement = null;
                foreach (KeyValuePair <int, Node> kvp in childNodes)
                {
                    DFSTraverse(kvp.Value, out statement);
                }
                ben.RightNode = statement;
                astList[0]    = ben;
            }

            //I don't know what I am doing
            if (astList[0] is BinaryExpressionNode)
            {
                BinaryExpressionNode tempBen = astList[0] as BinaryExpressionNode;
                if (tempBen.LeftNode is IdentifierNode)
                {
                    IdentifierNode identitiferNode = tempBen.LeftNode as IdentifierNode;
                    if (identitiferNode.ArrayDimensions != null)
                    {
                        ArrayIndexerNode arrIndex = new ArrayIndexerNode();
                        arrIndex.ArrayDimensions = identitiferNode.ArrayDimensions;
                        arrIndex.Array           = identitiferNode;
                        tempBen.LeftNode         = arrIndex;
                    }
                }
                if (tempBen.RightNode is IdentifierNode)
                {
                    IdentifierNode identitiferNode = tempBen.RightNode as IdentifierNode;
                    if (identitiferNode.ArrayDimensions != null)
                    {
                        ArrayIndexerNode arrIndex = new ArrayIndexerNode();
                        arrIndex.ArrayDimensions = identitiferNode.ArrayDimensions;
                        arrIndex.Array           = identitiferNode;
                        tempBen.RightNode        = arrIndex;
                    }
                }
                astList[0] = tempBen;
            }
            //it should be correct, if not, debug?

            ProtoCore.AST.AssociativeAST.BinaryExpressionNode bNode = astList[0] as ProtoCore.AST.AssociativeAST.BinaryExpressionNode;
            Validity.Assert(bNode != null);
            bNode.Guid = node.Guid;
            //bNode.SplitFromUID = node.splitFomUint;

            // Child nodes are arguments to expression in bNode.RightNode.
            // Match child nodes with IdentifierNode's in bNode.RightNode - pratapa
            foreach (Node n in childNodes.Values)
            {
                AssociativeNode argNode = null;
                DFSTraverse(n, out argNode);

                // DFS traverse the bNode.RightNode and check for IdentifierNode's
                // and if their names match with the names of argNode, then replace
                // the IdentifierNode in bNode.RightNode with argNode
                BinaryExpressionNode ben = argNode as BinaryExpressionNode;
                Validity.Assert(ben != null);
                //ProtoCore.CodeGenDS codeGen = new ProtoCore.CodeGenDS(ben);
                AstCodeBlockTraverse sourceGen = new AstCodeBlockTraverse(ben);
                ProtoCore.AST.AssociativeAST.AssociativeNode right = bNode.RightNode;
                sourceGen.DFSTraverse(ref right);
                bNode.RightNode = right;
            }

            //(AstRootNode as CodeBlockNode).Body.Add(expressionNode);

            Validity.Assert(gc != null);
            gc.HandleNewNode(bNode);

            outnode = bNode;
        }
예제 #31
0
        private void EmitUnaryExpressionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone)
        {
            UnaryExpressionNode u = node as UnaryExpressionNode;
            bool isPrefixOperation = ProtoCore.DSASM.UnaryOperator.Increment == u.Operator || ProtoCore.DSASM.UnaryOperator.Decrement == u.Operator;

            //(Ayush) In case of prefix, apply prefix operation first
            if (isPrefixOperation)
            {
                if (u.Expression is IdentifierListNode || u.Expression is IdentifierNode)
                {
                    BinaryExpressionNode binRight = new BinaryExpressionNode();
                    BinaryExpressionNode bin = new BinaryExpressionNode();
                    binRight.LeftNode = u.Expression;
                    binRight.RightNode = new IntNode(1);
                    binRight.Optr = (ProtoCore.DSASM.UnaryOperator.Increment == u.Operator) ? ProtoCore.DSASM.Operator.add : ProtoCore.DSASM.Operator.sub;
                    bin.LeftNode = u.Expression; bin.RightNode = binRight; bin.Optr = ProtoCore.DSASM.Operator.assign;
                    EmitBinaryExpressionNode(bin, ref inferedType, false, graphNode, subPass);
                }
                else
                    throw new BuildHaltException("Invalid use of prefix operation (DCDDEEF1).");
            }

            DfsTraverse(u.Expression, ref inferedType, false, graphNode, subPass);

            if (!isPrefixOperation && subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier)
            {
                string op = Op.GetUnaryOpName(u.Operator);
                EmitInstrConsole(op);
                EmitUnary(Op.GetUnaryOpCode(u.Operator));
            }
        }
예제 #32
0
        public ProcedureNode TraverseDotFunctionCall(
                                ProtoCore.AST.Node node, 
                                ProtoCore.AST.Node parentNode, 
                                int lefttype, 
                                int depth, 
                                GraphNode graphNode, 
                                ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass,
                                BinaryExpressionNode bnode,
                                ref ProtoCore.Type inferedType)
        {
            ProcedureNode procCallNode = null;

            var dotCallType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0); ;

            bool isConstructor = false;
            bool isStaticCall = false;
            bool isUnresolvedDot = false;

            int classIndex = Constants.kInvalidIndex;
            string className = string.Empty;

            var dotCall = new FunctionDotCallNode(node as FunctionDotCallNode);
            var funcCall = dotCall.DotCall;
            var procName = dotCall.FunctionCall.Function.Name;

            var firstArgument = dotCall.DotCall.FormalArguments[0];
            if (firstArgument is FunctionDotCallNode)
            {
                isUnresolvedDot = true;
            }
            else if (firstArgument is IdentifierNode)
            {
                // Check if the lhs identifer is a class name
                className = (firstArgument as IdentifierNode).Name;
                classIndex = core.ClassTable.IndexOf(className);

                // Check if the lhs is an variable
                SymbolNode symbolnode;
                bool isAccessible;
                bool hasAllocated = VerifyAllocation(className,
                                                     globalClassIndex,
                                                     globalProcIndex,
                                                     out symbolnode,
                                                     out isAccessible);

                bool toResolveMethodOnClass = classIndex != Constants.kInvalidIndex;

                // If the lhs is an variable which happens to have a same name
                // as some class, then check the right hand side is a valid 
                // constructor or static function call. 
                if (toResolveMethodOnClass && hasAllocated && isAccessible)
                {
                    var classes = core.ClassTable.ClassNodes;
                    var classNode = classes[classIndex];
                    int argCount = dotCall.FunctionCall.FormalArguments.Count;
                    var procNode = classNode.GetFirstConstructorBy(procName, argCount);
                    if (procNode == null)
                    {
                        procNode = classNode.GetFirstStaticFunctionBy(procName, argCount);
                    }

                    if (procNode == null)
                    {
                        toResolveMethodOnClass = false;
                        classIndex = Constants.kInvalidIndex;
                        className = string.Empty;
                    }
                }

                if (toResolveMethodOnClass)
                {
                    dotCall.DotCall.FormalArguments[0] = new IntNode(classIndex);
                    inferedType.UID = dotCallType.UID = classIndex;

                    // Now the left hand side of dot call is a valid class name.
                    // There are three cases for the right hand side: calling a 
                    // function, getting a static property or getting a function 
                    // pointer. I.e.,
                    // 
                    //    x = Foo.foo();
                    //
                    // Or
                    //    
                    //    y = Bar.bar;   // static property or funciton pointer
                    //    Bar.bar_2 = z; // static property
                    // 
                    // For the latters, they are converted to getter/setter. 
                    // I.e., 
                    //
                    //    y = Bar.%get_bar();
                    //    %ret = Bar.%set_bar_2(z);
                    //
                    // We need to check each case. 

                    var classes = core.ClassTable.ClassNodes;
                    var classNode = classes[classIndex];

                    var property = String.Empty;
                    if (CoreUtils.TryGetPropertyName(procName, out property))
                    {
                        if (procCallNode == null)
                        {
                            procCallNode = classNode.GetFirstStaticFunctionBy(procName);
                            isStaticCall = procCallNode != null;
                        }

                        if (procCallNode == null)
                        {
                            if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone)
                            {
                                return null;
                            }

                            // Try static function firstly
                            procCallNode = classNode.GetFirstStaticFunctionBy(property);
                            if (procCallNode == null)
                            {
                                procCallNode = classNode.GetFirstMemberFunctionBy(property);
                            }

                            if (procCallNode == null)
                            {
                                procCallNode = classNode.GetFirstMemberFunctionBy(procName);
                            }

                            if (procCallNode != null)
                            {
                                EmitFunctionPointer(procCallNode);
                            }
                            else
                            {
                                string message = String.Format(ProtoCore.Properties.Resources.kCallingNonStaticProperty,
                                                               className,
                                                               property);

                                buildStatus.LogWarning(WarningID.kCallingNonStaticMethodOnClass,
                                                       message,
                                                       core.CurrentDSFileName,
                                                       dotCall.line,
                                                       dotCall.col, 
                                                       graphNode);

                                EmitNullNode(new NullNode(), ref inferedType);
                            }
                            
                            return null;
                        }
                    }
                    else
                    {
                        int argCount = dotCall.FunctionCall.FormalArguments.Count;
                        procCallNode = classNode.GetFirstConstructorBy(procName, argCount);
                        isConstructor = procCallNode != null;

                        if (procCallNode == null)
                        {
                            procCallNode = classNode.GetFirstStaticFunctionBy(procName, argCount);
                            isStaticCall = procCallNode != null;
                        }

                        if (!isStaticCall && !isConstructor)
                        {
                            if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone)
                            {
                                string message = String.Format(ProtoCore.Properties.Resources.kStaticMethodNotFound,
                                                               className,
                                                               procName);

                                buildStatus.LogWarning(WarningID.kFunctionNotFound,
                                                       message,
                                                       core.CurrentDSFileName,
                                                       dotCall.line,
                                                       dotCall.col, 
                                                       graphNode);

                                EmitNullNode(new NullNode(), ref inferedType);
                            }

                            return null;
                        }
                    }
                }
                else if (hasAllocated && symbolnode.datatype.UID != (int)PrimitiveType.kTypeVar)
                {
                    inferedType.UID = symbolnode.datatype.UID;
                    if (Constants.kInvalidIndex != inferedType.UID)
                    {
                        procCallNode = GetProcedureFromInstance(symbolnode.datatype.UID, dotCall.FunctionCall);
                    }

                    if (null != procCallNode)
                    {
                        if (procCallNode.IsConstructor)
                        {
                            if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone)
                            {
                                string message = String.Format(ProtoCore.Properties.Resources.KCallingConstructorOnInstance,
                                                               procName);
                                buildStatus.LogWarning(WarningID.kCallingConstructorOnInstance,
                                                       message,
                                                       core.CurrentDSFileName,
                                                       funcCall.line,
                                                       funcCall.col, 
                                                       graphNode);
                                EmitNullNode(new NullNode(), ref inferedType);
                            }
                            return null;
                        }

                        isAccessible = procCallNode.AccessModifier == ProtoCore.CompilerDefinitions.AccessModifier.kPublic
                             || (procCallNode.AccessModifier == ProtoCore.CompilerDefinitions.AccessModifier.kPrivate && procCallNode.ClassID == globalClassIndex);

                        if (!isAccessible)
                        {
                            if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone)
                            {
                                string message = String.Format(ProtoCore.Properties.Resources.kMethodIsInaccessible, procName);
                                buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, core.CurrentDSFileName, funcCall.line, funcCall.col, graphNode);
                            }
                        }

                        var dynamicRhsIndex = (int)(dotCall.DotCall.FormalArguments[1] as IntNode).Value;
                        var dynFunc = core.DynamicFunctionTable.GetFunctionAtIndex(dynamicRhsIndex);
                        dynFunc.ClassIndex = procCallNode.ClassID;
                    }
                }
                else
                {
                    isUnresolvedDot = true;
                }
            }

            // Its an accceptable method at this point
            List<ProtoCore.Type> arglist = new List<ProtoCore.Type>();
            TraverseDotCallArguments(funcCall, 
                                     dotCall,
                                     procCallNode, 
                                     arglist,
                                     procName, 
                                     classIndex, 
                                     className, 
                                     isStaticCall, 
                                     isConstructor,
                                     graphNode, 
                                     subPass, 
                                     bnode);

            if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier)
            {
                return null;
            }

            if (!isConstructor && !isStaticCall)
            {
                Validity.Assert(dotCall.DotCall.FormalArguments[ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs] is ExprListNode);
                ExprListNode functionArgs = dotCall.DotCall.FormalArguments[ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs] as ExprListNode;
                functionArgs.Exprs.Insert(0, dotCall.DotCall.FormalArguments[ProtoCore.DSASM.Constants.kDotArgIndexPtr]);
            }
           
            // From here on, handle the actual procedure call 
            int type = ProtoCore.DSASM.Constants.kInvalidIndex;

            int refClassIndex = ProtoCore.DSASM.Constants.kInvalidIndex;
            if (parentNode != null && parentNode is IdentifierListNode)
            {
                var leftnode = (parentNode as IdentifierListNode).LeftNode;
                if (leftnode != null && leftnode is IdentifierNode)
                {
                    refClassIndex = core.ClassTable.IndexOf(leftnode.Name);
                }
            }

            if (firstArgument is FunctionCallNode ||
                firstArgument is FunctionDotCallNode ||
                firstArgument is ExprListNode)
            {
                inferedType.UID = arglist[0].UID;
            }

            // If lefttype is a valid class then check if calling a constructor
            if (procCallNode == null 
                && (int)PrimitiveType.kInvalidType != inferedType.UID
                && (int)PrimitiveType.kTypeVoid != inferedType.UID
                && procName != Constants.kFunctionPointerCall)
            {
                procCallNode = core.ClassTable.ClassNodes[inferedType.UID].GetFirstMemberFunctionBy(procName);
            }

            // Try function pointer firstly
            if ((procCallNode == null) && (procName != Constants.kFunctionPointerCall))
            {
                bool isAccessibleFp;
                ProtoCore.DSASM.SymbolNode symbolnode = null;
                bool isAllocated = VerifyAllocation(procName, globalClassIndex, globalProcIndex, out symbolnode, out isAccessibleFp);
                if (isAllocated) // not checking the type against function pointer, as the type could be var
                {
                    procName = Constants.kFunctionPointerCall;
                    // The graph node always depends on this function pointer
                    if (null != graphNode)
                    {
                        PushSymbolAsDependent(symbolnode, graphNode);
                    }
                }
            }

            // Always try global function firstly. Because we dont have syntax
            // support for calling global function (say, ::foo()), if we try
            // member function firstly, there is no way to call a global function
            // For member function, we can use this.foo() to distinguish it from 
            // global function. 
            if ((procCallNode == null) && (procName != Constants.kFunctionPointerCall))
            {
                procCallNode = CoreUtils.GetFunctionBySignature(procName, arglist, codeBlock);
                if (null != procCallNode)
                {
                    type = Constants.kGlobalScope;
                    if (core.TypeSystem.IsHigherRank(procCallNode.ReturnType.UID, inferedType.UID))
                    {
                        inferedType = procCallNode.ReturnType;
                    }
                }
            }

            // Try member functions in global class scope
            if ((procCallNode == null) && (procName != Constants.kFunctionPointerCall) && (parentNode == null))
            {
                if (globalClassIndex != Constants.kInvalidIndex)
                {
                    int realType;
                    bool isAccessible;
                    bool isStaticOrConstructor = refClassIndex != Constants.kInvalidIndex;
                    ProcedureNode memProcNode = core.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor);

                    if (memProcNode != null)
                    {
                        Validity.Assert(realType != Constants.kInvalidIndex);
                        procCallNode = memProcNode;
                        inferedType = procCallNode.ReturnType;
                        type = realType;

                        if (!isAccessible)
                        {
                            string message = String.Format(ProtoCore.Properties.Resources.kMethodIsInaccessible, procName);
                            buildStatus.LogWarning(WarningID.kAccessViolation, message, core.CurrentDSFileName, funcCall.line, funcCall.col, graphNode);

                            inferedType.UID = (int)PrimitiveType.kTypeNull;
                            EmitPushNull();
                            return procCallNode;
                        }
                    }
                }
            }

            if (isUnresolvedDot || procCallNode == null)
            {
                if (dotCallType.UID != (int)PrimitiveType.kTypeVar)
                {
                    inferedType.UID = dotCallType.UID;
                }

                var procNode = CoreUtils.GetFunctionByName(Constants.kDotMethodName, codeBlock);
                if (CoreUtils.IsGetter(procName))
                {
                    EmitFunctionCall(depth, type, arglist, procNode, funcCall, true);
                }
                else
                {
                    EmitFunctionCall(depth, type, arglist, procNode, funcCall, false, bnode);
                }
                return procNode;
            }
            else
            {
                if (procCallNode.IsConstructor &&
                    (globalClassIndex != Constants.kInvalidIndex) &&
                    (globalProcIndex != Constants.kInvalidIndex) &&
                    (globalClassIndex == inferedType.UID))
                {
                    ProcedureNode contextProcNode = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex];
                    if (contextProcNode.IsConstructor &&
                        string.Equals(contextProcNode.Name, procCallNode.Name) &&
                        contextProcNode.RuntimeIndex == procCallNode.RuntimeIndex)
                    {
                        string message = String.Format(ProtoCore.Properties.Resources.kCallingConstructorInConstructor, procName);
                        buildStatus.LogWarning(WarningID.kCallingConstructorInConstructor, message, core.CurrentDSFileName, node.line, node.col, graphNode);
                        inferedType.UID = (int)PrimitiveType.kTypeNull;
                        EmitPushNull();
                        return procCallNode;
                    }
                }

                inferedType = procCallNode.ReturnType;

                // Get the dot call procedure
                if (isConstructor || isStaticCall)
                {
                    bool isGetter = CoreUtils.IsGetter(procName);
                    EmitFunctionCall(depth, procCallNode.ClassID, arglist, procCallNode, funcCall, isGetter, bnode);
                }
                else
                {
                    var procNode = CoreUtils.GetFunctionByName(Constants.kDotMethodName, codeBlock);
                    if (CoreUtils.IsSetter(procName))
                    {
                        EmitFunctionCall(depth, type, arglist, procNode, funcCall);
                    }
                    // Do not emit breakpoint at getters only - pratapa
                    else if (CoreUtils.IsGetter(procName))
                    {
                        EmitFunctionCall(depth, type, arglist, procNode, funcCall, true);
                    }
                    else
                    {
                        EmitFunctionCall(depth, type, arglist, procNode, funcCall, false, bnode);
                    }

                    if (dotCallType.UID != (int)PrimitiveType.kTypeVar)
                    {
                        inferedType.UID = dotCallType.UID;
                    }
                }

                if (isConstructor)
                {
                    foreach (AssociativeNode paramNode in dotCall.FunctionCall.FormalArguments)
                    {
                        // Get the lhs symbol list
                        ProtoCore.Type ltype = new ProtoCore.Type();
                        ltype.UID = globalClassIndex;
                        UpdateNodeRef argNodeRef = new UpdateNodeRef();
                        DFSGetSymbolList(paramNode, ref ltype, argNodeRef);

                        if (null != graphNode)
                        {
                            if (argNodeRef.nodeList.Count > 0)
                            {
                                graphNode.updatedArguments.Add(argNodeRef);
                            }
                        }
                    }

                    graphNode.firstProc = procCallNode;
                }
                
                return procCallNode;
            }
        }
예제 #33
0
        private void HandlePointerList(BinaryExpressionNode bnode)
        {
            // All associative code is SSA'd and we want to keep track of the original identifier nodes of an identifier list:
            //      i.e. x.y.z
            // These identifiers will be used to populate the real graph nodes dependencies
            if (bnode.isSSAPointerAssignment)
            {
                Validity.Assert(null != ssaPointerStack);

                if (bnode.IsFirstIdentListNode)
                {
                    ssaPointerStack.Push(new List<AssociativeNode>());
                }

                if (bnode.RightNode is IdentifierNode)
                {
                    ssaPointerStack.Peek().Add(bnode.RightNode);
                }
                else if (bnode.RightNode is IdentifierListNode)
                {
                    ssaPointerStack.Peek().Add((bnode.RightNode as IdentifierListNode).RightNode);
                }
                else if (bnode.RightNode is FunctionDotCallNode)
                {
                    FunctionDotCallNode dotcall = bnode.RightNode as FunctionDotCallNode;
                    Validity.Assert(dotcall.FunctionCall.Function is IdentifierNode);

                    string className = dotcall.DotCall.FormalArguments[0].Name;
                    string fullyQualifiedClassName = string.Empty;
                    bool isClassName = core.ClassTable.TryGetFullyQualifiedName(className, out fullyQualifiedClassName);

                    if (ProtoCore.Utils.CoreUtils.IsGetterSetter(dotcall.FunctionCall.Function.Name))
                    {
                        //string className = dotcall.DotCall.FormalArguments[0].Name;
                        if (isClassName)
                        {
                            ssaPointerStack.Peek().Add(dotcall.DotCall.FormalArguments[0]);
                        }

                        // This function is an internal getter or setter, store the identifier node
                        ssaPointerStack.Peek().Add(dotcall.FunctionCall.Function);
                    }
                    else
                    {
                        bool isConstructorCall = isClassName ? true : false;
                        if (!isConstructorCall)
                        {
                            // This function is a member function, store the functioncall node
                            ssaPointerStack.Peek().Add(dotcall.FunctionCall);
                        }
                    }
                }
                else if (bnode.RightNode is FunctionCallNode)
                {
                    FunctionCallNode fcall = bnode.RightNode as FunctionCallNode;
                    Validity.Assert(fcall.Function is IdentifierNode);
                    ssaPointerStack.Peek().Add(fcall.Function);
                }
                else
                {
                    Validity.Assert(false);
                }
            }
        }
예제 #34
0
        private void SSAIdentList(AssociativeNode node, ref Stack<AssociativeNode> ssaStack, ref List<AssociativeNode> astlist)
        {
            if (node is IdentifierNode)
            {
                IdentifierNode ident = node as IdentifierNode;
                if (null == ident.ArrayDimensions)
                {
                    // Build the temp pointer
                    BinaryExpressionNode bnode = new BinaryExpressionNode();
                    bnode.Optr = ProtoCore.DSASM.Operator.assign;
                    bnode.isSSAAssignment = true;
                    bnode.isSSAPointerAssignment = true;
                    bnode.IsFirstIdentListNode = true;

                    // Left node
                    var identNode =AstFactory.BuildIdentifier(ProtoCore.Utils.CoreUtils.BuildSSATemp(core));
                    identNode.ReplicationGuides = GetReplicationGuides(ident);
                    identNode.AtLevel = ident.AtLevel;

                    bnode.LeftNode = identNode;

                    // Right node
                    bnode.RightNode = ident;

                    astlist.Add(bnode);
                    ssaStack.Push(bnode);
                }
                else
                {
                    EmitSSAArrayIndex(ident, ssaStack, ref astlist, true);
                    (astlist[0] as BinaryExpressionNode).IsFirstIdentListNode = true;
                }

            }
            else if (node is ExprListNode)
            {
                //ExprListNode exprList = node as ExprListNode;
                DFSEmitSSA_AST(node, ssaStack, ref astlist);
            }
            else if (node is FunctionCallNode)
            {
                FunctionCallNode fcall = node as FunctionCallNode;
                if (null == fcall.ArrayDimensions)
                {
                    // Build the temp pointer
                    BinaryExpressionNode bnode = new BinaryExpressionNode();
                    bnode.Optr = ProtoCore.DSASM.Operator.assign;
                    bnode.isSSAAssignment = true;
                    bnode.isSSAPointerAssignment = true;
                    bnode.IsFirstIdentListNode = true;

                    // Left node
                    var identNode =AstFactory.BuildIdentifier(ProtoCore.Utils.CoreUtils.BuildSSATemp(core));
                    identNode.ReplicationGuides = fcall.ReplicationGuides;
                    identNode.AtLevel = fcall.AtLevel;
                    bnode.LeftNode = identNode;

                    // Right node
                    bnode.RightNode = fcall;


                    astlist.Add(bnode);
                    ssaStack.Push(bnode);
                }
                else
                {
                    EmitSSAArrayIndex(fcall, ssaStack, ref astlist, true);
                    (astlist[0] as BinaryExpressionNode).IsFirstIdentListNode = true;
                }

            }
            else if (node is IdentifierListNode)
            {
                IdentifierListNode identList = node as IdentifierListNode;

                // Build the rhs identifier list containing the temp pointer
                IdentifierListNode rhsIdentList = new IdentifierListNode();
                rhsIdentList.Optr = Operator.dot;

                bool isLeftNodeExprList = false;

                // Check if identlist matches any namesapce
                bool resolvedCall = false;
                string[] classNames = ProtoCore.Utils.CoreUtils.GetResolvedClassName(core.ClassTable, identList);
                if (classNames.Length == 1)
                {
                    //
                    // The identlist is a class name and should not be SSA'd
                    // such as:
                    //  p = Obj.Create()
                    //
                    var leftNode =AstFactory.BuildIdentifier(classNames[0]);
                    rhsIdentList.LeftNode = leftNode;
                    ProtoCore.Utils.CoreUtils.CopyDebugData(leftNode, node);
                    resolvedCall = true;
                }
                else if (classNames.Length > 0)
                {
                    // There is a resolution conflict
                    // identList resolved to multiple classes 

                    // TODO Jun: Move this warning handler to after the SSA transform
                    // http://adsk-oss.myjetbrains.com/youtrack/issue/MAGN-5221
                    buildStatus.LogSymbolConflictWarning(identList.LeftNode.ToString(), classNames);
                    rhsIdentList = identList;
                    resolvedCall = true;
                }
                else
                {
                    // identList unresolved
                    // Continue to transform this identlist into SSA
                    isLeftNodeExprList = identList.LeftNode is ExprListNode;
                    
                    // Recursively traversse the left of the ident list
                    SSAIdentList(identList.LeftNode, ref ssaStack, ref astlist);

                    AssociativeNode lhsNode = ssaStack.Pop();
                    if (lhsNode is BinaryExpressionNode)
                    {
                        rhsIdentList.LeftNode = (lhsNode as BinaryExpressionNode).LeftNode;
                    }
                    else
                    {
                        rhsIdentList.LeftNode = lhsNode;
                    }
                }

                ArrayNode arrayDimension = null;

                AssociativeNode rnode = null;
                if (identList.RightNode is IdentifierNode)
                {
                    IdentifierNode identNode = identList.RightNode as IdentifierNode;
                    arrayDimension = identNode.ArrayDimensions;
                    rnode = identNode;
                }
                else if (identList.RightNode is FunctionCallNode)
                {
                    FunctionCallNode fcNode = new FunctionCallNode(identList.RightNode as FunctionCallNode);
                    arrayDimension = fcNode.ArrayDimensions;

                    List<AssociativeNode> astlistArgs = new List<AssociativeNode>();
                    for (int idx = 0; idx < fcNode.FormalArguments.Count; idx++)
                    {
                        AssociativeNode arg = fcNode.FormalArguments[idx];
                        var replicationGuides = GetReplicationGuides(arg);
                        if (replicationGuides == null)
                        {
                            replicationGuides = new List<AssociativeNode> { };
                        }
                        else
                        {
                            RemoveReplicationGuides(arg);
                        }

                        var atLevel = GetAtLevel(arg);
                        if (atLevel != null)
                        {
                            RemoveAtLevel(arg);
                        }

                        DFSEmitSSA_AST(arg, ssaStack, ref astlistArgs);

                        var argNode = ssaStack.Pop();
                        var argBinaryExpr = argNode as BinaryExpressionNode;
                        if (argBinaryExpr != null)
                        {
                            var newArgNode = NodeUtils.Clone(argBinaryExpr.LeftNode) as IdentifierNode;
                            newArgNode.ReplicationGuides = replicationGuides;
                            newArgNode.AtLevel = atLevel;
                            fcNode.FormalArguments[idx] = newArgNode;
                        }
                        else
                        {
                            fcNode.FormalArguments[idx] = argNode;
                        }
                        astlist.AddRange(astlistArgs);
                        astlistArgs.Clear();
                    }

                    astlist.AddRange(astlistArgs);
                    rnode = fcNode;
                }
                else
                {
                    Validity.Assert(false);
                }

                Validity.Assert(null != rnode);
                rhsIdentList.RightNode = rnode;

                if (null == arrayDimension)
                {
                    // New SSA expr for the current dot call
                    string ssatemp = ProtoCore.Utils.CoreUtils.BuildSSATemp(core);
                    var tmpIdent =AstFactory.BuildIdentifier(ssatemp);
                    BinaryExpressionNode bnode = new BinaryExpressionNode(tmpIdent, rhsIdentList, Operator.assign);
                    bnode.isSSAPointerAssignment = true;
                    if (resolvedCall || isLeftNodeExprList )
                    {
                        bnode.IsFirstIdentListNode = true;
                    }
                    astlist.Add(bnode);
                    ssaStack.Push(bnode);
                }
                else
                {
                    List<AssociativeNode> ssaAstList = new List<AssociativeNode>();
                    EmitSSAArrayIndex(rhsIdentList, ssaStack, ref ssaAstList, true);
                    if (resolvedCall || isLeftNodeExprList)
                    {
                        (ssaAstList[0] as BinaryExpressionNode).IsFirstIdentListNode = true;
                    }
                    astlist.AddRange(ssaAstList);
                }
            }
        }
예제 #35
0
        private void TraverseDotCallArguments(FunctionCallNode funcCall, 
                                              FunctionDotCallNode dotCall,
                                              ProcedureNode procCallNode,
                                              List<ProtoCore.Type> arglist,
                                              string procName,
                                              int classIndex,
                                              string className,
                                              bool isStaticCall,
                                              bool isConstructor,
                                              GraphNode graphNode,
                                              ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass,
                                              BinaryExpressionNode bnode)
        {
            // Update graph dependencies
            if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier && graphNode != null)
            {
                if (isStaticCall)
                {
                    Validity.Assert(classIndex != Constants.kInvalidIndex);
                    Validity.Assert(!string.IsNullOrEmpty(className));

                    SymbolNode classSymbol = new SymbolNode();
                    classSymbol.name = className;
                    classSymbol.classScope = classIndex;
                    PushSymbolAsDependent(classSymbol, graphNode);
                }
            }

            int funtionArgCount = 0;
            for (int n = 0; n < funcCall.FormalArguments.Count; ++n)
            {
                if (isStaticCall || isConstructor)
                {
                    if (n != Constants.kDotArgIndexArrayArgs)
                    {
                        continue;
                    }
                }

                AssociativeNode paramNode = funcCall.FormalArguments[n];
                ProtoCore.Type paramType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0);

                emitReplicationGuide = false;

                // If it's a binary node then continue type check, otherwise 
                // disable type check and just take the type of paramNode itself
                enforceTypeCheck = !(paramNode is BinaryExpressionNode);

                if (ProtoCore.DSASM.Constants.kDotArgIndexPtr == n)
                {
                    // Traversing the first arg (the LHS pointer/Static instanct/Constructor
                    
                    // Replication guides only allowed on method, e.g.,
                    // 
                    //    x = p<1>.f({1,2}<2>); 
                    //
                    // But not on getter, e.g.,
                    // 
                    //    c = a<1>.x<2>; 
                    if (!CoreUtils.IsGetterSetter(procName) && !isConstructor)
                    {
                        emitReplicationGuide = true;
                    }

                    DfsTraverse(paramNode, ref paramType, false, graphNode, subPass, bnode);
                }
                else if (ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs == n)
                {
                    // Traversing the actual arguments passed into the function 
                    // (not the dot function)
                    int defaultArgNumber = 0;

                    // If its null this is the second call in a chained dot
                    if (null != procCallNode)
                    {
                        defaultArgNumber = procCallNode.ArgumentInfos.Count - dotCall.FunctionCall.FormalArguments.Count;
                    }

                    // Enable graphnode dependencies if its a setter method
                    bool allowDependentState = null != graphNode ? graphNode.allowDependents : false;
                    if (CoreUtils.IsSetter(procName))
                    {
                        // If the arguments are not temporaries
                        ExprListNode exprList = paramNode as ExprListNode;
                        Validity.Assert(1 == exprList.Exprs.Count);

                        string varname = string.Empty;
                        if (exprList.Exprs[0] is IdentifierNode)
                        {
                            varname = (exprList.Exprs[0] as IdentifierNode).Name;

                            if (!CoreUtils.IsAutoGeneratedVar(varname))
                            {
                                graphNode.allowDependents = true;
                            }
                            else if (CoreUtils.IsSSATemp(varname) && core.Options.GenerateSSA)
                            {
                                graphNode.allowDependents = true;
                            }
                        }
                        else
                        {
                            graphNode.allowDependents = true;
                        }

                    }

                    emitReplicationGuide = true;

                    if (defaultArgNumber > 0)
                    {
                        ExprListNode exprList = paramNode as ExprListNode;

                        if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier)
                        {
                            for (int i = 0; i < defaultArgNumber; i++)
                            {
                                exprList.Exprs.Add(new DefaultArgNode());
                            }

                        }

                        if (!isStaticCall && !isConstructor)
                        {
                            DfsTraverse(paramNode, ref paramType, false, graphNode, subPass);
                            funtionArgCount = exprList.Exprs.Count;
                        }
                        else
                        {
                            foreach (AssociativeNode exprListNode in exprList.Exprs)
                            {
                                bool repGuideState = emitReplicationGuide;
                                if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier)
                                {
                                    emitReplicationGuide = false;
                                }

                                DfsTraverse(exprListNode, ref paramType, false, graphNode, subPass, bnode);
                                emitReplicationGuide = repGuideState;

                                arglist.Add(paramType);
                            }
                        }
                    }
                    else
                    {
                        ExprListNode exprList = paramNode as ExprListNode;

                        // Comment Jun: This is a getter/setter or a an auto-generated thisarg function...
                        // ...add the dynamic sv that will be resolved as a pointer at runtime
                        if (!isStaticCall && !isConstructor)
                        {
                            // TODO Jun: pls get rid of subPass checking outside the core travesal
                            if (ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone == subPass)
                            {
                                exprList.Exprs.Insert(0, new DynamicNode());
                            }
                        }

                        if (exprList.Exprs.Count > 0)
                        {
                            foreach (AssociativeNode exprListNode in exprList.Exprs)
                            {
                                bool repGuideState = emitReplicationGuide;
                                if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier)
                                {
                                    emitReplicationGuide = false;
                                }

                                DfsTraverse(exprListNode, ref paramType, false, graphNode, subPass, bnode);
                                emitReplicationGuide = repGuideState;

                                arglist.Add(paramType);
                            }

                            if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier &&
                                !isStaticCall &&
                                !isConstructor)
                            {
                                EmitInstrConsole(ProtoCore.DSASM.kw.alloca, exprList.Exprs.Count.ToString());
                                EmitPopArray(exprList.Exprs.Count);

                                if (exprList.ArrayDimensions != null)
                                {
                                    int dimensions = DfsEmitArrayIndexHeap(exprList.ArrayDimensions, graphNode);
                                    EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, dimensions.ToString() + "[dim]");
                                    EmitPushArrayIndex(dimensions);
                                }
                            }
                        }
                        else
                        {
                            if (!isStaticCall && !isConstructor)
                            {
                                if (exprList != null)
                                {
                                    bool emitReplicationGuideState = emitReplicationGuide;
                                    emitReplicationGuide = false;
                                    DfsTraverse(paramNode, ref paramType, false, graphNode, subPass);
                                    emitReplicationGuide = emitReplicationGuideState;
                                }
                                else
                                {
                                    DfsTraverse(paramNode, ref paramType, false, graphNode, subPass);
                                }
                            }
                        }

                        funtionArgCount = exprList.Exprs.Count;
                    }

                    emitReplicationGuide = false;

                    // Restore the state only if it is a setter method
                    if (ProtoCore.Utils.CoreUtils.IsSetter(procName))
                    {
                        graphNode.allowDependents = allowDependentState;
                    }
                }
                else if (ProtoCore.DSASM.Constants.kDotArgIndexArgCount == n)
                {
                    IntNode argNumNode = new IntNode(funtionArgCount);
                    DfsTraverse(argNumNode, ref paramType, false, graphNode, subPass);
                }
                else
                {
                    DfsTraverse(paramNode, ref paramType, false, graphNode, subPass);
                }

                emitReplicationGuide = false;
                enforceTypeCheck = true;

                if (!isStaticCall || !isConstructor)
                {
                    arglist.Add(paramType);
                }
            } 
        }
예제 #36
0
        /// <summary>
        /// This function applies SSA tranform to an array indexed identifier or identifier list
        /// 
        /// The transform applies as such:
        ///     i = 0
        ///     j = 1
        ///     x = a[i][j]
        ///     
        ///     t0 = a
        ///     t1 = i
        ///     t2 = t0[t1]
        ///     t3 = j
        ///     t4 = t2[t3]
        ///     x = t4
        /// 
        /// </summary>
        /// <param name="idendNode"></param>
        /// <param name="ssaStack"></param>
        /// <param name="astlist"></param>
        private void EmitSSAArrayIndex(AssociativeNode node, Stack<AssociativeNode> ssaStack, ref List<AssociativeNode> astlist, bool isSSAPointerAssignment = false)
        {
            //
            // Build the first SSA binary assignment of the identifier without its indexing
            //  x = a[i][j] -> t0 = a
            //
            BinaryExpressionNode bnode = new BinaryExpressionNode();
            bnode.Optr = ProtoCore.DSASM.Operator.assign;

            // Left node
            string ssaTempName = ProtoCore.Utils.CoreUtils.BuildSSATemp(core);
            var tmpName =AstFactory.BuildIdentifier(ssaTempName);
            bnode.LeftNode = tmpName;
            bnode.isSSAAssignment = true;
            bnode.isSSAPointerAssignment = isSSAPointerAssignment;
            bnode.isSSAFirstAssignment = true;

            IdentifierNode identNode = null;
            ArrayNode arrayDimensions = null;
            string firstVarName = string.Empty;
            if (node is IdentifierNode)
            {
                identNode = node as IdentifierNode;

                // Right node - Array indexing will be applied to this new identifier
                firstVarName = identNode.Name;
                bnode.RightNode =AstFactory.BuildIdentifier(firstVarName);
                ProtoCore.Utils.CoreUtils.CopyDebugData(bnode.RightNode, node);

                // Get the array dimensions of this node
                arrayDimensions = identNode.ArrayDimensions;


                // Associate the first pointer with each SSA temp
                // It is acceptable to store firstVar even if it is not a pointer as ResolveFinalNodeRefs() will just ignore this entry 
                // if this ssa temp is not treated as a pointer inside the function
                if (!ssaTempToFirstPointerMap.ContainsKey(ssaTempName))
                {
                    ssaTempToFirstPointerMap.Add(ssaTempName, firstVarName);
                }
            }
            else if (node is FunctionCallNode)
            {
                FunctionCallNode fcall = node as FunctionCallNode;
                Validity.Assert(fcall.Function is IdentifierNode);
                identNode = fcall.Function as IdentifierNode;

                // Assign the function array and guide properties to the new ident node
                identNode.ArrayDimensions = fcall.ArrayDimensions;
                identNode.ReplicationGuides = fcall.ReplicationGuides;
                identNode.AtLevel = fcall.AtLevel;

                // Right node - Remove the function array indexing.
                // The array indexing to this function will be applied downstream 
                fcall.ArrayDimensions = null;
                bnode.RightNode = fcall;
                //ProtoCore.Utils.CoreUtils.CopyDebugData(bnode.RightNode, node);

                // Get the array dimensions of this node
                arrayDimensions = identNode.ArrayDimensions;
            }
            else if (node is IdentifierListNode)
            {
                // Apply array indexing to the right node of the ident list
                //      a = p.x[i] -> apply it to x
                IdentifierListNode identList = node as IdentifierListNode;
                AssociativeNode rhsNode = identList.RightNode;

                if (rhsNode is IdentifierNode)
                {
                    identNode = rhsNode as IdentifierNode;

                    // Replace the indexed identifier with a new ident with the same name
                    //      i.e. replace x[i] with x
                    AssociativeNode nonIndexedIdent =AstFactory.BuildIdentifier(identNode.Name);
                    identList.RightNode = nonIndexedIdent;

                    // Get the array dimensions of this node
                    arrayDimensions = identNode.ArrayDimensions;
                }
                else if (rhsNode is FunctionCallNode)
                {
                    FunctionCallNode fcall = rhsNode as FunctionCallNode;
                    identNode = fcall.Function as IdentifierNode;

                    AssociativeNode newCall = AstFactory.BuildFunctionCall(identNode.Name, fcall.FormalArguments);

                    // Assign the function array and guide properties to the new ident node
                    identNode.ArrayDimensions = fcall.ArrayDimensions;
                    identNode.ReplicationGuides = fcall.ReplicationGuides;
                    identNode.AtLevel = fcall.AtLevel;

                    identList.RightNode = newCall;

                    // Get the array dimensions of this node
                    arrayDimensions = identNode.ArrayDimensions;
                }
                else
                {
                    Validity.Assert(false, "This token is not indexable");
                }

                // Right node
                bnode.RightNode = identList;
                //ProtoCore.Utils.CoreUtils.CopyDebugData(bnode.RightNode, node);

                bnode.isSSAPointerAssignment = true;
            }
            else if (node is GroupExpressionNode)
            {
                GroupExpressionNode groupExpr = node as GroupExpressionNode;
                DFSEmitSSA_AST(groupExpr.Expression, ssaStack, ref astlist);

                arrayDimensions = groupExpr.ArrayDimensions;
            }
            else
            {
                Validity.Assert(false);
            }

            // Push the first SSA stmt
            astlist.Add(bnode);
            ssaStack.Push(bnode);

            // Traverse the array index
            //      t1 = i
            List<AssociativeNode> arrayDimASTList = new List<AssociativeNode>();
            DFSEmitSSA_AST(arrayDimensions.Expr, ssaStack, ref arrayDimASTList);
            astlist.AddRange(arrayDimASTList);
            arrayDimASTList.Clear();

            //
            // Build the indexing statement
            //      t2 = t0[t1]
            BinaryExpressionNode indexedStmt = new BinaryExpressionNode();
            indexedStmt.Optr = ProtoCore.DSASM.Operator.assign;


            // Build the left node of the indexing statement
#region SSA_INDEX_STMT_LEFT
            ssaTempName = ProtoCore.Utils.CoreUtils.BuildSSATemp(core);
            AssociativeNode tmpIdent =AstFactory.BuildIdentifier(ssaTempName);
            Validity.Assert(null != tmpIdent);
            indexedStmt.LeftNode = tmpIdent;
            //ProtoCore.Utils.CoreUtils.CopyDebugData(bnode, node);



            // Associate the first pointer with each SSA temp
            // It is acceptable to store firstVar even if it is not a pointer as ResolveFinalNodeRefs() will just ignore this entry 
            // if this ssa temp is not treated as a pointer inside the function
            if (!string.IsNullOrEmpty(firstVarName))
            {
                if (!ssaTempToFirstPointerMap.ContainsKey(ssaTempName))
                {
                    ssaTempToFirstPointerMap.Add(ssaTempName, firstVarName);
                }
            }

#endregion

            // Build the right node of the indexing statement
#region SSA_INDEX_STMT_RIGHT
            
            ArrayNode arrayNode = null;

            // pop off the dimension
            AssociativeNode dimensionNode = ssaStack.Pop();
            if (dimensionNode is BinaryExpressionNode)
            {
                arrayNode = new ArrayNode((dimensionNode as BinaryExpressionNode).LeftNode, null);
            }
            else
            {
                arrayNode = new ArrayNode(dimensionNode, null);
            }

            // pop off the prev SSA variable
            AssociativeNode prevSSAStmt = ssaStack.Pop();

            // Assign the curent dimension to the prev SSA variable
            Validity.Assert(prevSSAStmt is BinaryExpressionNode);
            AssociativeNode rhsIdent =AstFactory.BuildIdentifier((prevSSAStmt as BinaryExpressionNode).LeftNode.Name);
            (rhsIdent as IdentifierNode).ArrayDimensions = arrayNode;

            // Right node of the indexing statement
            indexedStmt.RightNode = rhsIdent;

            astlist.Add(indexedStmt);
            ssaStack.Push(indexedStmt);


            // Traverse the next dimension
            //      [j]
            if (null != arrayDimensions.Type)
            {
                DFSEmitSSA_AST(arrayDimensions.Type, ssaStack, ref arrayDimASTList);
                astlist.AddRange(arrayDimASTList);
                arrayDimASTList.Clear();
            }
#endregion
        }