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