// TODO Jun: Merge TraverseFunctionCall with the associative version and implement in a codegen utils file //Fuqiang: Cannot merge the two functions. They are different. eg. Associative has "emitReplicationGuide = false;" public override void 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) { 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); 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.AssociativeAST.IdentifierListNode) { ProtoCore.AST.Node leftnode = (parentNode as ProtoCore.AST.AssociativeAST.IdentifierListNode).LeftNode; if (leftnode != null && leftnode is ProtoCore.AST.AssociativeAST.IdentifierNode) { refClassIndex = compileState.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 (inferedType.UID > (int)PrimitiveType.kMaxPrimitives) { //check if it is function pointer ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAllocated = VerifyAllocation(procName, inferedType.UID, out symbolnode, out isAccessible); if (isAllocated) { procName = ProtoCore.DSASM.Constants.kFunctionPointerCall; } } if (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { procNode = compileState.ClassTable.ClassNodes[inferedType.UID].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType); if (procNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); isConstructor = procNode.isConstructor; isStatic = procNode.isStatic; type = lefttype = realType; if ((refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && !procNode.isStatic && !procNode.isConstructor) { return; } if (!isAccessible) { type = lefttype = realType; hasLogError = true; } } } } if (!isConstructor && !isStatic && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { //check if it is function pointer bool isAccessibleFp; ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAllocated = VerifyAllocation(procName, globalClassIndex, out symbolnode, out isAccessibleFp); if (isAllocated) // not checking the type against function pointer, as the type could be var { procName = ProtoCore.DSASM.Constants.kFunctionPointerCall; } else { procNode = compileState.GetFirstVisibleProcedure(procName, arglist, codeBlock); if (null != procNode) { if ((int)ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { // A global function if (compileState.TypeSystem.IsHigherRank((int)procNode.returntype.UID, inferedType.UID)) { inferedType = procNode.returntype; } } else { procNode = null; } } else { type = (lefttype != ProtoCore.DSASM.Constants.kInvalidIndex) ? lefttype : globalClassIndex; if (type != ProtoCore.DSASM.Constants.kInvalidIndex) { int realType; bool isAccessible; ProtoCore.DSASM.ProcedureNode memProcNode = compileState.ClassTable.ClassNodes[type].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType); if (memProcNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); procNode = memProcNode; inferedType = procNode.returntype; type = realType; if ((refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && !procNode.isStatic && !procNode.isConstructor) { inferedType.UID = (int)PrimitiveType.kTypeNull; return; } if (!isAccessible) { procNode = null; if (!hasLogError) { hasLogError = true; } } } } } } } if (null != procNode) { //if call is replication call if (procNode.isThisCallReplication) { inferedType.IsIndexable = true; inferedType.rank++; } } else { if (depth <= 0 && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { inferedType.UID = (int)PrimitiveType.kTypeNull; } else { if (procName == ProtoCore.DSASM.Constants.kFunctionPointerCall && depth == 0) { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(procName, arglist, lefttype); compileState.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); IdentifierNode iNode = new IdentifierNode() { Value = funcCall.Function.Name, Name = funcCall.Function.Name, datatype = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, false) }; EmitIdentifierNode(iNode, ref inferedType); } else { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(funcCall.Function.Name, arglist, lefttype); compileState.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); } //assign inferedType to var inferedType.UID = (int)PrimitiveType.kTypeVar; } } }
public override void 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) { FunctionCallNode funcCall = node as FunctionCallNode; string procName = funcCall.Function.Name; List<ProtoCore.Type> arglist = new List<ProtoCore.Type>(); ProtoCore.Type dotCallType = new ProtoCore.Type(); dotCallType.UID = (int)PrimitiveType.kTypeVar; dotCallType.IsIndexable = false; if (procName == "%dot") { if (funcCall.FormalArguments[0] is IdentifierNode) { int ci = core.ClassTable.IndexOf((funcCall.FormalArguments[0] as IdentifierNode).Name); if (ci != ProtoCore.DSASM.Constants.kInvalidIndex) { funcCall.FormalArguments[0] = new IntNode() { value = ci.ToString() }; dotCallType.UID = ci; } if (funcCall.FormalArguments.Count > 4) { int dynamicRhsIndex = int.Parse((funcCall.FormalArguments[1] as IntNode).value); core.DynamicFunctionTable.functionTable[dynamicRhsIndex].classIndex = globalClassIndex; } else if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool isAllocated = VerifyAllocation((funcCall.FormalArguments[0] as IdentifierNode).Name, globalClassIndex, out symbolnode, out isAccessible); if (isAllocated && symbolnode.datatype.UID != (int)PrimitiveType.kTypeVar) { int rhsIndex = int.Parse((funcCall.FormalArguments[1] as IntNode).value); string rhsName = core.DynamicVariableTable.variableTable[rhsIndex].variableName; isAllocated = VerifyAllocation(rhsName, symbolnode.datatype.UID, out symbolnode, out isAccessible); if (null == symbolnode) //unbound identifier { if (isAllocated && !isAccessible) { ProtoCore.Type leftType = new ProtoCore.Type(); leftType.UID = (int)PrimitiveType.kInvalidType; leftType.IsIndexable = false; bool isFirstIdent = true; DfsEmitIdentList(funcCall.FormalArguments[0], null, globalClassIndex, ref leftType, ref depth, ref inferedType, false, ref isFirstIdent, graphNode, subPass); inferedType.UID = (int)PrimitiveType.kTypeNull; return; } } } } } else if (funcCall.FormalArguments[0] is IntNode) { dotCallType.UID = int.Parse((funcCall.FormalArguments[0] as IntNode).value); } } foreach (AssociativeNode paramNode in funcCall.FormalArguments) { ProtoCore.Type paramType = new ProtoCore.Type(); paramType.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; paramType.IsIndexable = false; //emitReplicationGuide = paramNode is IdentifierNode || paramNode is ExprListNode; // 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); enforceTypeCheck = true; arglist.Add(paramType); } if (subPass == ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { return; } 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.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 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 (inferedType.UID > (int)PrimitiveType.kMaxPrimitives) { //check if it is function pointer ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAllocated = VerifyAllocation(procName, inferedType.UID, out symbolnode, out isAccessible); if (isAllocated) { procName = ProtoCore.DSASM.Constants.kFunctionPointerCall; } } if (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { procNode = core.ClassTable.ClassNodes[inferedType.UID].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType); if (procNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); isConstructor = procNode.isConstructor; isStatic = procNode.isStatic; type = lefttype = realType; if ((refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && !procNode.isStatic && !procNode.isConstructor) { inferedType.UID = (int)PrimitiveType.kTypeNull; return; } if (!isAccessible) { type = lefttype = realType; procNode = null; hasLogError = true; } } } } if (!isConstructor && !isStatic && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { //check if it is function pointer bool isAccessibleFp; ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAllocated = VerifyAllocation(procName, globalClassIndex, out symbolnode, out isAccessibleFp); if (isAllocated) // not checking the type against function pointer, as the type could be var { procName = ProtoCore.DSASM.Constants.kFunctionPointerCall; } else { procNode = core.GetFirstVisibleProcedure(procName, arglist, codeBlock); if (null != procNode) { if ((int)ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { // A global function if (core.TypeSystem.IsHigherRank((int)procNode.returntype.UID, inferedType.UID)) { inferedType = procNode.returntype; } } else { procNode = null; } } else { type = (lefttype != ProtoCore.DSASM.Constants.kInvalidIndex) ? lefttype : globalClassIndex; if (type != ProtoCore.DSASM.Constants.kInvalidIndex) { int realType; bool isAccessible; ProtoCore.DSASM.ProcedureNode memProcNode = core.ClassTable.ClassNodes[type].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType); if (memProcNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); procNode = memProcNode; inferedType = procNode.returntype; type = realType; if ((refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && !procNode.isStatic && !procNode.isConstructor) { inferedType.UID = (int)PrimitiveType.kTypeNull; return; } if (!isAccessible) { procNode = null; if (!hasLogError) { hasLogError = true; } } } } } } } if (null != procNode) { //if call is replication call if (procNode.isThisCallReplication) { inferedType.IsIndexable = true; inferedType.rank++; } if ((int)ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { if (dotCallType.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = dotCallType.UID; } } } else { if (depth <= 0 && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { // At compile time we only check if function name and the number of parameter are // both matched, so if it is a global function call but we still can't get procNode, // it is hopeless to resolve that at run-time. Then we should return null. -yu ke inferedType.UID = (int)PrimitiveType.kTypeNull; } 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); IdentifierNode iNode = new IdentifierNode() { Value = funcCall.Function.Name, Name = funcCall.Function.Name, datatype = core.TypeSystem.BuildTypeObject(PrimitiveType.kTypeVar, false) }; EmitIdentifierNode(iNode, ref inferedType); } else { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(funcCall.Function.Name, arglist, lefttype); core.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); } inferedType.UID = (int)PrimitiveType.kTypeVar; } } }