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; bool hasReturnStatement = false; 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.Name = funcDef.ReturnType.Name; localProcedure.returntype.UID = core.TypeSystem.GetType(funcDef.ReturnType.Name); if (localProcedure.returntype.UID == ProtoCore.DSASM.Constants.kInvalidIndex) localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; localProcedure.returntype.Name = core.TypeSystem.GetType(localProcedure.returntype.UID); 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; int peekFunctionindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { peekFunctionindex = codeBlock.procedureTable.procList.Count; } else { peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count; } if (IsParsingMemberFunctionSig() && !funcDef.IsExternLib) CodeRangeTable.AddClassBlockFunctionEntry(globalClassIndex, peekFunctionindex, funcDef.FunctionBody.line, funcDef.FunctionBody.col, funcDef.FunctionBody.endLine, funcDef.FunctionBody.endCol, core.CurrentDSFileName); else if (!funcDef.IsExternLib) CodeRangeTable.AddCodeBlockFunctionEntry(codeBlock.codeBlockId, peekFunctionindex, funcDef.FunctionBody.line, funcDef.FunctionBody.col, funcDef.FunctionBody.endLine, funcDef.FunctionBody.endCol, core.CurrentDSFileName); // 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 = new ProtoCore.Type(); argType.UID = core.TypeSystem.GetType(argNode.ArgumentType.Name); if (argType.UID == ProtoCore.DSASM.Constants.kInvalidIndex) argType.UID = (int)PrimitiveType.kTypeVar; argType.Name = core.TypeSystem.GetType(argType.UID); argType.IsIndexable = argNode.ArgumentType.IsIndexable; argType.rank = argNode.ArgumentType.rank; // 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 { isDefault = aIsDefault, defaultExpression = aDefaultExpression, Name = paramNode.Name }; localProcedure.argInfoList.Add(argInfo); } } if (ProtoCore.DSASM.Constants.kInvalidIndex == globalClassIndex) { globalProcIndex = codeBlock.procedureTable.Append(localProcedure); } else { globalProcIndex = core.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(); } }); ExceptionRegistration registration = core.ExceptionHandlingManager.ExceptionTable.GetExceptionRegistration(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); if (registration == null) { registration = core.ExceptionHandlingManager.ExceptionTable.Register(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); Debug.Assert(registration != null); } } } else if (parseGlobalFunctionBody || parseMemberFunctionBody) { // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Singnature) { foreach (VarDeclNode argNode in funcDef.Singnature.Arguments) { int argType = core.TypeSystem.GetType(argNode.ArgumentType.Name); bool isArray = argNode.ArgumentType.IsIndexable; int rank = argNode.ArgumentType.rank; argList.Add(core.TypeSystem.BuildTypeObject(argType, isArray, rank)); } } // 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 = core.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList); localProcedure = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; } Debug.Assert(null != localProcedure); // 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); // 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) { 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; IdentifierNode iNodeTemp = new IdentifierNode() { Value = ProtoCore.DSASM.Constants.kTempDefaultArg, Name = ProtoCore.DSASM.Constants.kTempDefaultArg, datatype = core.TypeSystem.BuildTypeObject(PrimitiveType.kTypeVar, false) }; 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(); //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); } // 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 IdentifierNode iNode = new IdentifierNode() { Value = ProtoCore.DSASM.Constants.kTempLangBlock, Name = ProtoCore.DSASM.Constants.kTempLangBlock, datatype = core.TypeSystem.BuildTypeObject(PrimitiveType.kTypeVar, false) }; BinaryExpressionNode langBlockNode = new BinaryExpressionNode(); langBlockNode.LeftNode = iNode; 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); } BinaryExpressionNode binaryNode = bnode as BinaryExpressionNode; hasReturnStatement = hasReturnStatement || ((binaryNode != null) && (binaryNode.LeftNode.Name == ProtoCore.DSDefinitions.Kw.kw_return)); } // 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.procId && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } } else { core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[localProcedure.procId].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.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 { 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 = this.codeBlock.codeBlockId; 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; core.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep); } core.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; core.BaseOffset = 0; argOffset = 0; }
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; 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.localCount = funcDef.localVars; localProcedure.returntype.UID = compileState.TypeSystem.GetType(funcDef.ReturnType.Name); if (localProcedure.returntype.UID == ProtoCore.DSASM.Constants.kInvalidIndex) localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; localProcedure.returntype.Name = compileState.TypeSystem.GetType(localProcedure.returntype.UID); localProcedure.returntype.IsIndexable = funcDef.ReturnType.IsIndexable; localProcedure.returntype.rank = funcDef.ReturnType.rank; localProcedure.runtimeIndex = codeBlock.codeBlockId; globalProcIndex = codeBlock.procedureTable.Append(localProcedure); compileState.ProcNode = localProcedure; CodeRangeTable.AddCodeBlockFunctionEntry(codeBlock.codeBlockId, globalProcIndex, funcDef.FunctionBody.line, funcDef.FunctionBody.col, funcDef.FunctionBody.endLine, funcDef.FunctionBody.endCol, compileState.CurrentDSFileName); // 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 = new ProtoCore.Type(); argType.UID = compileState.TypeSystem.GetType(argNode.ArgumentType.Name); if (argType.UID == ProtoCore.DSASM.Constants.kInvalidIndex) argType.UID = (int)PrimitiveType.kTypeVar; argType.Name = compileState.TypeSystem.GetType(argType.UID); argType.IsIndexable = argNode.ArgumentType.IsIndexable; argType.rank = argNode.ArgumentType.rank; int symbolIndex = AllocateArg(paramNode.Value, localProcedure.procId, argType); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException(); } localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { isDefault = aIsDefault, defaultExpression = aDefaultExpression, Name = paramNode.Name }; localProcedure.argInfoList.Add(argInfo); } } ExceptionRegistration registration = compileState.ExceptionHandlingManager.ExceptionTable.GetExceptionRegistration(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); if (registration == null) { registration = compileState.ExceptionHandlingManager.ExceptionTable.Register(codeBlock.codeBlockId, globalProcIndex, globalClassIndex); Debug.Assert(registration != null); } } else if (parseGlobalFunctionBody) { // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { int argType = compileState.TypeSystem.GetType(argNode.ArgumentType.Name); bool isArray = argNode.ArgumentType.IsIndexable; int rank = argNode.ArgumentType.rank; argList.Add(compileState.TypeSystem.BuildTypeObject(argType, isArray, rank)); } } // 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); // Copy the active function to the core so nested language blocks can refer to it compileState.ProcNode = localProcedure; // Arguments have been allocated, update the baseOffset localProcedure.localCount = compileState.BaseOffset; ProtoCore.FunctionEndPoint fep = null; //Traverse default argument 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; IdentifierNode iNodeTemp = new IdentifierNode() { Value = ProtoCore.DSASM.Constants.kTempDefaultArg, Name = ProtoCore.DSASM.Constants.kTempDefaultArg, datatype = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, false) }; 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(); //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); } // Traverse definition bool hasReturnStatement = false; foreach (ImperativeNode bnode in funcDef.FunctionBody.Body) { DfsTraverse(bnode, ref inferedType); BinaryExpressionNode binaryNode = bnode as BinaryExpressionNode; hasReturnStatement = hasReturnStatement || ((binaryNode != null) && (binaryNode.LeftNode.Name == ProtoCore.DSDefinitions.Keyword.Return)); } // All locals have been stack allocated, update the local count of this function localProcedure.localCount = compileState.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 = this.codeBlock.codeBlockId; 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; compileState.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep); //Fuqiang: return is already done in traversing the function body //// function return //EmitInstrConsole(ProtoCore.DSASM.kw.ret); //EmitReturn(); } compileState.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; argOffset = 0; compileState.BaseOffset = 0; codeBlock.blockType = originalBlockType; }
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 = core.TypeSystem.GetType(funcDef.ReturnType.Name); if (localProcedure.returntype.UID == ProtoCore.DSASM.Constants.kInvalidIndex) localProcedure.returntype.UID = (int)PrimitiveType.kTypeVar; localProcedure.returntype.Name = core.TypeSystem.GetType(localProcedure.returntype.UID); localProcedure.returntype.IsIndexable = false; localProcedure.isConstructor = true; localProcedure.runtimeIndex = 0; Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class"); localProcedure.localCount = 0; int peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count; if (!funcDef.IsExternLib) CodeRangeTable.AddClassBlockFunctionEntry(globalClassIndex, peekFunctionindex, funcDef.FunctionBody.line, funcDef.FunctionBody.col, funcDef.FunctionBody.endLine, funcDef.FunctionBody.endCol, core.CurrentDSFileName); // 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 = new ProtoCore.Type(); argType.UID = core.TypeSystem.GetType(argNode.ArgumentType.Name); if (argType.UID == ProtoCore.DSASM.Constants.kInvalidIndex) argType.UID = (int)PrimitiveType.kTypeVar; argType.Name = core.TypeSystem.GetType(argType.UID); argType.IsIndexable = argNode.ArgumentType.IsIndexable; argType.rank = argNode.ArgumentType.rank; argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(paramNode.Value, argType)); localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { isDefault = aIsDefault, defaultExpression = aDefaultExpression, Name = paramNode.Name }; localProcedure.argInfoList.Add(argInfo); } } int findex = core.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(); } }); } } else if (IsParsingMemberFunctionBody()) { // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { int argType = core.TypeSystem.GetType(argNode.ArgumentType.Name); bool isArray = argNode.ArgumentType.IsIndexable; int rank = argNode.ArgumentType.rank; argList.Add(core.TypeSystem.BuildTypeObject(argType, isArray, rank)); } } globalProcIndex = core.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList); Debug.Assert(null == localProcedure); localProcedure = core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; Debug.Assert(null != localProcedure); if (null == localProcedure) return; if (-1 == localProcedure.classScope && (localProcedure.classScope != globalClassIndex)) localProcedure.classScope = globalClassIndex; // Assign class index if it's not done. ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { // Traverse default assignment for the class foreach (BinaryExpressionNode bNode in core.ClassTable.ClassNodes[globalClassIndex].defaultArgExprList) { EmitBinaryExpressionNode(bNode, ref inferedType, false, null, subPass); UpdateType(bNode.LeftNode.Name, ProtoCore.DSASM.Constants.kInvalidIndex, inferedType); } //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; IdentifierNode iNodeTemp = new IdentifierNode() { Value = ProtoCore.DSASM.Constants.kTempDefaultArg, Name = ProtoCore.DSASM.Constants.kTempDefaultArg, datatype = core.TypeSystem.BuildTypeObject(PrimitiveType.kTypeVar, false) }; 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(); 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); } // Traverse definition foreach (AssociativeNode bnode in funcDef.FunctionBody.Body) { inferedType.UID = (int)PrimitiveType.kTypeVoid; inferedType.rank = 0; DfsTraverse(bnode, ref inferedType, false, null, subPass); } // All locals have been stack allocated, update the local count of this function localProcedure.localCount = core.BaseOffset; core.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex].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 == 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]; 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; core.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep); // Build and append a graphnode for this return statememt ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode(); returnNode.name = "return"; } // Constructors have no return statemetns, reset variables here core.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; core.BaseOffset = 0; argOffset = 0; classOffset = 0; codeBlock.blockType = originalBlockType; }