private void EmitFunctionDefinitionNode(ImperativeNode node, ref ProtoCore.Type inferedType) { bool parseGlobalFunctionSig = null == localProcedure && ProtoCore.DSASM.ImperativeCompilePass.kGlobalFuncSig == compilePass; bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.DSASM.ImperativeCompilePass.kGlobalFuncBody == compilePass; FunctionDefinitionNode funcDef = node as FunctionDefinitionNode; localFunctionDefNode = funcDef; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (parseGlobalFunctionSig) { Debug.Assert(null == localProcedure); // TODO jun: Add semantics for checking overloads (different parameter types) localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.name = funcDef.Name; localProcedure.pc = pc; localProcedure.localCount = funcDef.localVars; localProcedure.returntype.UID = compileStateTracker.TypeSystem.GetType(funcDef.ReturnType.Name); if (localProcedure.returntype.UID == (int)PrimitiveType.kInvalidType) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kReturnTypeUndefined, funcDef.ReturnType.Name, funcDef.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kTypeUndefined, message, null, funcDef.line, funcDef.col); localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; } localProcedure.returntype.IsIndexable = funcDef.ReturnType.IsIndexable; localProcedure.returntype.rank = funcDef.ReturnType.rank; localProcedure.runtimeIndex = codeBlock.codeBlockId; globalProcIndex = codeBlock.procedureTable.Append(localProcedure); compileStateTracker.ProcNode = localProcedure; // Append arg symbols if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { IdentifierNode paramNode = null; bool aIsDefault = false; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aIsDefault = true; aDefaultExpression = bNode; //buildStatus.LogSemanticError("Defualt parameters are not supported"); //throw new BuildHaltException(); } else { Debug.Assert(false, "Check generated AST"); } ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); int symbolIndex = AllocateArg(paramNode.Value, localProcedure.procId, argType); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("26384684"); } localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { isDefault = aIsDefault, defaultExpression = aDefaultExpression }; localProcedure.argInfoList.Add(argInfo); } } // TODO Jun: Remove this once agree that alltest cases assume the default assoc block is block 0 // NOTE: Only affects mirror, not actual execution if (null == codeBlock.parent && pc <= 0) { // The first node in the top level block is a function compileStateTracker.DSExecutable.isSingleAssocBlock = false; } #if ENABLE_EXCEPTION_HANDLING core.ExceptionHandlingManager.Register(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); #endif } else if (parseGlobalFunctionBody) { EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature)); // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); argList.Add(argType); } } // Get the exisitng procedure that was added on the previous pass globalProcIndex = codeBlock.procedureTable.IndexOfExact(funcDef.Name, argList); localProcedure = codeBlock.procedureTable.procList[globalProcIndex]; Debug.Assert(null != localProcedure); localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.pc = pc; // Copy the active function to the core so nested language blocks can refer to it compileStateTracker.ProcNode = localProcedure; // Arguments have been allocated, update the baseOffset localProcedure.localCount = compileStateTracker.BaseOffset; ProtoCore.FunctionEndPoint fep = null; //Traverse default argument emitDebugInfo = false; foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList) { if (!argNode.isDefault) { continue; } BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp = nodeBuilder.BuildIdentfier(Constants.kTempDefaultArg); BinaryExpressionNode bNodeTemp = nodeBuilder.BuildBinaryExpression(iNodeTemp, bNode.LeftNode) as BinaryExpressionNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.ConditionExpression = nodeBuilder.BuildBinaryExpression(iNodeTemp, new DefaultArgNode(), Operator.eq); icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } emitDebugInfo = true; // Traverse definition bool hasReturnStatement = false; foreach (ImperativeNode bnode in funcDef.FunctionBody.Body) { DfsTraverse(bnode, ref inferedType); if (ProtoCore.Utils.NodeUtils.IsReturnExpressionNode(bnode)) { hasReturnStatement = true; } if (bnode is FunctionCallNode) { EmitSetExpressionUID(compileStateTracker.ExpressionUID++); } } // All locals have been stack allocated, update the local count of this function localProcedure.localCount = compileStateTracker.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values) { if (symnode.functionIndex == localProcedure.procId && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.pc; record.locals = localProcedure.localCount; record.classIndex = ProtoCore.DSASM.Constants.kInvalidIndex; record.funcIndex = localProcedure.procId; fep = new ProtoCore.Lang.JILFunctionEndPoint(record); // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count]; fep.BlockScope = codeBlock.codeBlockId; fep.procedureNode = localProcedure; localProcedure.argTypeList.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = ProtoCore.DSASM.Constants.kInvalidIndex + 1; compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep); if (!hasReturnStatement) { if (!compileStateTracker.Options.SuppressFunctionResolutionWarning) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kFunctionNotReturnAtAllCodePaths, localProcedure.name); compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col); } EmitReturnNull(); } EmitCompileLogFunctionEnd(); //Fuqiang: return is already done in traversing the function body //// function return //EmitInstrConsole(ProtoCore.DSASM.kw.ret); //EmitReturn(); } compileStateTracker.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; argOffset = 0; compileStateTracker.BaseOffset = 0; codeBlock.blockType = originalBlockType; localFunctionDefNode = null; }
private ArgumentInfo BuildArgumentInfoFromVarDeclNode(VarDeclNode argNode) { var argumentName = String.Empty; ProtoCore.AST.Node defaultExpression = null; if (argNode.NameNode is IdentifierNode) { argumentName = (argNode.NameNode as IdentifierNode).Value; } else if (argNode.NameNode is BinaryExpressionNode) { var bNode = argNode.NameNode as BinaryExpressionNode; defaultExpression = bNode; argumentName = (bNode.LeftNode as IdentifierNode).Value; } else { Validity.Assert(false, "Check generated AST"); } var argInfo = new ProtoCore.DSASM.ArgumentInfo { Name = argumentName, DefaultExpression = defaultExpression, Attributes = argNode.ExternalAttributes }; return argInfo; }
private void EmitFunctionDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone) { bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.DSASM.AssociativeCompilePass.kGlobalFuncBody == compilePass; bool parseMemberFunctionBody = ProtoCore.DSASM.Constants.kGlobalScope != globalClassIndex && ProtoCore.DSASM.AssociativeCompilePass.kClassMemFuncBody == compilePass; FunctionDefinitionNode funcDef = node as FunctionDefinitionNode; localFunctionDefNode = funcDef; if (funcDef.IsAssocOperator) { isAssocOperator = true; } else { isAssocOperator = false; } bool hasReturnStatement = false; ProtoCore.DSASM.CodeBlockType origCodeBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingGlobalFunctionSig() || IsParsingMemberFunctionSig()) { Debug.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.name = funcDef.Name; localProcedure.pc = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.localCount = 0; // Defer till all locals are allocated localProcedure.returntype.UID = compileStateTracker.TypeSystem.GetType(funcDef.ReturnType.Name); if (localProcedure.returntype.UID == (int)PrimitiveType.kInvalidType) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kReturnTypeUndefined, funcDef.ReturnType.Name, funcDef.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kTypeUndefined, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col); localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; } localProcedure.returntype.IsIndexable = funcDef.ReturnType.IsIndexable; localProcedure.returntype.rank = funcDef.ReturnType.rank; localProcedure.isConstructor = false; localProcedure.isStatic = funcDef.IsStatic; localProcedure.runtimeIndex = codeBlock.codeBlockId; localProcedure.access = funcDef.access; localProcedure.isExternal = funcDef.IsExternLib; localProcedure.isAutoGenerated = funcDef.IsAutoGenerated; localProcedure.classScope = globalClassIndex; localProcedure.isAssocOperator = funcDef.IsAssocOperator; localProcedure.isAutoGeneratedThisProc = funcDef.IsAutoGeneratedThisProc; int peekFunctionindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { peekFunctionindex = codeBlock.procedureTable.procList.Count; } else { peekFunctionindex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count; } // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); if (null != funcDef.Singnature) { int argNumber = 0; foreach (VarDeclNode argNode in funcDef.Singnature.Arguments) { ++argNumber; IdentifierNode paramNode = null; bool aIsDefault = false; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aIsDefault = true; aDefaultExpression = bNode; //buildStatus.LogSemanticError("Defualt parameters are not supported"); //throw new BuildHaltException(); } else { Debug.Assert(false, "Check generated AST"); } ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); // We dont directly allocate arguments now argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(paramNode.Value, argType)); localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { Name = paramNode.Value, isDefault = aIsDefault, defaultExpression = aDefaultExpression }; localProcedure.argInfoList.Add(argInfo); } } if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { globalProcIndex = codeBlock.procedureTable.Append(localProcedure); } else { globalProcIndex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.Append(localProcedure); } // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != globalProcIndex) { Debug.Assert(peekFunctionindex == localProcedure.procId); argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, globalProcIndex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("B2CB2093"); } }); // TODO Jun: Remove this once agree that alltest cases assume the default assoc block is block 0 // NOTE: Only affects mirror, not actual execution if (null == codeBlock.parent && pc <= 0) { // The first node in the top level block is a function compileStateTracker.DSExecutable.isSingleAssocBlock = false; } #if ENABLE_EXCEPTION_HANDLING core.ExceptionHandlingManager.Register(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); #endif } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodAlreadyDefined, localProcedure.name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col); funcDef.skipMe = true; } } else if (parseGlobalFunctionBody || parseMemberFunctionBody) { if (compileStateTracker.Options.DisableDisposeFunctionDebug) { if (node.Name.Equals(ProtoCore.DSDefinitions.Keyword.Dispose)) { compileStateTracker.Options.EmitBreakpoints = false; } } // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Singnature) { foreach (VarDeclNode argNode in funcDef.Singnature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); argList.Add(argType); } } // Get the exisitng procedure that was added on the previous pass if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { globalProcIndex = codeBlock.procedureTable.IndexOfExact(funcDef.Name, argList); localProcedure = codeBlock.procedureTable.procList[globalProcIndex]; } else { globalProcIndex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList); localProcedure = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; } Debug.Assert(null != localProcedure); // code gen the attribute localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.pc = pc; // Copy the active function to the core so nested language blocks can refer to it compileStateTracker.ProcNode = localProcedure; ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { //Traverse default argument emitDebugInfo = false; foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList) { if (!argNode.isDefault) { continue; } BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp = nodeBuilder.BuildTempVariable(); var bNodeTemp = nodeBuilder.BuildBinaryExpression(iNodeTemp, bNode.LeftNode) as BinaryExpressionNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, AssociativeSubCompilePass.kUnboundIdentifier); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.IsAutoGenerated = true; BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, AssociativeSubCompilePass.kUnboundIdentifier); } emitDebugInfo = true; EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Singnature)); // Traverse definition foreach (AssociativeNode bnode in funcDef.FunctionBody.Body) { // // TODO Jun: Handle stand alone language blocks // Integrate the subPass into a proper pass // ProtoCore.Type itype = new ProtoCore.Type(); itype.UID = (int)PrimitiveType.kTypeVar; if (bnode is LanguageBlockNode) { // Build a binaryn node with a temporary lhs for every stand-alone language block BinaryExpressionNode langBlockNode = new BinaryExpressionNode(); langBlockNode.LeftNode = nodeBuilder.BuildIdentfier(compileStateTracker.GenerateTempLangageVar()); langBlockNode.Optr = ProtoCore.DSASM.Operator.assign; langBlockNode.RightNode = bnode; //DfsTraverse(bnode, ref itype, false, null, ProtoCore.DSASM.AssociativeSubCompilePass.kNone); DfsTraverse(langBlockNode, ref itype, false, null, subPass); } else { DfsTraverse(bnode, ref itype, false, null, subPass); } if (NodeUtils.IsReturnExpressionNode(bnode)) hasReturnStatement = true; } EmitCompileLogFunctionEnd(); // All locals have been stack allocated, update the local count of this function localProcedure.localCount = compileStateTracker.BaseOffset; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { localProcedure.localCount = compileStateTracker.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values) { if (symnode.functionIndex == localProcedure.procId && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } } else { compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[localProcedure.procId].localCount = compileStateTracker.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in compileStateTracker.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList.Values) { if (symnode.functionIndex == localProcedure.procId && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } } ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.pc; record.locals = localProcedure.localCount; record.classIndex = globalClassIndex; record.funcIndex = localProcedure.procId; fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else if (funcDef.BuiltInMethodId != ProtoCore.Lang.BuiltInMethods.MethodID.kInvalidMethodID) { fep = new ProtoCore.Lang.BuiltInFunctionEndPoint(funcDef.BuiltInMethodId); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.pc; jRecord.locals = localProcedure.localCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.procId; // TODO Jun/Luke: Wrap this into Core.Options and extend if needed /* bool isCSFFI = false; if (isCSFFI) { ProtoCore.Lang.CSFFIActivationRecord record = new ProtoCore.Lang.CSFFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = funcDef.IsDNI; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.argTypeList; fep = new ProtoCore.Lang.CSFFIFunctionEndPoint(record); } else {*/ ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = funcDef.IsDNI; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.argTypeList; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); //} } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count]; fep.BlockScope = codeBlock.codeBlockId; fep.ClassOwnerIndex = localProcedure.classScope; fep.procedureNode = localProcedure; localProcedure.argTypeList.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = globalClassIndex + 1; FunctionGroup functionGroup = compileStateTracker.FunctionTable.GetFunctionGroup(classIndexAtCallsite, funcDef.Name); if (functionGroup != null) { functionGroup.FunctionEndPoints.Add(fep); } else { // If any functions in the base class have the same name, append them here FunctionGroup basegroup = null; int ci = classIndexAtCallsite - 1; if (ci != Constants.kInvalidIndex) { ProtoCore.DSASM.ClassNode cnode = compileStateTracker.ClassTable.ClassNodes[ci]; if (cnode.baseList.Count > 0) { Validity.Assert(1 == cnode.baseList.Count, "We don't support multiple inheritance yet"); basegroup = compileStateTracker.FunctionTable.GetFunctionGroup(cnode.baseList[0] + 1, funcDef.Name); } } if (basegroup == null) { compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep); } else { // Copy all non-private feps from the basegroup into this the new group FunctionGroup newGroup = new FunctionGroup(); newGroup.CopyVisible(basegroup.FunctionEndPoints); newGroup.FunctionEndPoints.Add(fep); foreach (var newfep in newGroup.FunctionEndPoints) { compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, newfep); } } } if (!hasReturnStatement && !funcDef.IsExternLib) { if (!compileStateTracker.Options.SuppressFunctionResolutionWarning) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kFunctionNotReturnAtAllCodePaths, localProcedure.name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col); } EmitReturnNull(); } if (compileStateTracker.Options.DisableDisposeFunctionDebug) { if (node.Name.Equals(ProtoCore.DSDefinitions.Keyword.Dispose)) { compileStateTracker.Options.EmitBreakpoints = true; } } } compileStateTracker.ProcNode = localProcedure = null; codeBlock.blockType = origCodeBlockType; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; localFunctionDefNode = null; compileStateTracker.BaseOffset = 0; argOffset = 0; isAssocOperator = false; }
private void EmitConstructorDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone) { ConstructorDefinitionNode funcDef = node as ConstructorDefinitionNode; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingMemberFunctionSig()) { Debug.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.name = funcDef.Name; localProcedure.pc = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.localCount = 0;// Defer till all locals are allocated localProcedure.returntype.UID = globalClassIndex; localProcedure.returntype.IsIndexable = false; localProcedure.isConstructor = true; localProcedure.runtimeIndex = 0; localProcedure.isExternal = funcDef.IsExternLib; Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class"); localProcedure.localCount = 0; localProcedure.classScope = globalClassIndex; int peekFunctionindex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count; // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); if (null != funcDef.Signature) { int argNumber = 0; foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ++argNumber; IdentifierNode paramNode = null; bool aIsDefault = false; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aIsDefault = true; aDefaultExpression = bNode; //buildStatus.LogSemanticError("Default parameters are not supported"); //throw new BuildHaltException(); } else { Debug.Assert(false, "Check generated AST"); } ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(paramNode.Value, argType)); localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { Name = paramNode.Value, isDefault = aIsDefault, defaultExpression = aDefaultExpression }; localProcedure.argInfoList.Add(argInfo); } } int findex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.Append(localProcedure); // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != findex) { Debug.Assert(peekFunctionindex == localProcedure.procId); argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, findex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("44B557F1"); } }); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodAlreadyDefined, localProcedure.name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col); funcDef.skipMe = true; } } else if (IsParsingMemberFunctionBody()) { EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature, true)); // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); argList.Add(argType); } } globalProcIndex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList); Debug.Assert(null == localProcedure); localProcedure = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; Debug.Assert(null != localProcedure); localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.pc = pc; EmitInstrConsole(ProtoCore.DSASM.kw.allocc, localProcedure.name); EmitAllocc(globalClassIndex); setConstructorStartPC = true; EmitCallingForBaseConstructor(globalClassIndex, funcDef.baseConstr); ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { // Traverse default assignment for the class emitDebugInfo = false; foreach (BinaryExpressionNode bNode in compileStateTracker.ClassTable.ClassNodes[globalClassIndex].defaultArgExprList) { ProtoCore.AssociativeGraph.GraphNode graphNode = new ProtoCore.AssociativeGraph.GraphNode(); graphNode.isParent = true; graphNode.exprUID = bNode.exprUID; graphNode.modBlkUID = bNode.modBlkUID; graphNode.procIndex = globalProcIndex; graphNode.classIndex = globalClassIndex; graphNode.isAutoGenerated = true; EmitBinaryExpressionNode(bNode, ref inferedType, false, graphNode, subPass); } //Traverse default argument for the constructor foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList) { if (!argNode.isDefault) { continue; } BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp = nodeBuilder.BuildIdentfier(Constants.kTempDefaultArg); BinaryExpressionNode bNodeTemp = new BinaryExpressionNode(); bNodeTemp.LeftNode = iNodeTemp; bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign; bNodeTemp.RightNode = bNode.LeftNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.IsAutoGenerated = true; BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } emitDebugInfo = true; // Traverse definition foreach (AssociativeNode bnode in funcDef.FunctionBody.Body) { inferedType.UID = (int)PrimitiveType.kTypeVoid; inferedType.rank = 0; if (bnode is LanguageBlockNode) { // Build a binaryn node with a temporary lhs for every stand-alone language block var iNode = nodeBuilder.BuildIdentfier(compileStateTracker.GenerateTempLangageVar()); BinaryExpressionNode langBlockNode = new BinaryExpressionNode(); langBlockNode.LeftNode = iNode; langBlockNode.Optr = ProtoCore.DSASM.Operator.assign; langBlockNode.RightNode = bnode; DfsTraverse(langBlockNode, ref inferedType, false, null, subPass); } else { DfsTraverse(bnode, ref inferedType, false, null, subPass); } } // All locals have been stack allocated, update the local count of this function localProcedure.localCount = compileStateTracker.BaseOffset; compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex].localCount = compileStateTracker.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in compileStateTracker.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList.Values) { if (symnode.functionIndex == globalProcIndex && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } // JIL FEP ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.pc; record.locals = localProcedure.localCount; record.classIndex = globalClassIndex; record.funcIndex = globalProcIndex; // Construct the fep arguments fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.pc; jRecord.locals = localProcedure.localCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.procId; ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = false; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.argTypeList; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count]; fep.procedureNode = localProcedure; localProcedure.argTypeList.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = globalClassIndex + 1; compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep); int startpc = pc; // Constructors auto return EmitInstrConsole(ProtoCore.DSASM.kw.retc); // Stepping out of a constructor body will have the execution cursor // placed right at the closing curly bracket of the constructor definition. // int closeCurlyBracketLine = 0, closeCurlyBracketColumn = -1; if (null != funcDef.FunctionBody) { closeCurlyBracketLine = funcDef.FunctionBody.endLine; closeCurlyBracketColumn = funcDef.FunctionBody.endCol; } // The execution cursor covers exactly one character -- the closing // curly bracket. Note that we decrement the start-column by one here // because end-column of "FunctionBody" here is *after* the closing // curly bracket, so we want one before that. // EmitRetc(closeCurlyBracketLine, closeCurlyBracketColumn - 1, closeCurlyBracketLine, closeCurlyBracketColumn); // Build and append a graphnode for this return statememt ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode(); returnNode.name = ProtoCore.DSDefinitions.Keyword.Return; ProtoCore.AssociativeGraph.GraphNode retNode = new ProtoCore.AssociativeGraph.GraphNode(); //retNode.symbol = returnNode; retNode.PushSymbolReference(returnNode); retNode.procIndex = globalProcIndex; retNode.classIndex = globalClassIndex; retNode.updateBlock.startpc = startpc; retNode.updateBlock.endpc = pc - 1; codeBlock.instrStream.dependencyGraph.Push(retNode); EmitCompileLogFunctionEnd(); } // Constructors have no return statemetns, reset variables here compileStateTracker.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; compileStateTracker.BaseOffset = 0; argOffset = 0; classOffset = 0; codeBlock.blockType = originalBlockType; }
private void EmitFunctionDefinitionNode(ImperativeNode node, ref ProtoCore.Type inferedType) { bool parseGlobalFunctionSig = null == localProcedure && ProtoCore.CompilerDefinitions.Imperative.CompilePass.kGlobalFuncSig == compilePass; bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.CompilerDefinitions.Imperative.CompilePass.kGlobalFuncBody == compilePass; FunctionDefinitionNode funcDef = node as FunctionDefinitionNode; localFunctionDefNode = funcDef; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (parseGlobalFunctionSig) { Validity.Assert(null == localProcedure); // TODO jun: Add semantics for checking overloads (different parameter types) localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.Name = funcDef.Name; localProcedure.PC = pc; localProcedure.LocalCount = funcDef.localVars; var returnType = new ProtoCore.Type(); returnType.UID = core.TypeSystem.GetType(funcDef.ReturnType.Name); if (returnType.UID == (int)PrimitiveType.kInvalidType) { string message = String.Format(ProtoCore.Properties.Resources.kReturnTypeUndefined, funcDef.ReturnType.Name, funcDef.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kTypeUndefined, message, null, funcDef.line, funcDef.col, firstSSAGraphNode); returnType.UID = (int)PrimitiveType.kTypeVar; } returnType.rank = funcDef.ReturnType.rank; localProcedure.ReturnType = returnType; localProcedure.RuntimeIndex = codeBlock.codeBlockId; globalProcIndex = codeBlock.procedureTable.Append(localProcedure); core.ProcNode = localProcedure; // Append arg symbols if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { IdentifierNode paramNode = null; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aDefaultExpression = bNode; } else { Validity.Assert(false, "Check generated AST"); } ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, firstSSAGraphNode); int symbolIndex = AllocateArg(paramNode.Value, localProcedure.ID, argType); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("26384684"); } localProcedure.ArgumentTypes.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { DefaultExpression = aDefaultExpression }; localProcedure.ArgumentInfos.Add(argInfo); } } } else if (parseGlobalFunctionBody) { EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature)); // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, firstSSAGraphNode); argList.Add(argType); } } // Get the exisitng procedure that was added on the previous pass globalProcIndex = codeBlock.procedureTable.IndexOfExact(funcDef.Name, argList, false); localProcedure = codeBlock.procedureTable.procList[globalProcIndex]; Validity.Assert(null != localProcedure); localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.PC = pc; // Copy the active function to the core so nested language blocks can refer to it core.ProcNode = localProcedure; // Arguments have been allocated, update the baseOffset localProcedure.LocalCount = core.BaseOffset; ProtoCore.FunctionEndPoint fep = null; //Traverse default argument emitDebugInfo = false; foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.ArgumentInfos) { if (!argNode.IsDefault) { continue; } BinaryExpressionNode bNode = argNode.DefaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp = nodeBuilder.BuildIdentfier(Constants.kTempDefaultArg); BinaryExpressionNode bNodeTemp = nodeBuilder.BuildBinaryExpression(iNodeTemp, bNode.LeftNode) as BinaryExpressionNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.ConditionExpression = nodeBuilder.BuildBinaryExpression(iNodeTemp, new DefaultArgNode(), Operator.eq); icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } emitDebugInfo = true; // Traverse definition bool hasReturnStatement = false; foreach (ImperativeNode bnode in funcDef.FunctionBody.Body) { DfsTraverse(bnode, ref inferedType); if (ProtoCore.Utils.NodeUtils.IsReturnExpressionNode(bnode)) { hasReturnStatement = true; } if (bnode is FunctionCallNode) { EmitSetExpressionUID(core.ExpressionUID++); } } // All locals have been stack allocated, update the local count of this function localProcedure.LocalCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in codeBlock.symbolTable.symbolList.Values) { if (symnode.functionIndex == localProcedure.ID && symnode.isArgument) { symnode.index -= localProcedure.LocalCount; } } ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.PC; record.locals = localProcedure.LocalCount; record.classIndex = ProtoCore.DSASM.Constants.kInvalidIndex; record.funcIndex = localProcedure.ID; fep = new ProtoCore.Lang.JILFunctionEndPoint(record); // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.ArgumentTypes.Count]; fep.BlockScope = codeBlock.codeBlockId; fep.procedureNode = localProcedure; localProcedure.ArgumentTypes.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = ProtoCore.DSASM.Constants.kInvalidIndex + 1; if (!core.FunctionTable.GlobalFuncTable.ContainsKey(classIndexAtCallsite)) { Dictionary<string, FunctionGroup> funcList = new Dictionary<string, FunctionGroup>(); core.FunctionTable.GlobalFuncTable.Add(classIndexAtCallsite, funcList); } Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } if (!hasReturnStatement) { if (!core.Options.SuppressFunctionResolutionWarning) { string message = String.Format(ProtoCore.Properties.Resources.kFunctionNotReturnAtAllCodePaths, localProcedure.Name); core.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, core.CurrentDSFileName, funcDef.line, funcDef.col, firstSSAGraphNode); } EmitReturnNull(); } EmitCompileLogFunctionEnd(); //Fuqiang: return is already done in traversing the function body //// function return //EmitInstrConsole(ProtoCore.DSASM.kw.ret); //EmitReturn(); } core.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; argOffset = 0; core.BaseOffset = 0; codeBlock.blockType = originalBlockType; localFunctionDefNode = null; }
/// <summary> /// Returns the list of properties for a given class /// </summary> /// <param name="className"></param> /// <returns></returns> public static List<string> GetProperties(string className) { List<string> properties = new List<string>(); Validity.Assert(core != null); ProtoCore.DSASM.ClassTable classTable = core.ClassTable; int ci = classTable.IndexOf(className); string name = string.Empty; if (ci != ProtoCore.DSASM.Constants.kInvalidIndex) { ClassNode classNode = classTable.ClassNodes[ci]; ProcedureTable procedureTable = classNode.vtable; List<ProcedureNode> procList = procedureTable.procList; string prefix = ProtoCore.DSASM.Constants.kGetterPrefix; ArgumentInfo aInfo = new ArgumentInfo(); aInfo.isDefault = false; aInfo.Name = ProtoCore.DSASM.Constants.kThisPointerArgName; foreach (ProcedureNode pNode in procList) { name = pNode.name; if (name.Contains(prefix) && pNode.argInfoList.Count == 0 && !pNode.argInfoList.Contains(aInfo)) { int prefixLength = prefix.Length; name = name.Substring(prefixLength); properties.Add(name); } } } return properties; }
/// <summary> /// Returns a list of member functions for a given class /// </summary> /// <param name="className"></param> /// <returns></returns> public static List<string> GetMethods(string className) { List<string> methods = new List<string>(); Validity.Assert(core != null); ProtoCore.DSASM.ClassTable classTable = core.ClassTable; int ci = classTable.IndexOf(className); string name = string.Empty; if (ci != ProtoCore.DSASM.Constants.kInvalidIndex) { ClassNode classNode = classTable.ClassNodes[ci]; ProcedureTable procedureTable = classNode.vtable; List<ProcedureNode> procList = procedureTable.procList; string prefix = ProtoCore.DSASM.Constants.kGetterPrefix; ArgumentInfo aInfo = new ArgumentInfo(); aInfo.Name = ProtoCore.DSASM.Constants.kThisPointerArgName; foreach (ProcedureNode pNode in procList) { name = pNode.name; if (name.Contains(prefix) == false && pNode.isConstructor == false && !pNode.argInfoList.Contains(aInfo)) { methods.Add(name); } } } return methods; }