private void EmitFunctionDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, GraphNode graphNode = null) { bool parseGlobalFunctionBody = null == localProcedure && ProtoCore.CompilerDefinitions.Associative.CompilePass.kGlobalFuncBody == compilePass; bool parseMemberFunctionBody = ProtoCore.DSASM.Constants.kGlobalScope != globalClassIndex && ProtoCore.CompilerDefinitions.Associative.CompilePass.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()) { Validity.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 var uid = core.TypeSystem.GetType(funcDef.ReturnType.Name); var rank = funcDef.ReturnType.rank; var returnType = core.TypeSystem.BuildTypeObject(uid, rank); if (returnType.UID == (int)PrimitiveType.kInvalidType) { string message = String.Format(ProtoCore.Properties.Resources.kReturnTypeUndefined, funcDef.ReturnType.Name, funcDef.Name); buildStatus.LogWarning(WarningID.kTypeUndefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode); returnType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, rank); } localProcedure.ReturnType = returnType; localProcedure.IsConstructor = false; localProcedure.IsStatic = funcDef.IsStatic; localProcedure.RuntimeIndex = codeBlock.codeBlockId; localProcedure.AccessModifier = funcDef.Access; localProcedure.IsExternal = funcDef.IsExternLib; localProcedure.IsAutoGenerated = funcDef.IsAutoGenerated; localProcedure.ClassID = globalClassIndex; localProcedure.IsAssocOperator = funcDef.IsAssocOperator; localProcedure.IsAutoGeneratedThisProc = funcDef.IsAutoGeneratedThisProc; localProcedure.MethodAttribute = funcDef.MethodAttributes; int peekFunctionindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { peekFunctionindex = codeBlock.procedureTable.Procedures.Count; } else { peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures.Count; } // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); string functionDescription = localProcedure.Name; if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { var argInfo = BuildArgumentInfoFromVarDeclNode(argNode); localProcedure.ArgumentInfos.Add(argInfo); var argType = BuildArgumentTypeFromVarDeclNode(argNode, graphNode); localProcedure.ArgumentTypes.Add(argType); argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(argInfo.Name, argType)); functionDescription += argNode.ArgumentType.ToString(); } localProcedure.HashID = functionDescription.GetHashCode(); localProcedure.IsVarArg = funcDef.Signature.IsVarArg; } if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { globalProcIndex = codeBlock.procedureTable.Append(localProcedure); } else { globalProcIndex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Append(localProcedure); } // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != globalProcIndex) { argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, globalProcIndex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("B2CB2093"); } }); } else { string message = String.Format(ProtoCore.Properties.Resources.kMethodAlreadyDefined, localProcedure.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode); funcDef.skipMe = true; } } else if (parseGlobalFunctionBody || parseMemberFunctionBody) { if (CoreUtils.IsDisposeMethod(node.Name)) { core.Options.EmitBreakpoints = false; } // 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, graphNode); argList.Add(argType); } } // Get the exisitng procedure that was added on the previous pass if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { var procNode = codeBlock.procedureTable.GetFunctionBySignature(funcDef.Name, argList); globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID; localProcedure = codeBlock.procedureTable.Procedures[globalProcIndex]; } else { var procNode = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.GetFunctionBySignature(funcDef.Name, argList); globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID; localProcedure = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex]; } Validity.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 //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; ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { //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 = AstFactory.BuildIdentifier(core.GenerateTempVar()); var bNodeTemp = AstFactory.BuildAssignment(iNodeTemp, bNode.LeftNode); bNodeTemp.IsProcedureOwned = true; EmitBinaryExpressionNode(bNodeTemp, ref inferedType, false, null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.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, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier); } emitDebugInfo = true; EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature)); ProtoCore.Type itype = new ProtoCore.Type(); hasReturnStatement = EmitCodeBlock(funcDef.FunctionBody.Body, ref itype, subPass, true); // Build dependency within the function ProtoCore.AssociativeEngine.Utils.BuildGraphNodeDependencies( codeBlock.instrStream.dependencyGraph.GetGraphNodesAtScope(globalClassIndex, globalProcIndex)); EmitCompileLogFunctionEnd(); // All locals have been stack allocated, update the local count of this function localProcedure.LocalCount = core.BaseOffset; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { 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; } } } else { core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[localProcedure.ID].LocalCount = core.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[globalClassIndex].Symbols.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 = globalClassIndex; record.funcIndex = localProcedure.ID; 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.ID; 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.ArgumentTypes; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.ArgumentTypes.Count]; fep.BlockScope = codeBlock.codeBlockId; fep.ClassOwnerIndex = localProcedure.ClassID; fep.procedureNode = localProcedure; localProcedure.ArgumentTypes.CopyTo(fep.FormalParams, 0); // 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables int classIndexAtCallsite = globalClassIndex + 1; core.FunctionTable.InitGlobalFunctionEntry(classIndexAtCallsite); // Get the function group of the current class and see if the current function exists Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // If any functions in the base class have the same name, append them here int ci = classIndexAtCallsite - 1; if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { ProtoCore.DSASM.ClassNode cnode = core.ClassTable.ClassNodes[ci]; if (cnode.Bases.Count > 0) { Validity.Assert(1 == cnode.Bases.Count, "We don't support multiple inheritance yet"); ci = cnode.Bases[0]; Dictionary<string, FunctionGroup> tgroup = new Dictionary<string, FunctionGroup>(); int callsiteCI = ci + 1; bool bSucceed = core.FunctionTable.GlobalFuncTable.TryGetValue(callsiteCI, out tgroup); if (bSucceed) { if (tgroup.ContainsKey(funcDef.Name)) { // Get that base group - the group of function from the baseclass FunctionGroup basegroup = new FunctionGroup(); bSucceed = tgroup.TryGetValue(funcDef.Name, out basegroup); if (bSucceed) { // Copy all non-private feps from the basegroup into this the new group FunctionGroup newGroup = new FunctionGroup(); newGroup.CopyVisible(basegroup.FunctionEndPoints); // Append the new fep newGroup.FunctionEndPoints.Add(fep); // Copy the new group to this class table core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, newGroup); } } else { // 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 { // 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); } cnode = core.ClassTable.ClassNodes[ci]; } else { // 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 { // 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 && !funcDef.IsExternLib) { if (!core.Options.SuppressFunctionResolutionWarning) { string message = String.Format(ProtoCore.Properties.Resources.kFunctionNotReturnAtAllCodePaths, localProcedure.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kMissingReturnStatement, message, core.CurrentDSFileName, funcDef.line, funcDef.col, graphNode); } EmitReturnNull(); } if (CoreUtils.IsDisposeMethod(node.Name)) { core.Options.EmitBreakpoints = true; } } core.ProcNode = localProcedure = null; codeBlock.blockType = origCodeBlockType; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; localFunctionDefNode = null; core.BaseOffset = 0; argOffset = 0; isAssocOperator = false; }
private void ResolveFunctionGroups() { // foreach class in classtable foreach (ProtoCore.DSASM.ClassNode cnode in core.ClassTable.ClassNodes) { if (cnode.Bases.Count > 0) { // Get the current class functiongroup int ci = cnode.ID; Dictionary<string, FunctionGroup> groupList = new Dictionary<string, FunctionGroup>(); if (!core.FunctionTable.GlobalFuncTable.TryGetValue(ci + 1, out groupList)) { continue; } // If it has a baseclass, get its function group 'basegroup' int baseCI = cnode.Bases[0]; Dictionary<string, FunctionGroup> baseGroupList = new Dictionary<string, FunctionGroup>(); bool groupListExists = core.FunctionTable.GlobalFuncTable.TryGetValue(baseCI + 1, out baseGroupList); if (groupListExists) { // If it has a baseclass, get its list of function group 'basegrouplist' // for every group, check if this already exisits in the current class foreach (KeyValuePair<string, FunctionGroup> baseGroup in baseGroupList) { if (groupList.ContainsKey(baseGroup.Key)) { // If this class has this function group, append the visible feps from the basegoup FunctionGroup currentGroup = new FunctionGroup(); if (groupList.TryGetValue(baseGroup.Key, out currentGroup)) { // currentGroup is this class's current function group given the current name currentGroup.CopyVisible(baseGroup.Value.FunctionEndPoints); } } else { // If this class doesnt have basegroup, create a new group and append the visible feps from the basegoup FunctionGroup newGroup = new FunctionGroup(); newGroup.CopyVisible(baseGroup.Value.FunctionEndPoints); if (newGroup.FunctionEndPoints.Count > 0) { groupList.Add(baseGroup.Key, newGroup); } } } } } } }
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; }