/// <summary> /// API used by external host to build AST for any function call /// </summary> /// <param name="type"></param> /// <param name="hostInstancePtr"></param> /// <param name="functionName"></param> /// <param name="userDefinedArgs"></param> /// <param name="primitiveArgs"></param> /// <param name="formatString"></param> /// <param name="core"></param> /// <param name="symbolName"></param> /// <param name="code"></param> /// <returns></returns> public static AssociativeNode BuildAST(string type, long hostInstancePtr, string functionName, List <IntPtr> userDefinedArgs, List <string> primitiveArgs, string formatString, ProtoCore.Core core, ref string symbolName, ref string code) { symbolName = string.Empty; List <AssociativeNode> astNodes = new List <AssociativeNode>(); FunctionDotCallNode dotCall = null; BinaryExpressionNode bNode = null; ProtoCore.AST.AssociativeAST.FunctionDotCallNode dotCallNode = null; List <AssociativeNode> argNodes = new List <AssociativeNode>(); if (userDefinedArgs != null) { foreach (var arg in userDefinedArgs) { dotCallNode = CreateEntityNode((long)arg, core); bNode = CreateAssignmentNode(dotCallNode); argNodes.Add(bNode); } astNodes.AddRange(argNodes); } List <ProtoCore.AST.AssociativeAST.AssociativeNode> args = CreateArgs(formatString, primitiveArgs, argNodes); if (hostInstancePtr != 0) { dotCallNode = CreateEntityNode(hostInstancePtr, core); bNode = CreateAssignmentNode(dotCallNode); astNodes.Add(bNode); dotCall = CreateFunctionCallNode((bNode.LeftNode as IdentifierNode).Value, functionName, args, core); } else { dotCall = CreateFunctionCallNode(type, functionName, args, core); } bNode = CreateAssignmentNode(dotCall); if (bNode.LeftNode is IdentifierNode) { symbolName = (bNode.LeftNode as IdentifierNode).Value; } astNodes.Add(bNode); CodeBlockNode codeBlockNode = new CodeBlockNode(); codeBlockNode.Body = astNodes; ProtoCore.CodeGenDS codeGen = new ProtoCore.CodeGenDS(astNodes); code = codeGen.GenerateCode(); return(codeBlockNode); }
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); } FunctionCallNode funCallNode = new FunctionCallNode(); IdentifierNode funcName = new IdentifierNode { Value = Constants.kDotArgMethodName, Name = Constants.kDotArgMethodName }; funCallNode.Function = funcName; funCallNode.Name = Constants.kDotArgMethodName; NodeUtils.CopyNodeLocation(funCallNode, lhs); int rhsIdx = ProtoCore.DSASM.Constants.kInvalidIndex; string lhsName = string.Empty; 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 (core != null) { DynamicFunction func; if (core.DynamicFunctionTable.TryGetFunction(rhsName, 0, Constants.kInvalidIndex, out func)) { rhsIdx = func.Index; } else { func = core.DynamicFunctionTable.AddNewFunction(rhsName, 0, Constants.kInvalidIndex); rhsIdx = func.Index; } } // The first param to the dot arg (the pointer or the class name) funCallNode.FormalArguments.Add(lhs); // The second param which is the dynamic table index of the function to call var rhs = new IntNode(rhsIdx); 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 var dimNode = new IntNode(dimCount); funCallNode.FormalArguments.Add(dimNode); if (argNum >= 0) { funCallNode.FormalArguments.Add(argList); funCallNode.FormalArguments.Add(new IntNode(argNum)); } var funDotCallNode = new 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; }
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, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass, BinaryExpressionNode bnode) { // Update graph dependencies if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.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; PushSymbolAsDependent(classSymbol, graphNode); } } 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.ArgumentInfos.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.Exprs.Count); string varname = string.Empty; if (exprList.Exprs[0] is IdentifierNode) { varname = (exprList.Exprs[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 != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { for (int i = 0; i < defaultArgNumber; i++) { exprList.Exprs.Add(new DefaultArgNode()); } } if (!isStaticCall && !isConstructor) { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); funtionArgCount = exprList.Exprs.Count; } else { foreach (AssociativeNode exprListNode in exprList.Exprs) { bool repGuideState = emitReplicationGuide; if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { 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 (ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone == subPass) { exprList.Exprs.Insert(0, new DynamicNode()); } } if (exprList.Exprs.Count > 0) { foreach (AssociativeNode exprListNode in exprList.Exprs) { bool repGuideState = emitReplicationGuide; if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { emitReplicationGuide = false; } DfsTraverse(exprListNode, ref paramType, false, graphNode, subPass, bnode); emitReplicationGuide = repGuideState; arglist.Add(paramType); } if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier && !isStaticCall && !isConstructor) { EmitInstrConsole(ProtoCore.DSASM.kw.alloca, exprList.Exprs.Count.ToString()); EmitPopArray(exprList.Exprs.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.Exprs.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 ProcedureNode TraverseDotFunctionCall( ProtoCore.AST.Node node, ProtoCore.AST.Node parentNode, int lefttype, int depth, GraphNode graphNode, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass, BinaryExpressionNode bnode, ref ProtoCore.Type inferedType) { 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 != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.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(ProtoCore.Properties.Resources.kCallingNonStaticProperty, className, property); buildStatus.LogWarning(WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, dotCall.line, dotCall.col, graphNode); 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 == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone) { string message = String.Format(ProtoCore.Properties.Resources.kStaticMethodNotFound, className, procName); buildStatus.LogWarning(WarningID.kFunctionNotFound, message, core.CurrentDSFileName, dotCall.line, dotCall.col, graphNode); 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 == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone) { string message = String.Format(ProtoCore.Properties.Resources.KCallingConstructorOnInstance, procName); buildStatus.LogWarning(WarningID.kCallingConstructorOnInstance, message, core.CurrentDSFileName, funcCall.line, funcCall.col, graphNode); EmitNullNode(new NullNode(), ref inferedType); } return null; } isAccessible = procCallNode.AccessModifier == ProtoCore.CompilerDefinitions.AccessModifier.kPublic || (procCallNode.AccessModifier == ProtoCore.CompilerDefinitions.AccessModifier.kPrivate && procCallNode.ClassID == globalClassIndex); if (!isAccessible) { if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone) { string message = String.Format(ProtoCore.Properties.Resources.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, core.CurrentDSFileName, funcCall.line, funcCall.col, graphNode); } } var dynamicRhsIndex = (int)(dotCall.DotCall.FormalArguments[1] as IntNode).Value; var dynFunc = core.DynamicFunctionTable.GetFunctionAtIndex(dynamicRhsIndex); dynFunc.ClassIndex = procCallNode.ClassID; } } 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 == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.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.Exprs.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) { PushSymbolAsDependent(symbolnode, graphNode); } } } // 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 = CoreUtils.GetFunctionBySignature(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(ProtoCore.Properties.Resources.kMethodIsInaccessible, procName); buildStatus.LogWarning(WarningID.kAccessViolation, message, core.CurrentDSFileName, funcCall.line, funcCall.col, graphNode); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procCallNode; } } } } if (isUnresolvedDot || procCallNode == null) { if (dotCallType.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = dotCallType.UID; } var procNode = CoreUtils.GetFunctionByName(Constants.kDotMethodName, 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].ProcTable.Procedures[globalProcIndex]; if (contextProcNode.IsConstructor && string.Equals(contextProcNode.Name, procCallNode.Name) && contextProcNode.RuntimeIndex == procCallNode.RuntimeIndex) { string message = String.Format(ProtoCore.Properties.Resources.kCallingConstructorInConstructor, procName); buildStatus.LogWarning(WarningID.kCallingConstructorInConstructor, message, core.CurrentDSFileName, node.line, node.col, graphNode); 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.ClassID, arglist, procCallNode, funcCall, isGetter, bnode); } else { var procNode = CoreUtils.GetFunctionByName(Constants.kDotMethodName, 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; } }
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; }
public FunctionDotCallNode(FunctionDotCallNode rhs): base(rhs) { DotCall = new FunctionCallNode(rhs.DotCall); FunctionCall = new FunctionCallNode(rhs.FunctionCall); lhsName = rhs.lhsName; isLastSSAIdentListFactor = rhs.isLastSSAIdentListFactor; }
private VariableSlotInfo GetVariableSlotInfo(FunctionDotCallNode functionDotCallNode) { // @TODO(done): No hard-casting. ProtoCore.AST.AssociativeAST.IdentifierNode idenNode = functionDotCallNode.DotCall.FormalArguments[0] as ProtoCore.AST.AssociativeAST.IdentifierNode; if (idenNode == null) throw new InvalidOperationException("Unsupported AST Node Type"); string var = idenNode.Value; int line = functionDotCallNode.line; uint slot = uint.MaxValue; return new VariableSlotInfo(var, line, slot); }
public static FunctionDotCallNode GenerateCallDotNode(AssociativeNode lhs, FunctionCallNode rhsCall, Core core = null) { // The function name to call string rhsName = rhsCall.Function.Name; int argNum = rhsCall.FormalArguments.Count; ExprListNode argList = new ExprListNode(); foreach (AssociativeNode arg in rhsCall.FormalArguments) { // The function arguments argList.Exprs.Add(arg); } var arguments = new List<AssociativeNode>(); int rhsIdx = DSASM.Constants.kInvalidIndex; string lhsName = string.Empty; if (lhs is IdentifierNode) { lhsName = (lhs as IdentifierNode).Name; if (lhsName == DSDefinitions.Keyword.This) { lhs = new ThisPointerNode(); } } if (core != null) { DynamicFunction func; if (core.DynamicFunctionTable.TryGetFunction(rhsName, 0, Constants.kInvalidIndex, out func)) { rhsIdx = func.Index; } else { func = core.DynamicFunctionTable.AddNewFunction(rhsName, 0, Constants.kInvalidIndex); rhsIdx = func.Index; } } // The first param to the dot arg (the pointer or the class name) arguments.Add(lhs); // The second param which is the dynamic table index of the function to call arguments.Add(new IntNode(rhsIdx)); // The array dimensions ExprListNode arrayDimExperList = new ExprListNode(); int dimCount = 0; if (rhsCall.Function is IdentifierNode) { // Number of dimensions IdentifierNode fIdent = rhsCall.Function as IdentifierNode; if (fIdent.ArrayDimensions != null) { arrayDimExperList = CoreUtils.BuildArrayExprList(fIdent.ArrayDimensions); dimCount = arrayDimExperList.Exprs.Count; } else if (rhsCall.ArrayDimensions != null) { arrayDimExperList = CoreUtils.BuildArrayExprList(rhsCall.ArrayDimensions); dimCount = arrayDimExperList.Exprs.Count; } else { arrayDimExperList = new ExprListNode(); } } arguments.Add(arrayDimExperList); // Number of dimensions var dimNode = new IntNode(dimCount); arguments.Add(dimNode); if (argNum >= 0) { arguments.Add(argList); arguments.Add(new IntNode(argNum)); } var funDotCallNode = new FunctionDotCallNode(rhsCall, arguments); // funDotCallNode.FunctionCall.Function = rhsCall.Function; NodeUtils.SetNodeEndLocation(funDotCallNode, rhsCall); return funDotCallNode; }