public override ProtoCore.DSASM.ProcedureNode TraverseFunctionCall(ProtoCore.AST.Node node, ProtoCore.AST.Node parentNode, int lefttype, int depth, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, ProtoCore.AST.Node bnode = null) { if (!IsParsingGlobal() && !IsParsingGlobalFunctionBody()) { return null; } //Debug.Assert(null == graphNode); FunctionCallNode funcCall = node as FunctionCallNode; string procName = funcCall.Function.Name; List<ProtoCore.Type> arglist = new List<ProtoCore.Type>(); foreach (ImperativeNode paramNode in funcCall.FormalArguments) { ProtoCore.Type paramType = new ProtoCore.Type(); paramType.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; paramType.IsIndexable = 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); DfsTraverse(paramNode, ref paramType, false, graphNode, AssociativeSubCompilePass.kNone, bnode); enforceTypeCheck = true; arglist.Add(paramType); } ProtoCore.DSASM.ProcedureNode procNode = null; int type = ProtoCore.DSASM.Constants.kInvalidIndex; bool isConstructor = false; bool isStatic = false; bool hasLogError = false; int refClassIndex = ProtoCore.DSASM.Constants.kInvalidIndex; if (parentNode != null && parentNode is ProtoCore.AST.ImperativeAST.IdentifierListNode) { ProtoCore.AST.Node leftnode = (parentNode as ProtoCore.AST.ImperativeAST.IdentifierListNode).LeftNode; if (leftnode != null && leftnode is ProtoCore.AST.ImperativeAST.IdentifierNode) { refClassIndex = compileStateTracker.ClassTable.IndexOf(leftnode.Name); } } // 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) { bool isAccessible; int realType; if (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex; procNode = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (procNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); isConstructor = procNode.isConstructor; isStatic = procNode.isStatic; type = lefttype = realType; if (!isAccessible) { type = lefttype = realType; string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); hasLogError = true; } } // To support unamed constructor, x = A(); else if (refClassIndex != Constants.kInvalidIndex) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticMethod, compileStateTracker.ClassTable.ClassNodes[refClassIndex].name, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return null; } else { int classIndex = compileStateTracker.ClassTable.IndexOf(procName); int dummy; if (classIndex != Constants.kInvalidIndex) { procNode = compileStateTracker.ClassTable.ClassNodes[classIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out dummy, true); if (procNode != null && procNode.isConstructor) { type = classIndex; } else { procNode = null; } } } } } // Try function pointer firstly if ((procNode == 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 ((procNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)) { procNode = compileStateTracker.GetFirstVisibleProcedure(procName, arglist, codeBlock); if (null != procNode) { type = ProtoCore.DSASM.Constants.kGlobalScope; if (compileStateTracker.TypeSystem.IsHigherRank(procNode.returntype.UID, inferedType.UID)) { inferedType = procNode.returntype; } } } // Try member functions in global class scope if ((procNode == 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 = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (memProcNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); procNode = memProcNode; inferedType = procNode.returntype; type = realType; if (!isAccessible) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return null; } } } } if (null != procNode) { inferedType = procNode.returntype; //if call is replication call if (procNode.isThisCallReplication) { inferedType.IsIndexable = true; inferedType.rank++; } if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { // 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 // Jun TODO: Implementeation of indexing into a function call: // x = f()[0][1] int dimensions = 0; EmitPushVarData(blockId, dimensions); // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, procNode.name); DebugProperties.BreakpointOptions oldOptions = compileStateTracker.DebugProps.breakOptions; if(procNode.name.StartsWith(Constants.kSetterPrefix)) { EmitCall(procNode.procId, type, depth, parentNode.line, parentNode.col, parentNode.endLine, parentNode.endCol); } /*else if(procNode.isExternal) { EmitCall(procNode.procId, type, depth); }*/ else if (bnode != null) { EmitCall(procNode.procId, type, depth, bnode.line, bnode.col, bnode.endLine, bnode.endCol); } else if (!procNode.name.Equals(Constants.kFunctionRangeExpression) || oldOptions.HasFlag(DebugProperties.BreakpointOptions.EmitCallrForTempBreakpoint)) { EmitCall(procNode.procId, type, depth, node.line, node.col, node.endLine, node.endCol); } else { EmitCall(procNode.procId, type, depth); } EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); } } else { if (depth <= 0 && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { if (!hasLogError) { if (!compileStateTracker.Options.SuppressFunctionResolutionWarning || parentNode == null) { string property; if (CoreUtils.TryGetPropertyName(procName, out property)) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kPropertyNotFound, property); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kPropertyNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodNotFound, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } } inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); } } else { if (procName == ProtoCore.DSASM.Constants.kFunctionPointerCall && depth == 0) { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(procName, arglist, lefttype); compileStateTracker.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); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); } // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, funcCall.Function.Name + "[dynamic]"); EmitDynamicCall(compileStateTracker.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); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); //assign inferedType to var inferedType.UID = (int)PrimitiveType.kTypeVar; } } return procNode; }
public ProtoCore.DSASM.ProcedureNode TraverseDotFunctionCall(ProtoCore.AST.Node node, ProtoCore.AST.Node parentNode, int lefttype, int depth, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, ProtoCore.AST.AssociativeAST.BinaryExpressionNode bnode = null) { FunctionCallNode funcCall = null; ProtoCore.DSASM.ProcedureNode procCallNode = null; ProtoCore.DSASM.ProcedureNode procDotCallNode = null; string procName = null; List<ProtoCore.Type> arglist = new List<ProtoCore.Type>(); ProtoCore.Type dotCallType = new ProtoCore.Type(); dotCallType.UID = (int)PrimitiveType.kTypeVar; dotCallType.IsIndexable = false; bool isConstructor = false; bool isStaticCall = false; bool isStaticCallAllowed = false; bool isUnresolvedDot = false; bool isUnresolvedMethod = false; int classIndex = ProtoCore.DSASM.Constants.kInvalidIndex; string className = string.Empty; ProtoCore.AST.AssociativeAST.FunctionDotCallNode dotCall = node as ProtoCore.AST.AssociativeAST.FunctionDotCallNode; funcCall = dotCall.DotCall; procName = dotCall.FunctionCall.Function.Name; List<AssociativeNode> replicationGuide = (dotCall.FunctionCall.Function as IdentifierNode).ReplicationGuides; var dotCallFirstArgument = dotCall.DotCall.FormalArguments[0]; if (dotCallFirstArgument is FunctionDotCallNode) { isUnresolvedDot = true; } else if (dotCallFirstArgument is IdentifierNode || dotCallFirstArgument is ThisPointerNode) { // Check if the lhs identifer is a class name string lhsName = ""; int ci = Constants.kInvalidIndex; if (dotCallFirstArgument is IdentifierNode) { lhsName = (dotCallFirstArgument as IdentifierNode).Name; ci = compileStateTracker.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 = ""; } } } } if (ci != ProtoCore.DSASM.Constants.kInvalidIndex) { // It is a class name dotCall.DotCall.FormalArguments[0] = new IntNode { value = ci.ToString() }; dotCallFirstArgument = 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) { ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.ClassTable.ClassNodes[ci].GetFirstStaticMemberFunction(procName); if (null != staticProcCallNode) { procCallNode = staticProcCallNode; } } isStaticCallAllowed = procCallNode.isStatic && isStaticCall; } else { ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.ClassTable.ClassNodes[ci].GetFirstStaticMemberFunction(procName); string functionName = dotCall.FunctionCall.Function.Name; string property; if (null != staticProcCallNode) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodHasInvalidArguments, functionName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else if (CoreUtils.TryGetPropertyName(functionName, out property)) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticProperty, lhsName, property); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticMethod, lhsName, functionName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } } } if (dotCall.DotCall.FormalArguments.Count == ProtoCore.DSASM.Constants.kDotCallArgCount) { if (dotCallFirstArgument is IdentifierNode) { ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool isAllocated = VerifyAllocation((dotCallFirstArgument as IdentifierNode).Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); if (isAllocated && symbolnode.datatype.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = symbolnode.datatype.UID; if (ProtoCore.DSASM.Constants.kInvalidIndex != inferedType.UID) { procCallNode = GetProcedureFromInstance(symbolnode.datatype.UID, dotCall.FunctionCall); } if (null != procCallNode) { if (procCallNode.isConstructor) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { // A constructor cannot be called from an instance string message = String.Format(ProtoCore.BuildData.WarningMessage.KCallingConstructorOnInstance, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingConstructorOnInstance, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } isUnresolvedDot = true; isUnresolvedMethod = true; } else { isAccessible = procCallNode.access == ProtoCore.DSASM.AccessSpecifier.kPublic || (procCallNode.access == ProtoCore.DSASM.AccessSpecifier.kPrivate && procCallNode.classScope == globalClassIndex); if (!isAccessible) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } } if (null != procCallNode) { int dynamicRhsIndex = int.Parse((dotCall.DotCall.FormalArguments[1] as IntNode).value); compileStateTracker.DynamicFunctionTable.functionTable[dynamicRhsIndex].classIndex = procCallNode.classScope; compileStateTracker.DynamicFunctionTable.functionTable[dynamicRhsIndex].procedureIndex = procCallNode.procId; compileStateTracker.DynamicFunctionTable.functionTable[dynamicRhsIndex].pc = procCallNode.pc; } } } } else { isUnresolvedDot = true; } } else if (dotCallFirstArgument is ThisPointerNode) { if (globalClassIndex != Constants.kInvalidIndex) { procCallNode = GetProcedureFromInstance(globalClassIndex, dotCall.FunctionCall); if (null != procCallNode && procCallNode.isConstructor) { dotCall.DotCall.FormalArguments[0] = new IntNode { value = globalClassIndex.ToString() }; dotCallFirstArgument = dotCall.DotCall.FormalArguments[0]; inferedType.UID = dotCallType.UID = ci; } } } } } else if (funcCall.FormalArguments[0] is IntNode) { inferedType.UID = dotCallType.UID = int.Parse((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 = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetFirstStaticMemberFunction(procName); if (null != staticProcCallNode) { procCallNode = staticProcCallNode; } } isStaticCallAllowed = procCallNode.isStatic && isStaticCall; className = compileStateTracker.ClassTable.ClassNodes[dotCallType.UID].name; if (isStaticCall && !isStaticCallAllowed) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { string property; className = compileStateTracker.ClassTable.ClassNodes[dotCallType.UID].name; ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.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, compileStateTracker.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, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticMethod, procName, className); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.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 = new ProtoCore.Type(); paramType.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; paramType.IsIndexable = false; 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; // 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 { 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 (compileStateTracker.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) { ProtoCore.AST.AssociativeAST.IntNode argNumNode = new ProtoCore.AST.AssociativeAST.IntNode() { value = funtionArgCount.ToString() }; 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 = compileStateTracker.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 = compileStateTracker.ClassTable.IndexOf(leftnode.Name); } } if (dotCallFirstArgument is FunctionCallNode || dotCallFirstArgument is FunctionDotCallNode || dotCallFirstArgument 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 = compileStateTracker.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 = compileStateTracker.GetFirstVisibleProcedure(procName, arglist, codeBlock); if (null != procCallNode) { type = ProtoCore.DSASM.Constants.kGlobalScope; if (compileStateTracker.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 = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (memProcNode != null) { Debug.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, compileStateTracker.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 = compileStateTracker.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 = compileStateTracker.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, compileStateTracker.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.IsIndexable = true; inferedType.rank++; } // Get the dot call procedure ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode; if (!isConstructor && !isStaticCall) { procNode = compileStateTracker.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) { 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 (!compileStateTracker.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, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodNotFound, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } } inferedType.UID = (int)PrimitiveType.kTypeNull; } // Get the dot call procedure ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode; if (!isConstructor && !isStaticCall) { procNode = compileStateTracker.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); compileStateTracker.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); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); } // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, funcCall.Function.Name + "[dynamic]"); EmitDynamicCall(compileStateTracker.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); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); if (compileStateTracker.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; }
public static ProtoCore.AST.AssociativeAST.FunctionDotCallNode GenerateCallDotNode(ProtoCore.AST.AssociativeAST.AssociativeNode lhs, ProtoCore.AST.AssociativeAST.FunctionCallNode rhsCall, ProtoLanguage.CompileStateTracker compileState = null) { // The function name to call string rhsName = rhsCall.Function.Name; int argNum = rhsCall.FormalArguments.Count; ProtoCore.AST.AssociativeAST.ExprListNode argList = new ProtoCore.AST.AssociativeAST.ExprListNode(); foreach (ProtoCore.AST.AssociativeAST.AssociativeNode arg in rhsCall.FormalArguments) { // The function arguments argList.list.Add(arg); } ProtoCore.AST.AssociativeAST.FunctionCallNode funCallNode = new ProtoCore.AST.AssociativeAST.FunctionCallNode(); ProtoCore.AST.AssociativeAST.IdentifierNode funcName = new ProtoCore.AST.AssociativeAST.IdentifierNode { Value = ProtoCore.DSASM.Constants.kDotArgMethodName, Name = ProtoCore.DSASM.Constants.kDotArgMethodName }; funCallNode.Function = funcName; funCallNode.Name = ProtoCore.DSASM.Constants.kDotArgMethodName; NodeUtils.CopyNodeLocation(funCallNode, lhs); int rhsIdx = ProtoCore.DSASM.Constants.kInvalidIndex; string lhsName = null; if (lhs is ProtoCore.AST.AssociativeAST.IdentifierNode) { lhsName = (lhs as ProtoCore.AST.AssociativeAST.IdentifierNode).Name; if (lhsName == ProtoCore.DSDefinitions.Keyword.This) { lhs = new ProtoCore.AST.AssociativeAST.ThisPointerNode(); } } if (compileState != null) { if (argNum >= 0) { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(rhsName, new List<ProtoCore.Type>()); compileState.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); rhsIdx = compileState.DynamicFunctionTable.functionTable.Count - 1; } else { DSASM.DyanmicVariableNode dynamicVariableNode = new DSASM.DyanmicVariableNode(rhsName); compileState.DynamicVariableTable.variableTable.Add(dynamicVariableNode); rhsIdx = compileState.DynamicVariableTable.variableTable.Count - 1; } } // The first param to the dot arg (the pointer or the class name) ProtoCore.AST.AssociativeAST.IntNode rhs = new ProtoCore.AST.AssociativeAST.IntNode() { value = rhsIdx.ToString() }; funCallNode.FormalArguments.Add(lhs); // The second param which is the dynamic table index of the function to call funCallNode.FormalArguments.Add(rhs); // The array dimensions ProtoCore.AST.AssociativeAST.ExprListNode arrayDimExperList = new ProtoCore.AST.AssociativeAST.ExprListNode(); int dimCount = 0; if (rhsCall.Function is ProtoCore.AST.AssociativeAST.IdentifierNode) { // Number of dimensions ProtoCore.AST.AssociativeAST.IdentifierNode fIdent = rhsCall.Function as ProtoCore.AST.AssociativeAST.IdentifierNode; if (fIdent.ArrayDimensions != null) { arrayDimExperList = ProtoCore.Utils.CoreUtils.BuildArrayExprList(fIdent.ArrayDimensions); dimCount = arrayDimExperList.list.Count; } else if (rhsCall.ArrayDimensions != null) { arrayDimExperList = ProtoCore.Utils.CoreUtils.BuildArrayExprList(rhsCall.ArrayDimensions); dimCount = arrayDimExperList.list.Count; } else { arrayDimExperList = new ProtoCore.AST.AssociativeAST.ExprListNode(); } } funCallNode.FormalArguments.Add(arrayDimExperList); // Number of dimensions ProtoCore.AST.AssociativeAST.IntNode dimNode = new ProtoCore.AST.AssociativeAST.IntNode() { value = dimCount.ToString() }; funCallNode.FormalArguments.Add(dimNode); if (argNum >= 0) { funCallNode.FormalArguments.Add(argList); funCallNode.FormalArguments.Add(new ProtoCore.AST.AssociativeAST.IntNode() { value = argNum.ToString() }); } ProtoCore.AST.AssociativeAST.FunctionDotCallNode funDotCallNode = new ProtoCore.AST.AssociativeAST.FunctionDotCallNode(rhsCall); funDotCallNode.DotCall = funCallNode; funDotCallNode.FunctionCall.Function = rhsCall.Function; // Consider the case of "myClass.Foo(a, b)", we will have "DotCall" being // equal to "myClass" (in terms of its starting line/column), and "rhsCall" // matching with the location of "Foo(a, b)". For execution cursor to cover // this whole statement, the final "DotCall" function call node should // range from "lhs.col" to "rhs.col". // NodeUtils.SetNodeEndLocation(funDotCallNode.DotCall, rhsCall); NodeUtils.CopyNodeLocation(funDotCallNode, funDotCallNode.DotCall); return funDotCallNode; }
public override ProtoCore.DSASM.ProcedureNode TraverseFunctionCall(ProtoCore.AST.Node node, ProtoCore.AST.Node parentNode, int lefttype, int depth, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, ProtoCore.AST.Node bnode = null) { FunctionCallNode funcCall = null; string procName = null; List<ProtoCore.Type> arglist = new List<ProtoCore.Type>(); ProtoCore.Type dotCallType = new ProtoCore.Type(); dotCallType.UID = (int)PrimitiveType.kTypeVar; dotCallType.IsIndexable = false; ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode(); if (node is ProtoCore.AST.AssociativeAST.FunctionDotCallNode) { return TraverseDotFunctionCall(node, parentNode, lefttype, depth, ref inferedType, graphNode, subPass, bnode as BinaryExpressionNode); } else { funcCall = node as FunctionCallNode; procName = funcCall.Function.Name; int classIndex = compileStateTracker.ClassTable.IndexOf(procName); bool isAccessible; int dummy; // To support unamed constructor if (classIndex != Constants.kInvalidIndex) { ProcedureNode constructor = compileStateTracker.ClassTable.ClassNodes[classIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out dummy, true); if (constructor != null && constructor.isConstructor) { FunctionCallNode rhsFNode = node as ProtoCore.AST.AssociativeAST.FunctionCallNode; AssociativeNode classNode = nodeBuilder.BuildIdentfier(procName); FunctionDotCallNode dotCallNode = ProtoCore.Utils.CoreUtils.GenerateCallDotNode(classNode, rhsFNode, compileStateTracker); return TraverseDotFunctionCall(dotCallNode, parentNode, lefttype, depth, ref inferedType, graphNode, subPass, bnode as BinaryExpressionNode); } } } foreach (AssociativeNode paramNode in funcCall.FormalArguments) { ProtoCore.Type paramType = new ProtoCore.Type(); paramType.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; paramType.IsIndexable = false; // The range expression function does not need replication guides emitReplicationGuide = !procName.Equals(ProtoCore.DSASM.Constants.kFunctionRangeExpression); // 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 == ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { return null; } ProtoCore.DSASM.ProcedureNode procNode = null; 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 = compileStateTracker.ClassTable.IndexOf(leftnode.Name); } } // Check for the actual method, not the dot method // 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 isAccessible; int realType; bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex; procNode = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (procNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); type = lefttype = realType; if (!isAccessible) { type = lefttype = realType; procNode = null; string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procNode; } } } // Try function pointer firstly if ((procNode == 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 ((procNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)) { procNode = compileStateTracker.GetFirstVisibleProcedure(procName, arglist, codeBlock); if (null != procNode) { type = ProtoCore.DSASM.Constants.kGlobalScope; if (compileStateTracker.TypeSystem.IsHigherRank(procNode.returntype.UID, inferedType.UID)) { inferedType = procNode.returntype; } } } // Try member functions in global class scope if ((procNode == 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 = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (memProcNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); procNode = memProcNode; inferedType = procNode.returntype; type = realType; if (!isAccessible) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procNode; } } } } if (null != procNode) { if (procNode.isConstructor && (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && (globalProcIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && (globalClassIndex == inferedType.UID)) { ProtoCore.DSASM.ProcedureNode contextProcNode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; if (contextProcNode.isConstructor && string.Equals(contextProcNode.name, procNode.name) && contextProcNode.runtimeIndex == procNode.runtimeIndex) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingConstructorInConstructor, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingConstructorInConstructor, message, compileStateTracker.CurrentDSFileName, node.line, node.col ); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procNode; } } inferedType = procNode.returntype; //if call is replication call if (procNode.isThisCallReplication) { inferedType.IsIndexable = true; inferedType.rank++; } if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { // // ==============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; ProtoCore.AssociativeGraph.UpdateNodeRef argNodeRef = new ProtoCore.AssociativeGraph.UpdateNodeRef(); DFSGetSymbolList(paramNode, ref ltype, argNodeRef); if (null != graphNode) { 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(ProtoCore.DSASM.kw.callr, procNode.name); // Do not emit breakpoints at built-in methods like _add/_sub etc. - pratapa if (procNode.isAssocOperator || procNode.name.Equals(ProtoCore.DSASM.Constants.kInlineConditionalMethodName)) { EmitCall(procNode.procId, type, depth, ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.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 (compileStateTracker.DebugProps.breakOptions.HasFlag(DebugProperties.BreakpointOptions.EmitInlineConditionalBreakpoint)) { Validity.Assert(compileStateTracker.DebugProps.highlightRange != null); ProtoCore.CodeModel.CodePoint startInclusive = compileStateTracker.DebugProps.highlightRange.StartInclusive; ProtoCore.CodeModel.CodePoint endExclusive = compileStateTracker.DebugProps.highlightRange.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(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); if (dotCallType.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = dotCallType.UID; } } } 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, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodNotFound, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); } else { if (procName == ProtoCore.DSASM.Constants.kFunctionPointerCall && depth == 0) { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(procName, arglist, lefttype); compileStateTracker.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); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); } // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, funcCall.Function.Name + "[dynamic]"); EmitDynamicCall(compileStateTracker.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); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); //assign inferedType to var inferedType.UID = (int)PrimitiveType.kTypeVar; } } return procNode; }
public static ProtoCore.AST.AssociativeAST.FunctionDotCallNode GenerateCallDotNode(ProtoCore.AST.AssociativeAST.AssociativeNode lhs, ProtoCore.AST.AssociativeAST.FunctionCallNode rhsCall, Core core = null) { // The function name to call string rhsName = rhsCall.Function.Name; int argNum = rhsCall.FormalArguments.Count; ProtoCore.AST.AssociativeAST.ExprListNode argList = new ProtoCore.AST.AssociativeAST.ExprListNode(); foreach (ProtoCore.AST.AssociativeAST.AssociativeNode arg in rhsCall.FormalArguments) { // The function arguments argList.list.Add(arg); } ProtoCore.AST.AssociativeAST.FunctionCallNode funCallNode = new ProtoCore.AST.AssociativeAST.FunctionCallNode(); ProtoCore.AST.AssociativeAST.IdentifierNode funcName = new ProtoCore.AST.AssociativeAST.IdentifierNode { Value = ProtoCore.DSASM.Constants.kDotArgMethodName, Name = ProtoCore.DSASM.Constants.kDotArgMethodName }; funCallNode.Function = funcName; funCallNode.Name = ProtoCore.DSASM.Constants.kDotArgMethodName; NodeUtils.CopyNodeLocation(funCallNode, lhs); int rhsIdx = ProtoCore.DSASM.Constants.kInvalidIndex; string lhsName = null; if (lhs is ProtoCore.AST.AssociativeAST.IdentifierNode) { lhsName = (lhs as ProtoCore.AST.AssociativeAST.IdentifierNode).Name; if (lhsName == ProtoCore.DSDefinitions.Kw.kw_this) { lhs = new ProtoCore.AST.AssociativeAST.ThisPointerNode(); } } if (core != null) { if (argNum >= 0) { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(rhsName, new List <ProtoCore.Type>()); core.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); rhsIdx = core.DynamicFunctionTable.functionTable.Count - 1; } else { DSASM.DyanmicVariableNode dynamicVariableNode = new DSASM.DyanmicVariableNode(rhsName); core.DynamicVariableTable.variableTable.Add(dynamicVariableNode); rhsIdx = core.DynamicVariableTable.variableTable.Count - 1; } } // The first param to the dot arg (the pointer or the class name) ProtoCore.AST.AssociativeAST.IntNode rhs = new ProtoCore.AST.AssociativeAST.IntNode() { value = rhsIdx.ToString() }; funCallNode.FormalArguments.Add(lhs); // The second param which is the dynamic table index of the function to call funCallNode.FormalArguments.Add(rhs); // The array dimensions ProtoCore.AST.AssociativeAST.ExprListNode arrayDimExperList = new ProtoCore.AST.AssociativeAST.ExprListNode(); int dimCount = 0; if (rhsCall.Function is ProtoCore.AST.AssociativeAST.IdentifierNode) { // Number of dimensions ProtoCore.AST.AssociativeAST.IdentifierNode fIdent = rhsCall.Function as ProtoCore.AST.AssociativeAST.IdentifierNode; if (fIdent.ArrayDimensions != null) { arrayDimExperList = ProtoCore.Utils.CoreUtils.BuildArrayExprList(fIdent.ArrayDimensions); dimCount = arrayDimExperList.list.Count; } else if (rhsCall.ArrayDimensions != null) { arrayDimExperList = ProtoCore.Utils.CoreUtils.BuildArrayExprList(rhsCall.ArrayDimensions); dimCount = arrayDimExperList.list.Count; } else { arrayDimExperList = new ProtoCore.AST.AssociativeAST.ExprListNode(); } } funCallNode.FormalArguments.Add(arrayDimExperList); // Number of dimensions ProtoCore.AST.AssociativeAST.IntNode dimNode = new ProtoCore.AST.AssociativeAST.IntNode() { value = dimCount.ToString() }; funCallNode.FormalArguments.Add(dimNode); if (argNum >= 0) { funCallNode.FormalArguments.Add(argList); funCallNode.FormalArguments.Add(new ProtoCore.AST.AssociativeAST.IntNode() { value = argNum.ToString() }); } ProtoCore.AST.AssociativeAST.FunctionDotCallNode funDotCallNode = new ProtoCore.AST.AssociativeAST.FunctionDotCallNode(rhsCall); funDotCallNode.DotCall = funCallNode; funDotCallNode.FunctionCall.Function = rhsCall.Function; // Consider the case of "myClass.Foo(a, b)", we will have "DotCall" being // equal to "myClass" (in terms of its starting line/column), and "rhsCall" // matching with the location of "Foo(a, b)". For execution cursor to cover // this whole statement, the final "DotCall" function call node should // range from "lhs.col" to "rhs.col". // NodeUtils.SetNodeEndLocation(funDotCallNode.DotCall, rhsCall); NodeUtils.CopyNodeLocation(funDotCallNode, funDotCallNode.DotCall); return(funDotCallNode); }