Exemplo n.º 1
0
        private void EmitRangeExprNode(AssociativeNode node, 
                                       ref ProtoCore.Type inferedType, 
                                       GraphNode graphNode = null, 
                                       AssociativeSubCompilePass subPass = AssociativeSubCompilePass.kNone)
        {
            RangeExprNode range = node as RangeExprNode;

            // Do some static checking...
            var fromNode = range.FromNode;
            var toNode = range.ToNode;
            var stepNode = range.StepNode;
            var stepOp = range.stepoperator;
            var hasAmountOperator = range.HasRangeAmountOperator;

            bool isStepValid = true;
            string warningMsg = string.Empty;

            if ((fromNode is IntNode || fromNode is DoubleNode) &&
                (toNode is IntNode || toNode is DoubleNode) &&
                (stepNode == null || stepNode is IntNode || stepNode is DoubleNode))
            {
                double current = (fromNode is IntNode) ?
                    (fromNode as IntNode).Value : (fromNode as DoubleNode).Value;
                double end = (toNode is IntNode) ?
                    (toNode as IntNode).Value : (toNode as DoubleNode).Value;

                double step = 1;
                if (stepNode != null)
                {
                    step = (stepNode is IntNode) ?
                        (stepNode as IntNode).Value : (stepNode as DoubleNode).Value;
                }

                switch (stepOp)
                {
                    case ProtoCore.DSASM.RangeStepOperator.stepsize:

                        if (!hasAmountOperator)
                        {
                            if (stepNode == null && end < current)
                            {
                                step = -1;
                            }

                            if (step == 0)
                            {
                                isStepValid = false;
                                warningMsg = WarningMessage.kRangeExpressionWithStepSizeZero;
                            }
                            else if ((end > current && step < 0) || (end < current && step > 0))
                            {
                                isStepValid = false;
                                warningMsg = WarningMessage.kRangeExpressionWithInvalidStepSize;
                            }
                        }

                       break;

                    case ProtoCore.DSASM.RangeStepOperator.num:

                       if (hasAmountOperator)
                       {
                           isStepValid = false;
                           warningMsg = WarningMessage.kRangeExpressionWithStepSizeZero;
                       }
                       else
                       {
                           if (stepNode != null && stepNode is DoubleNode &&
                               subPass == AssociativeSubCompilePass.kNone)
                           {
                               buildStatus.LogWarning(WarningID.kInvalidRangeExpression,
                                                      WarningMessage.kRangeExpressionWithNonIntegerStepNumber,
                                                      core.CurrentDSFileName,
                                                      stepNode.line,
                                                      stepNode.col);
                           }
                           else if (step <= 0)
                           {
                               isStepValid = false;
                               warningMsg = WarningMessage.kRangeExpressionWithNegativeStepNumber;
                           }
                       }

                       break;

                    case ProtoCore.DSASM.RangeStepOperator.approxsize:
                        if (hasAmountOperator)
                        {
                            isStepValid = false;
                            warningMsg = WarningMessage.kRangeExpressionConflictOperator;
                        }
                        else if (step == 0)
                        {
                            isStepValid = false;
                            warningMsg = WarningMessage.kRangeExpressionWithStepSizeZero;
                        }
                        break;

                    default:
                        break;
                }
            }

            if (!isStepValid && subPass == AssociativeSubCompilePass.kNone)
            {
                buildStatus.LogWarning(WarningID.kInvalidRangeExpression,
                                       warningMsg,
                                       core.CurrentDSFileName,
                                       stepNode.line,
                                       stepNode.col);

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

            // Replace with build-in RangeExpression() function. - Yu Ke
            bool emitReplicationgGuideState = emitReplicationGuide;
            emitReplicationGuide = false;

            IntNode op = null;
            switch (stepOp)
            {
                case RangeStepOperator.stepsize:
                    op = new IntNode(0);
                    break;
                case RangeStepOperator.num:
                    op = new IntNode(1);
                    break;
                case RangeStepOperator.approxsize:
                    op = new IntNode(2);
                    break;
                default:
                    op = new IntNode(-1);
                    break;
            }
            var arguments = new List<AssociativeNode>
            {
                fromNode,
                toNode,
                stepNode ?? new NullNode(),
                op,
                AstFactory.BuildBooleanNode(stepNode != null),
                AstFactory.BuildBooleanNode(hasAmountOperator),
            };
            var rangeExprFunc = AstFactory.BuildFunctionCall(Constants.kFunctionRangeExpression,
                                                             arguments);

            EmitFunctionCallNode(rangeExprFunc, ref inferedType, false, graphNode, subPass);

            emitReplicationGuide = emitReplicationgGuideState;

            if (subPass != AssociativeSubCompilePass.kUnboundIdentifier)
            {
                if (range.ArrayDimensions != null)
                {
                    int dim = DfsEmitArrayIndexHeap(range.ArrayDimensions, graphNode);
                    EmitInstrConsole(kw.pushindex, dim + "[dim]");
                    EmitPushArrayIndex(dim);
                }

                if (core.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide)
                {
                    int guide = EmitReplicationGuides(range.ReplicationGuides);
                    EmitInstrConsole(kw.pushindex, guide + "[guide]");
                    EmitPushReplicationGuide(guide);
                }
            }
        }
Exemplo n.º 2
0
        public ProcedureNode TraverseDotFunctionCall(
                                ProtoCore.AST.Node node, 
                                ProtoCore.AST.Node parentNode, 
                                int lefttype, 
                                int depth, 
                                ref ProtoCore.Type inferedType, 
                                GraphNode graphNode = null, 
                                AssociativeSubCompilePass subPass = AssociativeSubCompilePass.kNone,
                                BinaryExpressionNode bnode = null)
        {
            ProcedureNode procCallNode = null;
            ProcedureNode procDotCallNode = null;
            List<ProtoCore.Type> arglist = new List<ProtoCore.Type>();

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

            bool isConstructor = false;
            bool isStaticCall = false;
            bool isStaticCallAllowed = false;
            bool isUnresolvedDot = false;
            bool isUnresolvedMethod = false;

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

            //ProtoCore.AST.AssociativeAST.FunctionDotCallNode dotCall = node as ProtoCore.AST.AssociativeAST.FunctionDotCallNode;
            var dotCall = new FunctionDotCallNode(node as FunctionDotCallNode);
            FunctionCallNode funcCall = dotCall.DotCall;
            string procName = dotCall.FunctionCall.Function.Name;

            var replicationGuide = (dotCall.FunctionCall.Function as IdentifierNode).ReplicationGuides;

            var firstArgument = dotCall.DotCall.FormalArguments[0];
            if (firstArgument is FunctionDotCallNode)
            {
                isUnresolvedDot = true;
            }
            else if (firstArgument is IdentifierNode || firstArgument is ThisPointerNode)
            {
                // Check if the lhs identifer is a class name
                string lhsName = "";
                int ci = Constants.kInvalidIndex;

                if (firstArgument is IdentifierNode)
                {
                    lhsName = (firstArgument as IdentifierNode).Name;
                    ci = core.ClassTable.IndexOf(lhsName);
                    classIndex = ci;
                    className = lhsName;

                    // As a class name can be used as property name, we need to
                    // check if this identifier is a property or a class name.
                    //
                    if (ci != Constants.kInvalidIndex && globalClassIndex != Constants.kInvalidIndex)
                    {
                        ProtoCore.DSASM.SymbolNode symbolnode;
                        bool isAccessbile = false;
                        bool hasAllocated = VerifyAllocation(lhsName, globalClassIndex, globalProcIndex, out symbolnode, out isAccessbile);

                        // Well, found a property whose name is class name. Now
                        // we need to check if the RHS function call is
                        // constructor or not.
                        if (hasAllocated && isAccessbile && symbolnode.functionIndex == ProtoCore.DSASM.Constants.kInvalidIndex)
                        {
                            var procnode = GetProcedureFromInstance(ci, dotCall.FunctionCall);
                            if (procnode != null && !procnode.isConstructor)
                            {
                                ci = Constants.kInvalidIndex;
                                lhsName = "";
                            }
                        }
                    }
                }

                var classes = core.ClassTable.ClassNodes;

                if (ci != ProtoCore.DSASM.Constants.kInvalidIndex)
                {
                    // It is a class name
                    dotCall.DotCall.FormalArguments[0] = new IntNode(ci);
                    firstArgument = dotCall.DotCall.FormalArguments[0];

                    inferedType.UID = dotCallType.UID = ci;

                    string rhsName = dotCall.FunctionCall.Function.Name;
                    procCallNode = GetProcedureFromInstance(ci, dotCall.FunctionCall, graphNode);
                    if (null != procCallNode)
                    {
                        isConstructor = procCallNode.isConstructor;

                        // It's a static call if its not a constructor
                        isStaticCall = !procCallNode.isConstructor;

                        // If this is a static call and the first method found was not static
                        // Look further
                        if (isStaticCall && !procCallNode.isStatic)
                        {
                            ProcedureNode staticProcCallNode = classes[ci].GetFirstStaticMemberFunction(procName);
                            if (null != staticProcCallNode)
                            {
                                procCallNode = staticProcCallNode;
                            }
                        }

                        isStaticCallAllowed = procCallNode.isStatic && isStaticCall;
                    }
                    else
                    {
                        var procNode = classes[ci].GetFirstStaticMemberFunction(procName);
                        string functionName = dotCall.FunctionCall.Function.Name;
                        string property;

                        if (null != procNode)
                        {
                            string message = String.Format(WarningMessage.kMethodHasInvalidArguments, functionName);
                            buildStatus.LogWarning(WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, dotCall.line, dotCall.col);
                        }
                        else if (CoreUtils.TryGetPropertyName(functionName, out property))
                        {
                            procNode = classes[ci].GetFirstMemberFunction(property);

                            if (procNode != null)
                            {
                                if (subPass == AssociativeSubCompilePass.kNone)
                                {
                                    EmitFunctionPointer(procNode);
                                    return null;
                                }
                            }
                            else
                            {
                                if (subPass != AssociativeSubCompilePass.kUnboundIdentifier)
                                {
                                    string message = String.Format(WarningMessage.kCallingNonStaticProperty,
                                                                   lhsName, property);

                                    buildStatus.LogWarning(WarningID.kCallingNonStaticMethodOnClass,
                                                           message,
                                                           core.CurrentDSFileName,
                                                           dotCall.line,
                                                           dotCall.col);
                                }
                            }
                        }
                        else
                        {
                            if (subPass != AssociativeSubCompilePass.kUnboundIdentifier)
                            {
                                string message = String.Format(WarningMessage.kCallingNonStaticMethod, lhsName, functionName);
                                buildStatus.LogWarning(WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, dotCall.line, dotCall.col);
                            }
                        }
                    }
                }

                if (dotCall.DotCall.FormalArguments.Count == Constants.kDotCallArgCount)
                {
                    if (firstArgument is IdentifierNode)
                    {
                        SymbolNode symbolnode = null;
                        bool isAccessible = false;
                        bool isAllocated = VerifyAllocation((firstArgument as IdentifierNode).Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible);
                        if (isAllocated && 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 != AssociativeSubCompilePass.kUnboundIdentifier)
                                    {
                                        // A constructor cannot be called from an instance
                                        string message = String.Format(WarningMessage.KCallingConstructorOnInstance, procName);
                                        buildStatus.LogWarning(WarningID.kCallingConstructorOnInstance, message, core.CurrentDSFileName, funcCall.line, funcCall.col);
                                    }

                                    isUnresolvedDot = true;
                                    isUnresolvedMethod = true;
                                }
                                else
                                {
                                   isAccessible = procCallNode.access == AccessSpecifier.kPublic
                                        || (procCallNode.access == AccessSpecifier.kPrivate && procCallNode.classScope == globalClassIndex);

                                    if (!isAccessible)
                                    {
                                        if (subPass != AssociativeSubCompilePass.kUnboundIdentifier)
                                        {
                                            string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName);
                                            buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, core.CurrentDSFileName, funcCall.line, funcCall.col);
                                        }
                                    }

                                    if (null != procCallNode)
                                    {
                                        var dynamicRhsIndex = (int)(dotCall.DotCall.FormalArguments[1] as IntNode).Value;
                                        core.DynamicFunctionTable.functionTable[dynamicRhsIndex].classIndex = procCallNode.classScope;
                                        core.DynamicFunctionTable.functionTable[dynamicRhsIndex].procedureIndex = procCallNode.procId;
                                        core.DynamicFunctionTable.functionTable[dynamicRhsIndex].pc = procCallNode.pc;
                                    }
                                }
                            }
                        }
                        else
                        {
                            isUnresolvedDot = true;
                        }
                    }
                    else if (firstArgument is ThisPointerNode)
                    {
                        if (globalClassIndex != Constants.kInvalidIndex)
                        {
                            procCallNode = GetProcedureFromInstance(globalClassIndex, dotCall.FunctionCall);
                            if (null != procCallNode && procCallNode.isConstructor)
                            {
                                dotCall.DotCall.FormalArguments[0] = new IntNode(globalClassIndex);
                                firstArgument = dotCall.DotCall.FormalArguments[0];
                                inferedType.UID = dotCallType.UID = ci;
                            }
                        }
                    }
                }
            }
            else if (funcCall.FormalArguments[0] is IntNode)
            {
                inferedType.UID = dotCallType.UID = (int)(funcCall.FormalArguments[0] as IntNode).Value;
                classIndex = inferedType.UID;
                procCallNode = GetProcedureFromInstance(dotCallType.UID, dotCall.FunctionCall, graphNode);

                if (null != procCallNode)
                {
                    // It's a static call if its not a constructor
                    isConstructor = procCallNode.isConstructor;
                    isStaticCall = !procCallNode.isConstructor;

                    // If this is a static call and the first method found was not static
                    // Look further
                    if (isStaticCall && !procCallNode.isStatic)
                    {
                        ProtoCore.DSASM.ProcedureNode staticProcCallNode = core.ClassTable.ClassNodes[inferedType.UID].GetFirstStaticMemberFunction(procName);
                        if (null != staticProcCallNode)
                        {
                            procCallNode = staticProcCallNode;
                        }
                    }

                    isStaticCallAllowed = procCallNode.isStatic && isStaticCall;
                    className = core.ClassTable.ClassNodes[dotCallType.UID].name;

                    if (isStaticCall && !isStaticCallAllowed)
                    {
                        if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier)
                        {
                            string property;
                            className = core.ClassTable.ClassNodes[dotCallType.UID].name;
                            ProtoCore.DSASM.ProcedureNode staticProcCallNode = core.ClassTable.ClassNodes[inferedType.UID].GetFirstStaticMemberFunction(procName);

                            if (null != staticProcCallNode)
                            {
                                string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodHasInvalidArguments, procName);
                                buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, dotCall.line, dotCall.col);
                            }
                            else if (CoreUtils.TryGetPropertyName(procName, out property))
                            {
                                string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticProperty, property, className);
                                buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, dotCall.line, dotCall.col);
                            }
                            else
                            {
                                string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticMethod, procName, className);
                                buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, dotCall.line, dotCall.col);
                            }
                        }
                        isUnresolvedMethod = true;
                    }
                    else
                    {
                        inferedType = procCallNode.returntype;
                    }
                }
            }

            // Its an accceptable method at this point
            if (!isUnresolvedMethod)
            {
                int funtionArgCount = 0;

                //foreach (AssociativeNode paramNode in funcCall.FormalArguments)
                for (int n = 0; n < funcCall.FormalArguments.Count; ++n)
                {
                    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
                    // f(1+2.0) -> type check enabled - param is typed as double
                    // f(2) -> type check disabled - param is typed as int
                    enforceTypeCheck = !(paramNode is BinaryExpressionNode);

                    // TODO Jun: Cleansify me
                    // What im doing is just taking the second parameter of the dot op (The method call)
                    // ...and adding it to the graph node dependencies
                    if (ProtoCore.DSASM.Constants.kDotArgIndexDynTableIndex == n)
                    {
                        if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier)
                        {
                            if (!isConstructor)
                            {
                                if (null != procCallNode)
                                {
                                    if (graphNode.dependentList.Count > 0)
                                    {
                                        ProtoCore.AssociativeGraph.UpdateNodeRef nodeRef = new ProtoCore.AssociativeGraph.UpdateNodeRef();
                                        ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode();
                                        ProtoCore.DSASM.ProcedureNode procNodeDummy = new ProtoCore.DSASM.ProcedureNode();
                                        if (procCallNode.isAutoGenerated)
                                        {
                                            ProtoCore.DSASM.SymbolNode sym = new ProtoCore.DSASM.SymbolNode();
                                            sym.name = procName.Remove(0, ProtoCore.DSASM.Constants.kSetterPrefix.Length);
                                            updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol;
                                            updateNode.symbol = sym;
                                        }
                                        else
                                        {
                                            procNodeDummy.name = procName;
                                            updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kMethod;
                                            updateNode.procNode = procNodeDummy;
                                        }
                                        graphNode.dependentList[0].updateNodeRefList[0].nodeList.Add(updateNode);
                                    }
                                }
                                else
                                {
                                    // comment Jun:
                                    // This is dotarg whos first argument is also a dotarg
                                    // dotarg(dorarg...)...)
                                    if (graphNode.dependentList.Count > 0)
                                    {
                                        if (ProtoCore.Utils.CoreUtils.IsGetterSetter(procName))
                                        {
                                            ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode();
                                            ProtoCore.DSASM.SymbolNode sym = new ProtoCore.DSASM.SymbolNode();
                                            sym.name = procName.Remove(0, ProtoCore.DSASM.Constants.kSetterPrefix.Length);
                                            updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol;
                                            updateNode.symbol = sym;

                                            graphNode.dependentList[0].updateNodeRefList[0].nodeList.Add(updateNode);
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // Traversing the first arg (the LHS pointer/Static instanct/Constructor
                    if (ProtoCore.DSASM.Constants.kDotArgIndexPtr == n)
                    {
                        // Comment Jun:
                        //      Allow guides only on 'this' pointers for non getter/setter methods
                        //      No guides for 'this' pointers in constructors calls (There is no this pointer yet)
                        //
                        /*
                            class C
                            {
                                def f(a : int)
                                {
                                    return = 10;
                                }
                            }
                            p = {C.C(), C.C()};
                            x = p<1>.f({1,2}<2>); // guides allowed on the pointer 'p'

                            class A
                            {
                                x : var[];
                                constructor A()
                                {
                                    x = {1,2};
                                }
                            }
                            a = A.A();
                            b = A.A();
                            c = a<1>.x<2>; // guides not allowed on getter

                         */
                        if (!ProtoCore.Utils.CoreUtils.IsGetterSetter(procName) && !isConstructor)
                        {
                            emitReplicationGuide = true;
                        }

                        DfsTraverse(paramNode, ref paramType, false, graphNode, subPass, bnode);
                        if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier)
                        {
                            if (isStaticCall && isStaticCallAllowed)
                            {
                                Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != classIndex);
                                Validity.Assert(string.Empty != className);
                                SymbolNode classSymbol = new SymbolNode();
                                classSymbol.name = className;
                                classSymbol.classScope = classIndex;

                                ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode();
                                dependentNode.PushSymbolReference(classSymbol, ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol);
                                graphNode.PushDependent(dependentNode);
                            }
                        }
                    }

                    // Traversing the actual arguments passed into the function (not the dot function)
                    else if (ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs == n)
                    {
                        int defaultAdded = 0;

                        // If its null this is the second call in a chained dot
                        if (null != procCallNode)
                        {
                            // Check how many args were passed in.... against what is expected
                            defaultAdded = procCallNode.argInfoList.Count - dotCall.FunctionCall.FormalArguments.Count;
                        }

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

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

                                // TODO Jun: deprecate SSA flag and do full SSA
                                if (core.Options.GenerateSSA)
                                {
                                    // Only allow the acutal function variables and SSA temp vars
                                    // TODO Jun: determine what temp could be passed in that is autodegenerated and non-SSA
                                    if (!ProtoCore.Utils.CoreUtils.IsAutoGeneratedVar(varname)
                                        || ProtoCore.Utils.CoreUtils.IsSSATemp(varname))
                                    {
                                        graphNode.allowDependents = true;
                                    }
                                }
                                else
                                {
                                    if (!ProtoCore.Utils.CoreUtils.IsAutoGeneratedVar(varname))
                                    {
                                        graphNode.allowDependents = true;
                                    }
                                }
                            }
                            else
                            {
                                graphNode.allowDependents = true;
                            }

                        }

                        emitReplicationGuide = true;

                        if (defaultAdded > 0)
                        {
                            ProtoCore.AST.AssociativeAST.ExprListNode exprList = paramNode as ExprListNode;

                            if (subPass != AssociativeSubCompilePass.kUnboundIdentifier)
                            {
                                for (int i = 0; i < defaultAdded; i++)
                                {
                                    exprList.list.Add(new DefaultArgNode());
                                }

                            }
                            DfsTraverse(paramNode, ref paramType, false, graphNode, subPass);
                            funtionArgCount = exprList.list.Count;
                        }
                        else
                        {
                            Validity.Assert(paramNode is ProtoCore.AST.AssociativeAST.ExprListNode);
                            ProtoCore.AST.AssociativeAST.ExprListNode exprList = paramNode as ProtoCore.AST.AssociativeAST.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)
                            {
                                //if (null != procCallNode && ProtoCore.Utils.CoreUtils.IsGetterSetter(procCallNode.name) && AssociativeSubCompilePass.kNone == subPass)
                                // TODO Jun: pls get rid of subPass checking outside the core travesal
                                if (ProtoCore.DSASM.AssociativeSubCompilePass.kNone == subPass)
                                {
                                    exprList.list.Insert(0, new DynamicNode());
                                }
                            }

                            if (exprList.list.Count > 0)
                            {
                                foreach (ProtoCore.AST.AssociativeAST.AssociativeNode exprListNode in exprList.list)
                                {
                                    bool repGuideState = emitReplicationGuide;
                                    if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier)
                                    {
                                        if (exprListNode is ProtoCore.AST.AssociativeAST.ExprListNode
                                            || exprListNode is ProtoCore.AST.AssociativeAST.GroupExpressionNode)
                                        {
                                            if (core.Options.TempReplicationGuideEmptyFlag)
                                            {
                                                // Emit the replication guide for the exprlist
                                                List<ProtoCore.AST.AssociativeAST.AssociativeNode> repGuideList = GetReplicationGuides(exprListNode);
                                                EmitReplicationGuides(repGuideList, true);

                                                emitReplicationGuide = false;

                                                // Pop off the guide if the current element was an array
                                                if (null != repGuideList)
                                                {
                                                    EmitInstrConsole(ProtoCore.DSASM.kw.popg);
                                                    EmitPopGuide();
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        emitReplicationGuide = false;
                                    }

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

                                if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier)
                                {

                                    EmitInstrConsole(ProtoCore.DSASM.kw.alloca, exprList.list.Count.ToString());
                                    EmitPopArray(exprList.list.Count);

                                    if (exprList.ArrayDimensions != null)
                                    {
                                        int dimensions = DfsEmitArrayIndexHeap(exprList.ArrayDimensions, graphNode);
                                        EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, dimensions.ToString() + "[dim]");
                                        EmitPushArrayIndex(dimensions);
                                    }
                                }
                            }
                            else
                            {
                                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.list.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;

                    arglist.Add(paramType);
                }
            }

            if (subPass == ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier)
            {
                return null;
            }

            // Comment Jun: Append the lhs pointer as an argument to the overloaded function
            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.list.Insert(0, dotCall.DotCall.FormalArguments[ProtoCore.DSASM.Constants.kDotArgIndexPtr]);
            }

            if (isUnresolvedMethod)
            {
                EmitNullNode(new NullNode(), ref inferedType);
                return null;
            }

            procDotCallNode = core.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotArgMethodName, arglist, codeBlock);

            // 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 ProtoCore.AST.AssociativeAST.IdentifierListNode)
            {
                ProtoCore.AST.Node leftnode = (parentNode as ProtoCore.AST.AssociativeAST.IdentifierListNode).LeftNode;
                if (leftnode != null && leftnode is ProtoCore.AST.AssociativeAST.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 ((int)ProtoCore.PrimitiveType.kInvalidType != inferedType.UID
                && (int)ProtoCore.PrimitiveType.kTypeVoid != inferedType.UID
                && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)
            {
                bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex;
                //procCallNode = core.classTable.list[inferedType.UID].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor);
                procCallNode = core.ClassTable.ClassNodes[inferedType.UID].GetFirstMemberFunction(procName);
            }

            // Try function pointer firstly
            if ((procCallNode == null) && (procName != ProtoCore.DSASM.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 = ProtoCore.DSASM.Constants.kFunctionPointerCall;
                    // The graph node always depends on this function pointer
                    if (null != graphNode)
                    {
                        ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode();
                        dependentNode.PushSymbolReference(symbolnode);
                        graphNode.PushDependent(dependentNode);
                    }
                }
            }

            // 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 != ProtoCore.DSASM.Constants.kFunctionPointerCall))
            {
                procCallNode = core.GetFirstVisibleProcedure(procName, arglist, codeBlock);
                if (null != procCallNode)
                {
                    type = ProtoCore.DSASM.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 != ProtoCore.DSASM.Constants.kFunctionPointerCall) && (parentNode == null))
            {
                if (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex)
                {
                    int realType;
                    bool isAccessible;
                    bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex;
                    ProtoCore.DSASM.ProcedureNode memProcNode = core.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor);

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

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

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

            if (isUnresolvedDot)
            {
                // Get the dot call procedure
                ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode;
                if (!isConstructor && !isStaticCall)
                {
                    procNode = core.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotMethodName, null, codeBlock);
                }

                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;
                }

                return procCallNode;
            }

            if (null != procCallNode)
            {
                if (procCallNode.isConstructor &&
                        (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) &&
                        (globalProcIndex != ProtoCore.DSASM.Constants.kInvalidIndex) &&
                        (globalClassIndex == inferedType.UID))
                {
                    ProtoCore.DSASM.ProcedureNode contextProcNode = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex];
                    if (contextProcNode.isConstructor &&
                        string.Equals(contextProcNode.name, procCallNode.name) &&
                        contextProcNode.runtimeIndex == procCallNode.runtimeIndex)
                    {
                        string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingConstructorInConstructor, procName);
                        buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingConstructorInConstructor, message, core.CurrentDSFileName, node.line, node.col);
                        inferedType.UID = (int)PrimitiveType.kTypeNull;
                        EmitPushNull();
                        return procCallNode;
                    }
                }

                inferedType = procCallNode.returntype;

                //if call is replication call
                if (procCallNode.isThisCallReplication)
                {
                    inferedType.rank++;
                }

                // Get the dot call procedure
                ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode;
                if (!isConstructor && !isStaticCall)
                {
                    procNode = core.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotMethodName, null, 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;
                        ProtoCore.AssociativeGraph.UpdateNodeRef argNodeRef = new ProtoCore.AssociativeGraph.UpdateNodeRef();
                        DFSGetSymbolList(paramNode, ref ltype, argNodeRef);

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

                    graphNode.firstProc = procCallNode;
                }

                return procCallNode;
            }
            else
            {
                // Function does not exist at this point but we try to reolve at runtime
                if (depth <= 0 && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)
                {
                    if (inferedType.UID != (int)PrimitiveType.kTypeVar)
                    {
                        if (!core.Options.SuppressFunctionResolutionWarning)
                        {
                            string property;
                            if (CoreUtils.TryGetPropertyName(procName, out property))
                            {
                                string message = String.Format(ProtoCore.BuildData.WarningMessage.kPropertyNotFound, property);
                                buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kPropertyNotFound, message, core.CurrentDSFileName, funcCall.line, funcCall.col);
                            }
                            else
                            {
                                string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodNotFound, procName);
                                buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionNotFound, message, core.CurrentDSFileName, funcCall.line, funcCall.col);
                            }
                        }
                        inferedType.UID = (int)PrimitiveType.kTypeNull;
                    }

                    // Get the dot call procedure
                    ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode;
                    if (!isConstructor && !isStaticCall)
                    {
                        procNode = core.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotMethodName, null, codeBlock);
                    }

                    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;
                    }
                }
                else
                {
                    if (procName == ProtoCore.DSASM.Constants.kFunctionPointerCall && depth == 0)
                    {
                        ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(procName, arglist, lefttype);
                        core.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode);

                        var iNode = nodeBuilder.BuildIdentfier(funcCall.Function.Name);
                        EmitIdentifierNode(iNode, ref inferedType);
                    }
                    else
                    {
                        ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(funcCall.Function.Name, arglist, lefttype);
                        core.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode);
                    }
                    // The function call
                    EmitInstrConsole(ProtoCore.DSASM.kw.callr, funcCall.Function.Name + "[dynamic]");
                    EmitDynamicCall(core.DynamicFunctionTable.functionTable.Count - 1, globalClassIndex, depth, funcCall.line, funcCall.col, funcCall.endLine, funcCall.endCol);

                    // The function return value
                    EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX);
                    StackValue opReturn = StackValue.BuildRegister(Registers.RX);
                    EmitPush(opReturn);

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

                    //assign inferedType to var
                    inferedType.UID = (int)PrimitiveType.kTypeVar;
                }
            }
            return procDotCallNode;
        }
Exemplo n.º 3
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,
                                              AssociativeSubCompilePass subPass,
                                              BinaryExpressionNode bnode)
        {
            // Update graph dependencies
            if (subPass != AssociativeSubCompilePass.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;

                    GraphNode dependentNode = new GraphNode();
                    dependentNode.PushSymbolReference(classSymbol, UpdateNodeType.kSymbol);
                    graphNode.PushDependent(dependentNode);
                }

                if (!isConstructor && graphNode.dependentList.Count > 0)
                {
                    UpdateNode updateNode = new UpdateNode();

                    string propertyName;
                    if (CoreUtils.TryGetPropertyName(procName, out propertyName))
                    {
                        var dummySymbol = new SymbolNode();
                        dummySymbol.name = propertyName;

                        updateNode.nodeType = UpdateNodeType.kSymbol;
                        updateNode.symbol = dummySymbol;
                    }
                    else
                    {
                        var dummyProcNode = new ProcedureNode();
                        dummyProcNode.name = procName;

                        updateNode.nodeType = UpdateNodeType.kMethod;
                        updateNode.procNode = dummyProcNode;
                    }

                    graphNode.dependentList[0].updateNodeRefList[0].nodeList.Add(updateNode);
                }
            }

            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.argInfoList.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.list.Count);

                        string varname = string.Empty;
                        if (exprList.list[0] is IdentifierNode)
                        {
                            varname = (exprList.list[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 != AssociativeSubCompilePass.kUnboundIdentifier)
                        {
                            for (int i = 0; i < defaultArgNumber; i++)
                            {
                                exprList.list.Add(new DefaultArgNode());
                            }

                        }

                        if (!isStaticCall && !isConstructor)
                        {
                            DfsTraverse(paramNode, ref paramType, false, graphNode, subPass);
                            funtionArgCount = exprList.list.Count;
                        }
                        else
                        {
                            foreach (AssociativeNode exprListNode in exprList.list)
                            {
                                bool repGuideState = emitReplicationGuide;
                                if (subPass != AssociativeSubCompilePass.kUnboundIdentifier)
                                {
                                    if (exprListNode is ExprListNode || exprListNode is GroupExpressionNode)
                                    {
                                        if (core.Options.TempReplicationGuideEmptyFlag)
                                        {
                                            // Emit the replication guide for the exprlist
                                            var repGuideList = GetReplicationGuides(exprListNode);
                                            if (repGuideList != null)
                                            {
                                                EmitReplicationGuides(repGuideList, true);
                                                EmitInstrConsole(ProtoCore.DSASM.kw.popg);
                                                EmitPopGuide();
                                            }

                                            emitReplicationGuide = false;
                                        }
                                    }
                                }
                                else
                                {
                                    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 (AssociativeSubCompilePass.kNone == subPass)
                            {
                                exprList.list.Insert(0, new DynamicNode());
                            }
                        }

                        if (exprList.list.Count > 0)
                        {
                            foreach (AssociativeNode exprListNode in exprList.list)
                            {
                                bool repGuideState = emitReplicationGuide;
                                if (subPass != AssociativeSubCompilePass.kUnboundIdentifier)
                                {
                                    if (exprListNode is ExprListNode || exprListNode is GroupExpressionNode)
                                    {
                                        if (core.Options.TempReplicationGuideEmptyFlag)
                                        {
                                            // Emit the replication guide for the exprlist
                                            var repGuideList = GetReplicationGuides(exprListNode);
                                            if (repGuideList != null)
                                            {
                                                EmitReplicationGuides(repGuideList, true);
                                                EmitInstrConsole(ProtoCore.DSASM.kw.popg);
                                                EmitPopGuide();
                                            }

                                            emitReplicationGuide = false;
                                        }
                                    }
                                }
                                else
                                {
                                    emitReplicationGuide = false;
                                }

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

                                arglist.Add(paramType);
                            }

                            if (subPass != AssociativeSubCompilePass.kUnboundIdentifier &&
                                !isStaticCall &&
                                !isConstructor)
                            {
                                EmitInstrConsole(ProtoCore.DSASM.kw.alloca, exprList.list.Count.ToString());
                                EmitPopArray(exprList.list.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.list.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);
                }
            } 
        }
Exemplo n.º 4
0
        public override ProcedureNode TraverseFunctionCall(
            ProtoCore.AST.Node node, 
            ProtoCore.AST.Node parentNode, 
            int lefttype, 
            int depth, 
            ref ProtoCore.Type inferedType,             
            GraphNode graphNode = null, 
            AssociativeSubCompilePass subPass = AssociativeSubCompilePass.kNone,                 
            ProtoCore.AST.Node bnode = null)
        {
            Guid guid = graphNode == null ? default(Guid) : graphNode.guid;
            ProcedureNode procNode = null;
            if (node is FunctionDotCallNode)
            {
                procNode = TraverseDotFunctionCall(node, 
                                               parentNode, 
                                               lefttype, 
                                               depth, 
                                               graphNode, 
                                               subPass, 
                                               bnode as BinaryExpressionNode,
                                               ref inferedType);

                if (graphNode != null && procNode != null)
                {
                    GenerateCallsiteIdentifierForGraphNode(graphNode, procNode.name);
                }
                return procNode;
            }

            var arglist = new List<ProtoCore.Type>();
            var funcCall = node as FunctionCallNode;
            var procName = funcCall.Function.Name;
            int classIndex = core.ClassTable.IndexOf(procName);

            // To support unamed constructor
            if (classIndex != Constants.kInvalidIndex)
            {
                bool isAccessible;
                int dummy;

                ProcedureNode constructor = core.ClassTable.ClassNodes[classIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out dummy, true);
                if (constructor != null && constructor.isConstructor)
                {
                    var rhsFNode = node as FunctionCallNode;
                    var classNode = nodeBuilder.BuildIdentfier(procName);
                    var dotCallNode = CoreUtils.GenerateCallDotNode(classNode, rhsFNode, core);

                    procNode = TraverseDotFunctionCall(dotCallNode, 
                                                   parentNode, 
                                                   lefttype, 
                                                   depth, 
                                                   graphNode, 
                                                   subPass, 
                                                   bnode as BinaryExpressionNode,
                                                   ref inferedType);
                    if (graphNode != null && procNode != null)
                    {
                        GenerateCallsiteIdentifierForGraphNode(graphNode, procNode.name);
                    }
                    return procNode;
                }
            }

            foreach (AssociativeNode paramNode in funcCall.FormalArguments)
            {
                var paramType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0);

                // The range expression function does not need replication guides
                emitReplicationGuide = !procName.Equals(Constants.kFunctionRangeExpression)  
                                    && !CoreUtils.IsGetterSetter(procName);

                // If it's a binary node then continue type check, otherwise 
                // disable type check and just take the type of paramNode itself
                // f(1+2.0) -> type check enabled - param is typed as double
                // f(2) -> type check disabled - param is typed as int
                enforceTypeCheck = !(paramNode is BinaryExpressionNode);

                DfsTraverse(paramNode, ref paramType, false, graphNode, subPass, bnode);

                emitReplicationGuide = false;
                enforceTypeCheck = true;

                arglist.Add(paramType);
            }
           
            if (subPass == AssociativeSubCompilePass.kUnboundIdentifier)
            {
                return null;   
            }
                    
            int refClassIndex = 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);
                }
            }

            int type = Constants.kInvalidIndex;

            // Check for the actual method, not the dot method
            // If lefttype is a valid class then check if calling a constructor
            if ((int)PrimitiveType.kInvalidType != inferedType.UID
                && (int)PrimitiveType.kTypeVoid != inferedType.UID
                && procName != Constants.kFunctionPointerCall)
            {

                bool isAccessible;
                int realType;

                bool isStaticOrConstructor = refClassIndex != Constants.kInvalidIndex;
                procNode = core.ClassTable.ClassNodes[inferedType.UID].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor);

                if (procNode != null)
                {
                    Validity.Assert(realType != Constants.kInvalidIndex);
                    type = lefttype = realType;

                    if (!isAccessible)
                    {
                        type = lefttype = realType;
                        procNode = null;
                        string message = String.Format(WarningMessage.kMethodIsInaccessible, procName);
                        buildStatus.LogWarning(WarningID.kAccessViolation, message, core.CurrentDSFileName, funcCall.line, funcCall.col, guid);
                        inferedType.UID = (int)PrimitiveType.kTypeNull;

                        EmitPushNull();
                        if (graphNode != null && procNode != null)
                        {
                            GenerateCallsiteIdentifierForGraphNode(graphNode, procNode.name);
                        }
                        return procNode;
                    }

                }
            }

            // Try function pointer firstly
            if ((procNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall))
            {
                bool isAccessibleFp;
                SymbolNode symbolnode = null;
                bool isAllocated = VerifyAllocation(procName, globalClassIndex, globalProcIndex, out symbolnode, out isAccessibleFp);

                if (isAllocated) 
                {
                    // The graph node always depends on this function pointer
                    if (null != graphNode)
                    {
                        GraphNode dependentNode = new GraphNode();
                        dependentNode.PushSymbolReference(symbolnode);
                        graphNode.PushDependent(dependentNode);

                        GenerateCallsiteIdentifierForGraphNode(graphNode, procName);
                    }

                    // not checking the type against function pointer, as the 
                    // type could be var
                    procName = Constants.kFunctionPointerCall;
                }
            }

            // 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 ((procNode == null) && (procName != Constants.kFunctionPointerCall))
            {
                procNode = core.GetFirstVisibleProcedure(procName, arglist, codeBlock);
                if (null != procNode)
                {
                    type = ProtoCore.DSASM.Constants.kGlobalScope;
                    if (core.TypeSystem.IsHigherRank(procNode.returntype.UID, inferedType.UID))
                    {
                        inferedType = procNode.returntype;
                    }
                }
            }

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

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

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

                            inferedType.UID = (int)PrimitiveType.kTypeNull;
                            EmitPushNull();
                            if (graphNode != null && procNode != null)
                            {
                                GenerateCallsiteIdentifierForGraphNode(graphNode, procNode.name);
                            }
                            return procNode;
                        }
                    }
                }
            }

            if (null != procNode)
            {
                if (procNode.isConstructor && 
                    (globalClassIndex != Constants.kInvalidIndex) && 
                    (globalProcIndex != Constants.kInvalidIndex) && 
                    (globalClassIndex == inferedType.UID))
                {
                    ProcedureNode contextProcNode = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex];
                    if (contextProcNode.isConstructor &&
                        string.Equals(contextProcNode.name, procNode.name) &&
                        contextProcNode.runtimeIndex == procNode.runtimeIndex)
                    {
                        string message = String.Format(WarningMessage.kCallingConstructorInConstructor, procName);
                        buildStatus.LogWarning(WarningID.kCallingConstructorInConstructor, message, core.CurrentDSFileName, node.line, node.col, guid);
                        inferedType.UID = (int)PrimitiveType.kTypeNull;
                        EmitPushNull();
                        if (graphNode != null && procNode != null)
                        {
                            GenerateCallsiteIdentifierForGraphNode(graphNode, procNode.name);
                        }
                        return procNode;
                    }
                }

                inferedType = procNode.returntype;

                if (procNode.procId != Constants.kInvalidIndex)
                {

                    //
                    // ==============Establishing graphnode links in modified arguments=============
                    //
                    //  proc TraverseCall(node, graphnode)
                    //      ; Get the first procedure, this will only be the first visible procedure 
                    //      ; Overloads will be handled at runtime
                    //      def fnode = getProcedure(node)
                    //      
                    //      ; For every argument in the function call,
                    //      ; attach the modified property list and append it to the graphnode update list
                    //      foreach arg in node.args
                    //          if fnode.updatedArgProps is not null
                    //              def noderef = arg.ident (or identlist)
                    //              noderef.append(fnode.updatedArgProps)
                    //              graphnode.pushUpdateRef(noderef)
                    //          end
                    //      end
                    //  end
                    //
                    // =============================================================================
                    //

                    foreach (AssociativeNode paramNode in funcCall.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);
                            }
                        }
                    }

                    // The function is at block 0 if its a constructor, member 
                    // or at the globals scope.  Its at block 1 if its inside a 
                    // language block. Its limited to block 1 as of R1 since we 
                    // dont support nested function declarations yet
                    int blockId = procNode.runtimeIndex;

                    //push value-not-provided default argument
                    for (int i = arglist.Count; i < procNode.argInfoList.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(blockId, dimensions);

                    // The function call
                    EmitInstrConsole(kw.callr, procNode.name);

                    // Do not emit breakpoints at built-in methods like _add/_sub etc. - pratapa
                    if (procNode.isAssocOperator || procNode.name.Equals(Constants.kInlineConditionalMethodName))
                    {
                        EmitCall(procNode.procId, 
                                 type, 
                                 depth, 
                                 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.DebugProps.breakOptions.HasFlag(DebugProperties.BreakpointOptions.EmitInlineConditionalBreakpoint))
                    {
                        var codeRange = core.DebugProps.highlightRange;
                        Validity.Assert(codeRange != null);

                        var startInclusive = codeRange.StartInclusive;
                        var endExclusive = codeRange.EndExclusive;

                        EmitCall(procNode.procId, 
                                 type, 
                                 depth, 
                                 startInclusive.LineNo, 
                                 startInclusive.CharNo, 
                                 endExclusive.LineNo, 
                                 endExclusive.CharNo, 
                                 procNode.pc);
                    }
                    // Use startCol and endCol of binary expression node containing function call except if it's a setter
                    else if (bnode != null && !procNode.name.StartsWith(Constants.kSetterPrefix))
                    {
                        EmitCall(procNode.procId, 
                                 type, 
                                 depth, 
                                 bnode.line, 
                                 bnode.col, 
                                 bnode.endLine, 
                                 bnode.endCol, 
                                 procNode.pc);
                    }
                    else
                    {
                        EmitCall(procNode.procId, 
                                 type, 
                                 depth, 
                                 funcCall.line, 
                                 funcCall.col, 
                                 funcCall.endLine, 
                                 funcCall.endCol, 
                                 procNode.pc);
                    }

                    // The function return value
                    EmitInstrConsole(kw.push, kw.regRX);
                    StackValue opReturn = StackValue.BuildRegister(Registers.RX);
                    EmitPush(opReturn);
                }
            }
            else
            {
                if (depth <= 0 && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)
                {
                    string property;
                    if (CoreUtils.TryGetPropertyName(procName, out property))
                    {
                        string message = String.Format(ProtoCore.BuildData.WarningMessage.kPropertyNotFound, property);
                        buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kPropertyNotFound, message, core.CurrentDSFileName, funcCall.line, funcCall.col, guid);
                    }
                    else
                    {
                        string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodNotFound, procName);
                        buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionNotFound, message, core.CurrentDSFileName, funcCall.line, funcCall.col, guid);
                    }

                    inferedType.UID = (int)PrimitiveType.kTypeNull;
                    EmitPushNull();
                }
                else
                {
                    DynamicFunction dynFunc = null;
                    if (procName == Constants.kFunctionPointerCall && depth == 0)
                    {
                        if (!core.DynamicFunctionTable.TryGetFunction(procName, arglist.Count, lefttype, out dynFunc))
                        {
                            dynFunc = core.DynamicFunctionTable.AddNewFunction(procName, arglist.Count, lefttype);
                        }
                        var iNode = nodeBuilder.BuildIdentfier(funcCall.Function.Name);
                        EmitIdentifierNode(iNode, ref inferedType);
                    }
                    else
                    {
                        if (!core.DynamicFunctionTable.TryGetFunction(procName, arglist.Count, lefttype, out dynFunc))
                        {
                            dynFunc = core.DynamicFunctionTable.AddNewFunction(procName, arglist.Count, lefttype);
                        }
                    }

                    // The function call
                    EmitInstrConsole(kw.callr, funcCall.Function.Name + "[dynamic]");
                    EmitDynamicCall(dynFunc.Index, 
                                    globalClassIndex, 
                                    depth, 
                                    funcCall.line, 
                                    funcCall.col, 
                                    funcCall.endLine, 
                                    funcCall.endCol);

                    // The function return value
                    EmitInstrConsole(kw.push, kw.regRX);
                    StackValue opReturn = StackValue.BuildRegister(Registers.RX);
                    EmitPush(opReturn);

                    //assign inferedType to var
                    inferedType.UID = (int)PrimitiveType.kTypeVar;
                }
            }

            if (graphNode != null && procNode != null)
            {
                GenerateCallsiteIdentifierForGraphNode(graphNode, procNode.name);
            }
            
            return procNode;
        }
Exemplo n.º 5
0
        public ProcedureNode TraverseDotFunctionCall(
                                ProtoCore.AST.Node node, 
                                ProtoCore.AST.Node parentNode, 
                                int lefttype, 
                                int depth, 
                                GraphNode graphNode, 
                                AssociativeSubCompilePass subPass,
                                BinaryExpressionNode bnode,
                                ref ProtoCore.Type inferedType)
        {
            Guid guid = graphNode == null ? default(Guid) : graphNode.guid;

            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 != AssociativeSubCompilePass.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(WarningMessage.kCallingNonStaticProperty,
                                                               className,
                                                               property);

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

                                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 == AssociativeSubCompilePass.kNone)
                            {
                                string message = String.Format(WarningMessage.kStaticMethodNotFound,
                                                               className,
                                                               procName);

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

                                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 == AssociativeSubCompilePass.kNone)
                            {
                                string message = String.Format(WarningMessage.KCallingConstructorOnInstance,
                                                               procName);
                                buildStatus.LogWarning(WarningID.kCallingConstructorOnInstance,
                                                       message,
                                                       core.CurrentDSFileName,
                                                       funcCall.line,
                                                       funcCall.col, guid);
                                EmitNullNode(new NullNode(), ref inferedType);
                            }
                            return null;
                        }

                        isAccessible = procCallNode.access == AccessSpecifier.kPublic
                             || (procCallNode.access == AccessSpecifier.kPrivate && procCallNode.classScope == globalClassIndex);

                        if (!isAccessible)
                        {
                            if (subPass == AssociativeSubCompilePass.kNone)
                            {
                                string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName);
                                buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, core.CurrentDSFileName, funcCall.line, funcCall.col, guid);
                            }
                        }

                        var dynamicRhsIndex = (int)(dotCall.DotCall.FormalArguments[1] as IntNode).Value;
                        var dynFunc = core.DynamicFunctionTable.GetFunctionAtIndex(dynamicRhsIndex);
                        dynFunc.ClassIndex = procCallNode.classScope;
                    }
                }
                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 == AssociativeSubCompilePass.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.list.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)
                    {
                        GraphNode dependentNode = new GraphNode();
                        dependentNode.PushSymbolReference(symbolnode);
                        graphNode.PushDependent(dependentNode);
                    }
                }
            }

            // 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 = core.GetFirstVisibleProcedure(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(WarningMessage.kMethodIsInaccessible, procName);
                            buildStatus.LogWarning(WarningID.kAccessViolation, message, core.CurrentDSFileName, funcCall.line, funcCall.col, guid);

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

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

                var procNode = core.GetFirstVisibleProcedure(Constants.kDotMethodName, null, 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].vtable.procList[globalProcIndex];
                    if (contextProcNode.isConstructor &&
                        string.Equals(contextProcNode.name, procCallNode.name) &&
                        contextProcNode.runtimeIndex == procCallNode.runtimeIndex)
                    {
                        string message = String.Format(WarningMessage.kCallingConstructorInConstructor, procName);
                        buildStatus.LogWarning(WarningID.kCallingConstructorInConstructor, message, core.CurrentDSFileName, node.line, node.col, guid);
                        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.classScope, arglist, procCallNode, funcCall, isGetter, bnode);
                }
                else
                {
                    var procNode = core.GetFirstVisibleProcedure(Constants.kDotMethodName, null, 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;
            }
        }
Exemplo n.º 6
0
        protected void EmitStringNode(
            Node node, 
            ref Type inferedType, 
            AssociativeGraph.GraphNode graphNode = null,
            AssociativeSubCompilePass subPass = AssociativeSubCompilePass.kNone)
        {
            if (subPass == AssociativeSubCompilePass.kUnboundIdentifier)
            {
                return;
            }

            dynamic sNode = node;
            if (!enforceTypeCheck || core.TypeSystem.IsHigherRank((int)PrimitiveType.kTypeString, inferedType.UID))
            {
                inferedType.UID = (int)PrimitiveType.kTypeString;
            }

            Byte[] utf8bytes = EncodingUtils.UTF8StringToUTF8Bytes((String)sNode.value);
            String value = Encoding.UTF8.GetString(utf8bytes);

            foreach (char ch in value)
            {
                String strValue = "'" + ch + "'";
                EmitInstrConsole(kw.push, strValue);

                StackValue op = StackValue.BuildChar(ch);
                EmitPush(op, node.line, node.col);
            }

            if (IsAssociativeArrayIndexing && graphNode != null && graphNode.isIndexingLHS)
            {
                SymbolNode literalSymbol = new SymbolNode();
                literalSymbol.name = value;

                var dimNode = new AssociativeGraph.UpdateNode();
                dimNode.symbol = literalSymbol;
                dimNode.nodeType = AssociativeGraph.UpdateNodeType.kLiteral;

                graphNode.dimensionNodeList.Add(dimNode);
            }

            EmitInstrConsole(kw.alloca, value.Length.ToString());
            EmitPopString(value.Length);
        }