Example #1
0
        protected bool DfsEmitIdentList(
            Node pNode, 
            Node parentNode, 
            int contextClassScope, 
            ref ProtoCore.Type lefttype,
            ref int depth, 
            ref ProtoCore.Type finalType, 
            bool isLeftidentList, 
            ref bool isFirstIdent, 
            ref bool isMethodCallPresent,
            ref ProtoCore.DSASM.SymbolNode firstSymbol,
            ProtoCore.AssociativeGraph.GraphNode graphNode = null,
            ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone,
            ProtoCore.AST.Node binaryExpNode = null)
        {
            dynamic node = pNode;
            if (node is ProtoCore.AST.ImperativeAST.IdentifierListNode || node is ProtoCore.AST.AssociativeAST.IdentifierListNode)
            {
                dynamic bnode = node;
                if (ProtoCore.DSASM.Operator.dot != bnode.Optr)
                {
                    string message = "The left hand side of an operation can only contain an indirection operator '.' (48D67B9B)";
                    buildStatus.LogSemanticError(message, core.CurrentDSFileName, bnode.line, bnode.col);
                    throw new BuildHaltException(message);
                }

                DfsEmitIdentList(bnode.LeftNode, bnode, contextClassScope, ref lefttype, ref depth, ref finalType, isLeftidentList, ref isFirstIdent, ref isMethodCallPresent, ref firstSymbol, graphNode, subPass);

                if (lefttype.rank > 0)
                {
                    lefttype.UID = finalType.UID = (int)PrimitiveType.kTypeNull;
                    EmitPushNull();
                    return false;
                }
                node = bnode.RightNode;
            }

            if (node is ProtoCore.AST.ImperativeAST.GroupExpressionNode)
            {
                ProtoCore.AST.ImperativeAST.ArrayNode array = node.ArrayDimensions;
                node = node.Expression;
                node.ArrayDimensions = array;
            }
            else if (node is ProtoCore.AST.AssociativeAST.GroupExpressionNode)
            {
                ProtoCore.AST.AssociativeAST.ArrayNode array = node.ArrayDimensions;
                List<ProtoCore.AST.AssociativeAST.AssociativeNode> replicationGuides = node.ReplicationGuides;

                node = node.Expression;
                node.ArrayDimensions = array;
                node.ReplicationGuides = replicationGuides;
            }

            if (node is ProtoCore.AST.ImperativeAST.IdentifierNode || node is ProtoCore.AST.AssociativeAST.IdentifierNode)
            {
                dynamic identnode = node;

                int ci = core.ClassTable.IndexOf(identnode.Value);
                if (ProtoCore.DSASM.Constants.kInvalidIndex != ci)
                {
                    finalType.UID = lefttype.UID = ci;
                }
                else if (identnode.Value == ProtoCore.DSDefinitions.Keyword.This)
                {
                    finalType.UID = lefttype.UID = contextClassScope;
                    EmitInstrConsole(ProtoCore.DSASM.kw.push, 0 + "[dim]");
                    StackValue opdim = StackValue.BuildArrayDimension(0);
                    EmitPush(opdim);
                    EmitThisPointerNode();
                    depth++;
                    return true;
                }
                else
                {
                    ProtoCore.DSASM.SymbolNode symbolnode = null;
                    bool isAllocated = false;
                    bool isAccessible = false;
                    if (lefttype.UID != -1)
                    {
                        isAllocated = VerifyAllocation(identnode.Value, lefttype.UID, globalProcIndex, out symbolnode, out isAccessible);
                    }
                    else
                    {
                        isAllocated = VerifyAllocation(identnode.Value, contextClassScope, globalProcIndex, out symbolnode, out isAccessible);
                        Validity.Assert(null == firstSymbol);
                        firstSymbol = symbolnode;
                    }

                    bool callOnClass = false;
                    string leftClassName = "";
                    int leftci = Constants.kInvalidIndex;

                    if (pNode is ProtoCore.AST.ImperativeAST.IdentifierListNode ||
                        pNode is ProtoCore.AST.AssociativeAST.IdentifierListNode)
                    {
                        dynamic leftnode = ((dynamic)pNode).LeftNode;
                        if (leftnode != null && 
                            (leftnode is ProtoCore.AST.ImperativeAST.IdentifierNode ||
                            leftnode is ProtoCore.AST.AssociativeAST.IdentifierNode))
                        {
                            leftClassName = leftnode.Name;
                            leftci = core.ClassTable.IndexOf(leftClassName);
                            if (leftci != ProtoCore.DSASM.Constants.kInvalidIndex)
                            {
                                callOnClass = true;

                                EmitInstrConsole(ProtoCore.DSASM.kw.push, 0 + "[dim]");
                                StackValue dynamicOpdim = StackValue.BuildArrayDimension(0);
                                EmitPush(dynamicOpdim);

                                EmitInstrConsole(ProtoCore.DSASM.kw.pushm, leftClassName);
                                StackValue classOp = StackValue.BuildClassIndex(leftci);
                                EmitPushm(classOp, globalClassIndex, codeBlock.codeBlockId);

                                depth = depth + 1;
                            }
                        }
                    }

                    if (null == symbolnode)    //unbound identifier
                    {
                        if (isAllocated && !isAccessible)
                        {
                            string message = String.Format(Resources.kPropertyIsInaccessible, identnode.Value);
                            buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode);
                            lefttype.UID = finalType.UID = (int)PrimitiveType.kTypeNull;
                            EmitPushNull();
                            return false;
                        }
                        else
                        {
                            string message = String.Format(Resources.kUnboundIdentifierMsg, identnode.Value);
                            var unboundSymbol = new SymbolNode
                            {
                                name = identnode.Value
                            };
                            buildStatus.LogUnboundVariableWarning(unboundSymbol, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode);
                        }

                        if (depth == 0)
                        {
                            lefttype.UID = finalType.UID = (int)PrimitiveType.kTypeNull;
                            EmitPushNull();
                            depth = 1;
                            return false;
                        }
                        else
                        {
                            DSASM.DyanmicVariableNode dynamicVariableNode = new DSASM.DyanmicVariableNode(identnode.Value, globalProcIndex, globalClassIndex);
                            core.DynamicVariableTable.variableTable.Add(dynamicVariableNode);
                            int dim = 0;
                            if (null != identnode.ArrayDimensions)
                            {
                                dim = DfsEmitArrayIndexHeap(identnode.ArrayDimensions, graphNode);
                            }
                            EmitInstrConsole(ProtoCore.DSASM.kw.push, dim + "[dim]");
                            StackValue dynamicOpdim = StackValue.BuildArrayDimension(dim);
                            EmitPush(dynamicOpdim);

                            EmitInstrConsole(ProtoCore.DSASM.kw.pushm, identnode.Value + "[dynamic]");
                            StackValue dynamicOp = StackValue.BuildDynamic(core.DynamicVariableTable.variableTable.Count - 1);
                            EmitPushm(dynamicOp, symbolnode == null ? globalClassIndex : symbolnode.classScope, DSASM.Constants.kInvalidIndex);

                            lefttype.UID = finalType.UID = (int)PrimitiveType.kTypeVar;
                            depth++;
                            return true;
                        }
                    }
                    else
                    {
                        if (callOnClass && !symbolnode.isStatic)
                        {
                            string procName = identnode.Name;
                            string property;
                            ProtoCore.DSASM.ProcedureNode staticProcCallNode = core.ClassTable.ClassNodes[leftci].GetFirstStaticFunctionBy(procName);

                            if (null != staticProcCallNode)
                            {
                                string message = String.Format(Resources.kMethodHasInvalidArguments, procName);
                                buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode);
                            }
                            else if (CoreUtils.TryGetPropertyName(procName, out property))
                            {
                                string message = String.Format(Resources.kPropertyIsInaccessible, property);
                                buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode);
                            }
                            else
                            {
                                string message = String.Format(Resources.kMethodIsInaccessible, procName);
                                buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode);
                            }

                            lefttype.UID = finalType.UID = (int)PrimitiveType.kTypeNull;
                            EmitPushNull();
                            return false;
                        }
                    }

                    //
                    // The graph node depends on the first identifier in this identifier list
                    // Where:
                    //      p = f(1);			        
                    //      px = p.x; // px dependent on p
                    //      p = f(2);
                    //
                    if (isFirstIdent && null != graphNode)
                    {
                        isFirstIdent = false;
                        //ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode();
                        //dependentNode.symbol = symbolnode;
                        //dependentNode.symbolList.Add(symbolnode);
                        //graphNode.PushDependent(dependentNode);
                    }
                    
                    /* Dont try to figure out the type at compile time if it is
                     * an array, it is just not reliable because each element in
                     * an array can have different types
                     */
                    if (!symbolnode.datatype.IsIndexable || symbolnode.datatype.rank < 0)
                        lefttype = symbolnode.datatype;

                    int dimensions = 0;

                    // Get the symbols' table index
                    int runtimeIndex = symbolnode.runtimeTableIndex;

                    ProtoCore.DSASM.AddressType operandType = ProtoCore.DSASM.AddressType.Pointer;

                    if (null != identnode.ArrayDimensions)
                    {
                        dimensions = DfsEmitArrayIndexHeap(identnode.ArrayDimensions, graphNode);
                        operandType = ProtoCore.DSASM.AddressType.ArrayPointer;
                    }

                    if (lefttype.rank >= 0)
                    {
                        lefttype.rank -= dimensions;
                        if (lefttype.rank < 0)
                        {
                            lefttype.rank = 0;
                        }
                    }

                    if (0 == depth || (symbolnode != null && symbolnode.isStatic))
                    {
                        if (ProtoCore.DSASM.Constants.kGlobalScope == symbolnode.functionIndex
                            && ProtoCore.DSASM.Constants.kInvalidIndex != symbolnode.classScope)
                        {
                            // member var
                            operandType = symbolnode.isStatic ? ProtoCore.DSASM.AddressType.StaticMemVarIndex : ProtoCore.DSASM.AddressType.MemVarIndex;
                        }
                        else
                        {
                            operandType = ProtoCore.DSASM.AddressType.VarIndex;
                        }
                    }

                    StackValue op = new StackValue();
                    op.optype = operandType;
                    op.opdata = symbolnode.symbolTableIndex;

                    // TODO Jun: Performance. 
                    // Is it faster to have a 'push' specific to arrays to prevent pushing dimension for push instruction?
                    EmitInstrConsole(ProtoCore.DSASM.kw.push, dimensions + "[dim]");
                    StackValue opdim = StackValue.BuildArrayDimension(dimensions);
                    EmitPush(opdim);

                    
                    if (isLeftidentList || depth == 0)
                    {
                        EmitInstrConsole(ProtoCore.DSASM.kw.pushm, identnode.Value);
                        EmitPushm(op, symbolnode == null ? globalClassIndex : symbolnode.classScope, runtimeIndex);
                    }
                    else
                    {
                        // change to dynamic call to facilitate update mechanism
                        DSASM.DyanmicVariableNode dynamicVariableNode = new DSASM.DyanmicVariableNode(identnode.Name, globalProcIndex, globalClassIndex);
                        core.DynamicVariableTable.variableTable.Add(dynamicVariableNode);
                        StackValue dynamicOp = StackValue.BuildDynamic(core.DynamicVariableTable.variableTable.Count - 1);
                        EmitInstrConsole(ProtoCore.DSASM.kw.pushm, identnode.Value + "[dynamic]");
                        EmitPushm(dynamicOp, symbolnode == null ? globalClassIndex : symbolnode.classScope, runtimeIndex);
                    }
                    depth = depth + 1;
                    finalType = lefttype;
                }
                return true;
            }
            else if (node is ProtoCore.AST.ImperativeAST.FunctionCallNode || node is ProtoCore.AST.AssociativeAST.FunctionCallNode)
            {
                // A function call must always track dependents
                bool allowDependents = true;
                if (null != graphNode)
                {
                    allowDependents = graphNode.allowDependents;
                    graphNode.allowDependents = true;
                }

                if (binaryExpNode != null)
                {
                    ProtoCore.Utils.NodeUtils.SetNodeLocation(node, binaryExpNode, binaryExpNode);
                }
                ProtoCore.DSASM.ProcedureNode procnode = TraverseFunctionCall(node, pNode, lefttype.UID, depth, ref finalType, graphNode, subPass, binaryExpNode);

                // Restore the graphNode dependent state
                if (null != graphNode)
                {
                    graphNode.allowDependents = allowDependents;
                }

                // This is the first non-auto generated procedure found in the identifier list
                if (null != procnode)
                {
                    if (!procnode.IsConstructor && !procnode.Name.Equals(ProtoCore.DSASM.Constants.kStaticPropertiesInitializer))
                    {
                        functionCallStack.Add(procnode);
                        if (null != graphNode)
                        {
                            graphNode.firstProcRefIndex = graphNode.dependentList.Count - 1;
                        }
                    }
                    isMethodCallPresent = !isMethodCallPresent && !procnode.IsAutoGenerated && !procnode.IsConstructor;
                }

                //finalType.UID = isBooleanOp ? (int)PrimitiveType.kTypeBool : finalType.UID;
                lefttype = finalType;
                depth = 1;
            }
            else
            {
                string message = "The left side of operator '.' must be an identifier. (B9AEA3A6)";
                buildStatus.LogSemanticError(message, core.CurrentDSFileName, node.line, node.col);
                throw new BuildHaltException(message);
            }
            return false;
        }
Example #2
0
        protected bool DfsEmitIdentList(
            Node pNode, 
            Node parentNode, 
            int contextClassScope, 
            ref Type lefttype,
            ref int depth, 
            ref Type finalType, 
            bool isLeftidentList, 
            AssociativeGraph.GraphNode graphNode = null,
            CompilerDefinitions.SubCompilePass subPass = CompilerDefinitions.SubCompilePass.None,
            Node binaryExpNode = null)
        {
            dynamic node = pNode;
            if (node is ProtoCore.AST.ImperativeAST.IdentifierListNode || node is ProtoCore.AST.AssociativeAST.IdentifierListNode)
            {
                dynamic bnode = node;
                if (ProtoCore.DSASM.Operator.dot != bnode.Optr)
                {
                    string message = "The left hand side of an operation can only contain an indirection operator '.' (48D67B9B)";
                    buildStatus.LogSemanticError(message, core.CurrentDSFileName, bnode.line, bnode.col);
                    throw new BuildHaltException(message);
                }

                DfsEmitIdentList(bnode.LeftNode, bnode, contextClassScope, ref lefttype, ref depth, ref finalType, isLeftidentList, graphNode, subPass);

                if (lefttype.rank > 0)
                {
                    lefttype.UID = finalType.UID = (int)PrimitiveType.Null;
                    EmitPushNull();
                    return false;
                }
                node = bnode.RightNode;
            }

            if (node is ProtoCore.AST.ImperativeAST.GroupExpressionNode)
            {
                ProtoCore.AST.ImperativeAST.ArrayNode array = node.ArrayDimensions;
                node = node.Expression;
                node.ArrayDimensions = array;
            }
            else if (node is ProtoCore.AST.AssociativeAST.GroupExpressionNode)
            {
                ProtoCore.AST.AssociativeAST.ArrayNode array = node.ArrayDimensions;
                List<ProtoCore.AST.AssociativeAST.AssociativeNode> replicationGuides = node.ReplicationGuides;

                node = node.Expression;
                node.ArrayDimensions = array;
                node.ReplicationGuides = replicationGuides;
            }

            if (node is ProtoCore.AST.ImperativeAST.IdentifierNode || node is ProtoCore.AST.AssociativeAST.IdentifierNode)
            {
                dynamic identnode = node;

                int ci = core.ClassTable.IndexOf(identnode.Value);
                if (Constants.kInvalidIndex != ci)
                {
                    finalType.UID = lefttype.UID = ci;
                }
                else if (identnode.Value == DSDefinitions.Keyword.This)
                {
                    finalType.UID = lefttype.UID = contextClassScope;
                    EmitThisPointerNode();
                    depth++;
                    return true;
                }
                else
                {
                    SymbolNode symbolnode = null;
                    bool isAllocated = false;
                    bool isAccessible = false;
                    if (lefttype.UID != -1)
                    {
                        isAllocated = VerifyAllocation(identnode.Value, lefttype.UID, globalProcIndex, out symbolnode, out isAccessible);
                    }
                    else
                    {
                        isAllocated = VerifyAllocation(identnode.Value, contextClassScope, globalProcIndex, out symbolnode, out isAccessible);
                    }

                    if (null == symbolnode)    //unbound identifier
                    {
                        if (isAllocated && !isAccessible)
                        {
                            string message = String.Format(Resources.kPropertyIsInaccessible, identnode.Value);
                            buildStatus.LogWarning(ProtoCore.BuildData.WarningID.AccessViolation, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode);
                            lefttype.UID = finalType.UID = (int)PrimitiveType.Null;
                            EmitPushNull();
                            return false;
                        }
                        else
                        {
                            string message = String.Format(Resources.kUnboundIdentifierMsg, identnode.Value);
                            var unboundSymbol = new SymbolNode
                            {
                                name = identnode.Value
                            };
                            buildStatus.LogUnboundVariableWarning(unboundSymbol, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode);
                        }

                        if (depth == 0)
                        {
                            lefttype.UID = finalType.UID = (int)PrimitiveType.Null;
                            EmitPushNull();
                            depth = 1;
                            return false;
                        }
                        else
                        {
                            DSASM.DyanmicVariableNode dynamicVariableNode = new DSASM.DyanmicVariableNode(identnode.Value, globalProcIndex, globalClassIndex);
                            core.DynamicVariableTable.variableTable.Add(dynamicVariableNode);
                            int dim = 0;
                            if (null != identnode.ArrayDimensions)
                            {
                                dim = DfsEmitArrayIndexHeap(identnode.ArrayDimensions, graphNode);
                            }


                            EmitInstrConsole(kw.pushm, identnode.Value + "[dynamic]");
                            StackValue dynamicOp = StackValue.BuildDynamic(core.DynamicVariableTable.variableTable.Count - 1);
                            EmitPushm(dynamicOp, symbolnode == null ? globalClassIndex : symbolnode.classScope, DSASM.Constants.kInvalidIndex);

                            if (dim > 0)
                            {
                                EmitPushDimensions(dim);
                                EmitLoadElement(null, Constants.kInvalidIndex);
                            }

                            lefttype.UID = finalType.UID = (int)PrimitiveType.Var;
                            depth++;
                            return true;
                        }
                    }

                    /* Dont try to figure out the type at compile time if it is
                     * an array, it is just not reliable because each element in
                     * an array can have different types
                     */
                    if (!symbolnode.datatype.IsIndexable || symbolnode.datatype.rank < 0)
                        lefttype = symbolnode.datatype;

                    int dimensions = 0;

                    // Get the symbols' table index
                    int runtimeIndex = symbolnode.runtimeTableIndex;

                    if (lefttype.rank >= 0)
                    {
                        lefttype.rank -= dimensions;
                        if (lefttype.rank < 0)
                        {
                            lefttype.rank = 0;
                        }
                    }

                    StackValue op = StackValue.Null;
                    if (0 == depth || (symbolnode != null && symbolnode.isStatic))
                    {
                        if (ProtoCore.DSASM.Constants.kGlobalScope == symbolnode.functionIndex
                            && ProtoCore.DSASM.Constants.kInvalidIndex != symbolnode.classScope)
                        {
                            // member var
                            if (symbolnode.isStatic)
                                op = StackValue.BuildStaticMemVarIndex(symbolnode.symbolTableIndex);
                            else
                                op = StackValue.BuildMemVarIndex(symbolnode.symbolTableIndex);
                        }
                        else
                        {
                            op = StackValue.BuildVarIndex(symbolnode.symbolTableIndex);
                        }
                    }

                    if (isLeftidentList || depth == 0)
                    {
                        EmitInstrConsole(kw.pushm, identnode.Value);
                        EmitPushm(op, symbolnode == null ? globalClassIndex : symbolnode.classScope, runtimeIndex);

                        if (null != identnode.ArrayDimensions)
                        {
                            dimensions = DfsEmitArrayIndexHeap(identnode.ArrayDimensions, graphNode);
                        }

                        if (dimensions > 0)
                        {
                            EmitPushDimensions(dimensions);
                            EmitLoadElement(symbolnode, runtimeIndex);
                        }
                    }
                    else
                    {
                        // change to dynamic call to facilitate update mechanism
                        DSASM.DyanmicVariableNode dynamicVariableNode = new DSASM.DyanmicVariableNode(identnode.Name, globalProcIndex, globalClassIndex);
                        core.DynamicVariableTable.variableTable.Add(dynamicVariableNode);
                        StackValue dynamicOp = StackValue.BuildDynamic(core.DynamicVariableTable.variableTable.Count - 1);
                        EmitInstrConsole(ProtoCore.DSASM.kw.pushm, identnode.Value + "[dynamic]");
                        EmitPushm(dynamicOp, symbolnode == null ? globalClassIndex : symbolnode.classScope, runtimeIndex);

                        if (null != identnode.ArrayDimensions)
                        {
                            dimensions = DfsEmitArrayIndexHeap(identnode.ArrayDimensions, graphNode);
                        }

                        if (dimensions > 0)
                        {
                            EmitPushDimensions(dimensions);
                            EmitLoadElement(null, Constants.kInvalidIndex);
                        }
                    }
                    depth = depth + 1;
                    finalType = lefttype;
                }
                return true;
            }
            else if (node is ProtoCore.AST.ImperativeAST.FunctionCallNode || node is ProtoCore.AST.AssociativeAST.FunctionCallNode)
            {
                // A function call must always track dependents
                bool allowDependents = true;
                if (null != graphNode)
                {
                    allowDependents = graphNode.allowDependents;
                    graphNode.allowDependents = true;
                }

                if (binaryExpNode != null)
                {
                    ProtoCore.Utils.NodeUtils.SetNodeLocation(node, binaryExpNode, binaryExpNode);
                }
                ProtoCore.DSASM.ProcedureNode procnode = TraverseFunctionCall(node, pNode, lefttype.UID, depth, ref finalType, graphNode, subPass, binaryExpNode);

                // Restore the graphNode dependent state
                if (null != graphNode)
                {
                    graphNode.allowDependents = allowDependents;
                }

                // This is the first non-auto generated procedure found in the identifier list
                if (null != procnode)
                {
                    if (!procnode.IsConstructor)
                    {
                        functionCallStack.Add(procnode);
                    }
                }

                lefttype = finalType;
                depth = 1;
            }
            else
            {
                string message = "The left side of operator '.' must be an identifier. (B9AEA3A6)";
                buildStatus.LogSemanticError(message, core.CurrentDSFileName, node.line, node.col);
                throw new BuildHaltException(message);
            }
            return false;
        }