private void EmitLanguageBlockNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone) { if (IsParsingGlobal() || IsParsingGlobalFunctionBody() || IsParsingMemberFunctionBody() ) { if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { return; } LanguageBlockNode langblock = node as LanguageBlockNode; //Validity.Assert(ProtoCore.Language.kInvalid != langblock.codeblock.language); if (ProtoCore.Language.NotSpecified == langblock.codeblock.Language) throw new BuildHaltException("Invalid language block type (D1B95A65)"); ProtoCore.CompileTime.Context nextContext = new ProtoCore.CompileTime.Context(); // Save the guid of the current scope (which is stored in the current graphnodes) to the nested language block. // This will be passed on to the nested language block that will be compiled nextContext.guid = graphNode.guid; int entry = 0; int blockId = ProtoCore.DSASM.Constants.kInvalidIndex; // Top block signifies the auto inserted global block bool isTopBlock = null == codeBlock.parent; // The warning is enforced only if this is not the top block if (ProtoCore.Language.Associative == langblock.codeblock.Language && !isTopBlock) { // TODO Jun: Move the associative and all common string into some table buildStatus.LogSyntaxError(Resources.InvalidNestedAssociativeBlock, core.CurrentDSFileName, langblock.line, langblock.col); } // Set the current class scope so the next language can refer to it core.ClassIndex = globalClassIndex; if (globalProcIndex != ProtoCore.DSASM.Constants.kInvalidIndex && core.ProcNode == null) { if (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) core.ProcNode = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex]; else core.ProcNode = codeBlock.procedureTable.Procedures[globalProcIndex]; } ProtoCore.AssociativeGraph.GraphNode propagateGraphNode = null; if (core.Options.AssociativeToImperativePropagation && Language.Imperative == langblock.codeblock.Language) { propagateGraphNode = graphNode; } core.Compilers[langblock.codeblock.Language].Compile(out blockId, codeBlock, langblock.codeblock, nextContext, codeBlock.EventSink, langblock.CodeBlockNode, propagateGraphNode); graphNode.isLanguageBlock = true; graphNode.languageBlockId = blockId; foreach (GraphNode dNode in nextContext.DependentVariablesInScope) { graphNode.PushDependent(dNode); } setBlkId(blockId); inferedType = core.InferedType; //Validity.Assert(codeBlock.children[codeBlock.children.Count - 1].blockType == ProtoCore.DSASM.CodeBlockType.kLanguage); codeBlock.children[codeBlock.children.Count - 1].Attributes = PopulateAttributes(langblock.Attributes); EmitInstrConsole(ProtoCore.DSASM.kw.bounce + " " + blockId + ", " + entry.ToString()); EmitBounceIntrinsic(blockId, entry); // The callee language block will have stored its result into the RX register. EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); StackValue opRes = StackValue.BuildRegister(Registers.RX); EmitPush(opRes); } }
private void EmitInlineConditionalNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, ProtoCore.AST.AssociativeAST.BinaryExpressionNode parentNode = null) { if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { return; } bool isInlineConditionalFlag = false; int startPC = pc; bool isReturn = false; if (graphNode != null) { isInlineConditionalFlag = graphNode.isInlineConditional; graphNode.isInlineConditional = true; startPC = graphNode.updateBlock.startpc; isReturn = graphNode.isReturn; } InlineConditionalNode inlineConditionalNode = node as InlineConditionalNode; // TODO: Jun, this 'if' condition needs to be removed as it was the old implementation - pratapa if (inlineConditionalNode.IsAutoGenerated) { // Normal inline conditional IfStatementNode ifNode = new IfStatementNode(); ifNode.ifExprNode = inlineConditionalNode.ConditionExpression; List<AssociativeNode> ifBody = new List<AssociativeNode>(); List<AssociativeNode> elseBody = new List<AssociativeNode>(); ifBody.Add(inlineConditionalNode.TrueExpression); elseBody.Add(inlineConditionalNode.FalseExpression); ifNode.IfBody = ifBody; ifNode.ElseBody = elseBody; EmitIfStatementNode(ifNode, ref inferedType, graphNode); } else { // CPS inline conditional FunctionCallNode inlineCall = new FunctionCallNode(); IdentifierNode identNode = new IdentifierNode(); identNode.Name = ProtoCore.DSASM.Constants.kInlineConditionalMethodName; inlineCall.Function = identNode; DebugProperties.BreakpointOptions oldOptions = core.DebuggerProperties.breakOptions; DebugProperties.BreakpointOptions newOptions = oldOptions; newOptions |= DebugProperties.BreakpointOptions.EmitInlineConditionalBreakpoint; core.DebuggerProperties.breakOptions = newOptions; core.DebuggerProperties.highlightRange = new ProtoCore.CodeModel.CodeRange { StartInclusive = new ProtoCore.CodeModel.CodePoint { LineNo = parentNode.line, CharNo = parentNode.col }, EndExclusive = new ProtoCore.CodeModel.CodePoint { LineNo = parentNode.endLine, CharNo = parentNode.endCol } }; // As SSA conversion is enabled, we have got the values of // true and false branch, so it isn't necessary to create // language blocks. if (core.Options.GenerateSSA) { inlineCall.FormalArguments.Add(inlineConditionalNode.ConditionExpression); inlineCall.FormalArguments.Add(inlineConditionalNode.TrueExpression); inlineCall.FormalArguments.Add(inlineConditionalNode.FalseExpression); } else { // True condition language block BinaryExpressionNode bExprTrue = AstFactory.BuildReturnStatement(inlineConditionalNode.TrueExpression); LanguageBlockNode langblockT = new LanguageBlockNode(); int trueBlockId = Constants.kInvalidIndex; langblockT.codeblock.Language = ProtoCore.Language.Associative; core.AssocNode = bExprTrue; core.InlineConditionalBodyGraphNodes.Push(new List<GraphNode>()); EmitDynamicLanguageBlockNode(langblockT, bExprTrue, ref inferedType, ref trueBlockId, graphNode, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone); List<GraphNode> trueBodyNodes = core.InlineConditionalBodyGraphNodes.Pop(); // Append dependent nodes of the inline conditional foreach (GraphNode gnode in trueBodyNodes) foreach (GraphNode dNode in gnode.dependentList) graphNode.PushDependent(dNode); core.AssocNode = null; DynamicBlockNode dynBlockT = new DynamicBlockNode(trueBlockId); // False condition language block BinaryExpressionNode bExprFalse = AstFactory.BuildReturnStatement(inlineConditionalNode.FalseExpression); LanguageBlockNode langblockF = new LanguageBlockNode(); int falseBlockId = Constants.kInvalidIndex; langblockF.codeblock.Language = ProtoCore.Language.Associative; core.AssocNode = bExprFalse; core.InlineConditionalBodyGraphNodes.Push(new List<GraphNode>()); EmitDynamicLanguageBlockNode(langblockF, bExprFalse, ref inferedType, ref falseBlockId, graphNode, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone); List<GraphNode> falseBodyNodes = core.InlineConditionalBodyGraphNodes.Pop(); // Append dependent nodes of the inline conditional foreach (GraphNode gnode in falseBodyNodes) foreach (GraphNode dNode in gnode.dependentList) graphNode.PushDependent(dNode); core.AssocNode = null; DynamicBlockNode dynBlockF = new DynamicBlockNode(falseBlockId); inlineCall.FormalArguments.Add(inlineConditionalNode.ConditionExpression); inlineCall.FormalArguments.Add(dynBlockT); inlineCall.FormalArguments.Add(dynBlockF); } core.DebuggerProperties.breakOptions = oldOptions; core.DebuggerProperties.highlightRange = new ProtoCore.CodeModel.CodeRange { StartInclusive = new ProtoCore.CodeModel.CodePoint { LineNo = Constants.kInvalidIndex, CharNo = Constants.kInvalidIndex }, EndExclusive = new ProtoCore.CodeModel.CodePoint { LineNo = Constants.kInvalidIndex, CharNo = Constants.kInvalidIndex } }; // Save the pc and store it after the call EmitFunctionCallNode(inlineCall, ref inferedType, false, graphNode, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier); EmitFunctionCallNode(inlineCall, ref inferedType, false, graphNode, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, parentNode); // Need to restore those settings. if (graphNode != null) { graphNode.isInlineConditional = isInlineConditionalFlag; graphNode.updateBlock.startpc = startPC; graphNode.isReturn = isReturn; } } }
private void EmitLanguageBlockNode(ImperativeNode node, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode propogateUpdateGraphNode = null) { // // TODO Jun: // Add support for language blocks, classes and functions in GRAPH post july release // This Temporary guard will no longer be necessary bool disableLanguageBlocks = compileStateTracker.IsParsingCodeBlockNode || compileStateTracker.IsParsingPreloadedAssembly; if (disableLanguageBlocks) { compileStateTracker.BuildStatus.LogSemanticError("Defining language blocks are not yet supported"); } if (IsParsingGlobal() || IsParsingGlobalFunctionBody()) { LanguageBlockNode langblock = node as LanguageBlockNode; //(Fuqiang, Ayush) : Throwing an assert stops NUnit. Negative tests expect to catch a // CompilerException, so we throw that instead. //Debug.Assert(ProtoCore.Language.kInvalid != langblock.codeblock.language); if (ProtoCore.Language.kInvalid == langblock.codeblock.language) { throw new ProtoCore.Exceptions.CompileErrorsOccured("Invalid language block"); } ProtoCore.CompileTime.Context context = new ProtoCore.CompileTime.Context(); int entry = 0; int blockId = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.Language.kImperative == langblock.codeblock.language) { // TODO Jun: Move the associative and all common string into some table buildStatus.LogSyntaxError("An imperative language block is declared within an imperative language block.", compileStateTracker.CurrentDSFileName, langblock.line, langblock.col); } if (globalProcIndex != ProtoCore.DSASM.Constants.kInvalidIndex && compileStateTracker.ProcNode == null) { compileStateTracker.ProcNode = codeBlock.procedureTable.procList[globalProcIndex]; } compileStateTracker.Executives[langblock.codeblock.language].Compile(compileStateTracker, out blockId, codeBlock, langblock.codeblock, context, codeBlock.EventSink, langblock.CodeBlockNode); if (propogateUpdateGraphNode != null) { propogateUpdateGraphNode.languageBlockId = blockId; CodeBlock childBlock = compileStateTracker.CompleteCodeBlockList[blockId]; foreach (var subGraphNode in childBlock.instrStream.dependencyGraph.GraphList) { foreach (var depentNode in subGraphNode.dependentList) { if (depentNode.updateNodeRefList != null && depentNode.updateNodeRefList.Count > 0 && depentNode.updateNodeRefList[0].nodeList != null && depentNode.updateNodeRefList[0].nodeList.Count > 0) { SymbolNode dependentSymbol = depentNode.updateNodeRefList[0].nodeList[0].symbol; int symbolBlockId = dependentSymbol.codeBlockId; if (symbolBlockId != Constants.kInvalidIndex) { CodeBlock symbolBlock = compileStateTracker.CompleteCodeBlockList[symbolBlockId]; if (!symbolBlock.IsMyAncestorBlock(codeBlock.codeBlockId)) { propogateUpdateGraphNode.PushDependent(depentNode); } } } } } } setBlkId(blockId); inferedType = compileStateTracker.InferedType; //Debug.Assert(codeBlock.children[codeBlock.children.Count - 1].blockType == ProtoCore.DSASM.CodeBlockType.kLanguage); codeBlock.children[codeBlock.children.Count - 1].Attributes = PopulateAttributes(langblock.Attributes); #if ENABLE_EXCEPTION_HANDLING core.ExceptionHandlingManager.Register(blockId, globalProcIndex, globalClassIndex); #endif EmitInstrConsole("bounce " + blockId + ", " + entry.ToString()); EmitBounceIntrinsic(blockId, entry); // The callee language block will have stored its result into the RX register. EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); ProtoCore.DSASM.StackValue opRes = new ProtoCore.DSASM.StackValue(); opRes.optype = ProtoCore.DSASM.AddressType.Register; opRes.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opRes); } }
/// <summary> /// Pushes the symbol as a dependent to graphNode if codegeneration semantic conditions are met /// </summary> /// <param name="symbol"></param> /// <param name="graphNode"></param> private ProtoCore.AssociativeGraph.GraphNode PushSymbolAsDependent(SymbolNode symbol, ProtoCore.AssociativeGraph.GraphNode graphNode) { // Check for symbols that need to be pushed as dependents // Temporary properties and default args are autogenerated and are not part of the assocaitve behavior // For temp properties, refer to: EmitGettersForRHSIdentList // For default arg temp vars, refer to usage of: Constants.kTempDefaultArg if (CoreUtils.IsPropertyTemp(symbol.name) || CoreUtils.IsDefaultArgTemp(symbol.name)) { return null; } ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbol, UpdateNodeType.kSymbol); graphNode.PushDependent(dependentNode); return dependentNode; }
public override ProtoCore.DSASM.ProcedureNode TraverseFunctionCall(ProtoCore.AST.Node node, ProtoCore.AST.Node parentNode, int lefttype, int depth, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, ProtoCore.AST.Node bnode = null) { if (!IsParsingGlobal() && !IsParsingGlobalFunctionBody()) { return null; } //Debug.Assert(null == graphNode); FunctionCallNode funcCall = node as FunctionCallNode; string procName = funcCall.Function.Name; List<ProtoCore.Type> arglist = new List<ProtoCore.Type>(); foreach (ImperativeNode paramNode in funcCall.FormalArguments) { ProtoCore.Type paramType = new ProtoCore.Type(); paramType.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; paramType.IsIndexable = false; // If it's a binary node then continue type check, otherwise disable type check and just take the type of paramNode itself // f(1+2.0) -> type check enabled - param is typed as double // f(2) -> type check disabled - param is typed as int enforceTypeCheck = !(paramNode is BinaryExpressionNode); DfsTraverse(paramNode, ref paramType, false, graphNode, AssociativeSubCompilePass.kNone, bnode); enforceTypeCheck = true; arglist.Add(paramType); } ProtoCore.DSASM.ProcedureNode procNode = null; int type = ProtoCore.DSASM.Constants.kInvalidIndex; bool isConstructor = false; bool isStatic = false; bool hasLogError = false; int refClassIndex = ProtoCore.DSASM.Constants.kInvalidIndex; if (parentNode != null && parentNode is ProtoCore.AST.ImperativeAST.IdentifierListNode) { ProtoCore.AST.Node leftnode = (parentNode as ProtoCore.AST.ImperativeAST.IdentifierListNode).LeftNode; if (leftnode != null && leftnode is ProtoCore.AST.ImperativeAST.IdentifierNode) { refClassIndex = compileStateTracker.ClassTable.IndexOf(leftnode.Name); } } // If lefttype is a valid class then check if calling a constructor if ((int)ProtoCore.PrimitiveType.kInvalidType != inferedType.UID && (int)ProtoCore.PrimitiveType.kTypeVoid != inferedType.UID) { bool isAccessible; int realType; if (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex; procNode = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (procNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); isConstructor = procNode.isConstructor; isStatic = procNode.isStatic; type = lefttype = realType; if (!isAccessible) { type = lefttype = realType; string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); hasLogError = true; } } // To support unamed constructor, x = A(); else if (refClassIndex != Constants.kInvalidIndex) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticMethod, compileStateTracker.ClassTable.ClassNodes[refClassIndex].name, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return null; } else { int classIndex = compileStateTracker.ClassTable.IndexOf(procName); int dummy; if (classIndex != Constants.kInvalidIndex) { procNode = compileStateTracker.ClassTable.ClassNodes[classIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out dummy, true); if (procNode != null && procNode.isConstructor) { type = classIndex; } else { procNode = null; } } } } } // Try function pointer firstly if ((procNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)) { bool isAccessibleFp; ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAllocated = VerifyAllocation(procName, globalClassIndex, globalProcIndex, out symbolnode, out isAccessibleFp); if (isAllocated) // not checking the type against function pointer, as the type could be var { procName = ProtoCore.DSASM.Constants.kFunctionPointerCall; // The graph node always depends on this function pointer if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } } } // Always try global function firstly. Because we dont have syntax // support for calling global function (say, ::foo()), if we try // member function firstly, there is no way to call a global function // For member function, we can use this.foo() to distinguish it from // global function. if ((procNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)) { procNode = compileStateTracker.GetFirstVisibleProcedure(procName, arglist, codeBlock); if (null != procNode) { type = ProtoCore.DSASM.Constants.kGlobalScope; if (compileStateTracker.TypeSystem.IsHigherRank(procNode.returntype.UID, inferedType.UID)) { inferedType = procNode.returntype; } } } // Try member functions in global class scope if ((procNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) && (parentNode == null)) { if (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) { int realType; bool isAccessible; bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex; ProtoCore.DSASM.ProcedureNode memProcNode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (memProcNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); procNode = memProcNode; inferedType = procNode.returntype; type = realType; if (!isAccessible) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return null; } } } } if (null != procNode) { inferedType = procNode.returntype; //if call is replication call if (procNode.isThisCallReplication) { inferedType.IsIndexable = true; inferedType.rank++; } if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { // The function is at block 0 if its a constructor, member or at the globals scope. // Its at block 1 if its inside a language block. // Its limited to block 1 as of R1 since we dont support nested function declarations yet int blockId = procNode.runtimeIndex; //push value-not-provided default argument for (int i = arglist.Count; i < procNode.argInfoList.Count; i++) { EmitDefaultArgNode(); } // Push the function declaration block // Jun TODO: Implementeation of indexing into a function call: // x = f()[0][1] int dimensions = 0; EmitPushVarData(blockId, dimensions); // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, procNode.name); DebugProperties.BreakpointOptions oldOptions = compileStateTracker.DebugProps.breakOptions; if(procNode.name.StartsWith(Constants.kSetterPrefix)) { EmitCall(procNode.procId, type, depth, parentNode.line, parentNode.col, parentNode.endLine, parentNode.endCol); } /*else if(procNode.isExternal) { EmitCall(procNode.procId, type, depth); }*/ else if (bnode != null) { EmitCall(procNode.procId, type, depth, bnode.line, bnode.col, bnode.endLine, bnode.endCol); } else if (!procNode.name.Equals(Constants.kFunctionRangeExpression) || oldOptions.HasFlag(DebugProperties.BreakpointOptions.EmitCallrForTempBreakpoint)) { EmitCall(procNode.procId, type, depth, node.line, node.col, node.endLine, node.endCol); } else { EmitCall(procNode.procId, type, depth); } EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); } } else { if (depth <= 0 && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { if (!hasLogError) { if (!compileStateTracker.Options.SuppressFunctionResolutionWarning || parentNode == null) { string property; if (CoreUtils.TryGetPropertyName(procName, out property)) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kPropertyNotFound, property); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kPropertyNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodNotFound, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } } inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); } } else { if (procName == ProtoCore.DSASM.Constants.kFunctionPointerCall && depth == 0) { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(procName, arglist, lefttype); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); var iNode = nodeBuilder.BuildIdentfier(funcCall.Function.Name); EmitIdentifierNode(iNode, ref inferedType); } else { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(funcCall.Function.Name, arglist, lefttype); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); } // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, funcCall.Function.Name + "[dynamic]"); EmitDynamicCall(compileStateTracker.DynamicFunctionTable.functionTable.Count - 1, globalClassIndex, depth, funcCall.line, funcCall.col, funcCall.endLine, funcCall.endCol); // The function return value EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); //assign inferedType to var inferedType.UID = (int)PrimitiveType.kTypeVar; } } return procNode; }
private void EmitIdentifierNode(ImperativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null) { IdentifierNode t = node as IdentifierNode; if (t.Name.Equals(ProtoCore.DSDefinitions.Kw.kw_this)) { if (localProcedure != null) { if (localProcedure.isStatic) { string message = ProtoCore.BuildData.WarningMessage.kUsingThisInStaticFunction; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } else if (localProcedure.classScope == Constants.kGlobalScope) { string message = ProtoCore.BuildData.WarningMessage.kInvalidThis; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } else { EmitThisPointerNode(); return; } } else { string message = ProtoCore.BuildData.WarningMessage.kInvalidThis; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } } int dimensions = 0; int runtimeIndex = codeBlock.symbolTable.runtimeIndex; ProtoCore.Type type = new ProtoCore.Type(); type.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; type.IsIndexable = false; ProtoCore.DSASM.SymbolNode symbolnode = null; //bool isAllocated = VerifyAllocation(t.Value, out blockId, out localAllocBlock, out symindex, ref type); //bool allocatedLocally = isAllocated && core.runtimeTableIndex == localAllocBlock; //bool allocatedExternally = isAllocated && core.runtimeTableIndex > localAllocBlock; //bool isVisible = isAllocated && core.runtimeTableIndex >= localAllocBlock; bool isAccessible = false; if (null == t.ArrayDimensions) { //check if it is a function instance ProtoCore.DSASM.ProcedureNode procNode = null; procNode = compileStateTracker.GetFirstVisibleProcedure(t.Name, null, codeBlock); if (null != procNode) { if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { // A global function inferedType.IsIndexable = false; inferedType.UID = (int)PrimitiveType.kTypeFunctionPointer; int fptr = compileStateTracker.FunctionPointerTable.functionPointerDictionary.Count; ProtoCore.DSASM.FunctionPointerNode fptrNode = new ProtoCore.DSASM.FunctionPointerNode(procNode.procId, procNode.runtimeIndex); compileStateTracker.FunctionPointerTable.functionPointerDictionary.TryAdd(fptr, fptrNode); compileStateTracker.FunctionPointerTable.functionPointerDictionary.TryGetBySecond(fptrNode, out fptr); EmitPushVarData(runtimeIndex, 0); EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Name); ProtoCore.DSASM.StackValue opFunctionPointer = new ProtoCore.DSASM.StackValue(); opFunctionPointer.optype = ProtoCore.DSASM.AddressType.FunctionPointer; opFunctionPointer.opdata = fptr; opFunctionPointer.opdata_d = fptr; EmitPush(opFunctionPointer, t.line, t.col); return; } } } bool isAllocated = VerifyAllocation(t.Value, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); if (!isAllocated || !isAccessible) { if (isAllocated) { if (!isAccessible) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kPropertyIsInaccessible, t.Value); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, t.line, t.col); } } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kUnboundIdentifierMsg, t.Value); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kIdUnboundIdentifier, message, compileStateTracker.CurrentDSFileName, t.line, t.col); } inferedType.UID = (int)ProtoCore.PrimitiveType.kTypeNull; // Jun Comment: Specification excerpt // If resolution fails at this point a com.Design-Script.Imperative.Core.UnboundIdentifier // warning is emitted during pre-execute phase, and at the ID is bound to null. (R1 - Feb) EmitPushNull(); EmitPushVarData(runtimeIndex, dimensions); ProtoCore.Type varType = compileStateTracker.TypeSystem.BuildTypeObject((int)PrimitiveType.kTypeVar, false, 0); symbolnode = Allocate(t.Value, globalProcIndex, varType); EmitInstrConsole(ProtoCore.DSASM.kw.pop, t.Value); EmitPopForSymbol(symbolnode); } else { type = symbolnode.datatype; runtimeIndex = symbolnode.runtimeTableIndex; if (compileStateTracker.Options.AssociativeToImperativePropagation) { // Comment Jun: If this symbol belongs to an outer block, then append it to this language blocks dependent if (symbolnode.codeBlockId != codeBlock.codeBlockId) { // A parent codeblock owns this symbol if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } } } } if (null != t.ArrayDimensions) { dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions); } //fix type's rank //fix type's rank if (type.rank >= 0) { type.rank -= dimensions; if (type.rank < 0) { //throw new Exception("Exceed maximum rank!"); type.rank = 0; } } //check whether the value is an array if (type.rank == 0) { type.IsIndexable = false; } EmitPushVarData(runtimeIndex, dimensions); EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Value); EmitPushForSymbol(symbolnode, t); if (compileStateTracker.TypeSystem.IsHigherRank(type.UID, inferedType.UID)) { inferedType = type; } // We need to get inferedType for boolean variable so that we can perform type check inferedType.UID = (isBooleanOp || (type.UID == (int)PrimitiveType.kTypeBool)) ? (int)PrimitiveType.kTypeBool : type.UID; }
/* proc EmitIdentNode(identnode, graphnode) if ssa // Check an if this identifier is array indexed // The array index is a secondary property and is not the original array property of the AST. this is required because this array index is meant only to resolve graphnode dependency with arrays if node.arrayindex.secondary is valid dimension = traverse(node.arrayindex.secondary) // Create a new dependent with the array indexing dependent = new GraphNode(identnode.name, dimension) graphnode.pushdependent(dependent) end end end */ private void EmitIdentifierNode(AssociativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, BinaryExpressionNode parentNode = null) { IdentifierNode t = node as IdentifierNode; if (t.Name.Equals(ProtoCore.DSDefinitions.Keyword.This)) { if (subPass != AssociativeSubCompilePass.kNone) { return; } if (localProcedure != null) { if (localProcedure.isStatic) { string message = ProtoCore.BuildData.WarningMessage.kUsingThisInStaticFunction; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } else if (localProcedure.classScope == Constants.kGlobalScope) { string message = ProtoCore.BuildData.WarningMessage.kInvalidThis; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } else { EmitThisPointerNode(subPass); return; } } else { string message = ProtoCore.BuildData.WarningMessage.kInvalidThis; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } } int dimensions = 0; ProtoCore.DSASM.SymbolNode symbolnode = null; int runtimeIndex = codeBlock.symbolTable.runtimeIndex; ProtoCore.Type type = new ProtoCore.Type(); type.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; type.IsIndexable = false; bool isAccessible = false; if (null == t.ArrayDimensions) { //check if it is a function instance ProtoCore.DSASM.ProcedureNode procNode = null; procNode = compileStateTracker.GetFirstVisibleProcedure(t.Name, null, codeBlock); if (null != procNode) { if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { // A global function inferedType.IsIndexable = false; inferedType.UID = (int)PrimitiveType.kTypeFunctionPointer; if (ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier != subPass) { int fptr = compileStateTracker.FunctionPointerTable.functionPointerDictionary.Count; ProtoCore.DSASM.FunctionPointerNode fptrNode = new ProtoCore.DSASM.FunctionPointerNode(procNode.procId, procNode.runtimeIndex); compileStateTracker.FunctionPointerTable.functionPointerDictionary.TryAdd(fptr, fptrNode); compileStateTracker.FunctionPointerTable.functionPointerDictionary.TryGetBySecond(fptrNode, out fptr); EmitPushVarData(runtimeIndex, 0); EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Name); ProtoCore.DSASM.StackValue opFunctionPointer = new ProtoCore.DSASM.StackValue(); opFunctionPointer.optype = ProtoCore.DSASM.AddressType.FunctionPointer; opFunctionPointer.opdata = fptr; opFunctionPointer.opdata_d = fptr; EmitPush(opFunctionPointer, t.line, t.col); } return; } } } bool isAllocated = VerifyAllocation(t.Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); // If its executing in interpreter mode - attempt to find and anubond identifer in a child block // Remove this, because if we are watching cases like: //c1 = [Imperative] //{ // a = 1; // b = 2; //} // //c2 = [Associative] //{ // a = 3; // b = 4; //} //After c2 is executed, the watch value for a, b will be 1, 2. //if (ProtoCore.DSASM.ExecutionMode.kExpressionInterpreter == core.ExecMode) //{ // if (!isAllocated) // { // isAllocated = VerifyAllocationIncludingChildBlock(t.Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); // } //} if (AssociativeSubCompilePass.kUnboundIdentifier == subPass) { if (symbolnode == null) { if (isAllocated) { string message = String.Format(WarningMessage.kPropertyIsInaccessible, t.Value); if (localProcedure != null && localProcedure.isStatic) { SymbolNode tempSymbolNode; VerifyAllocation( t.Name, globalClassIndex, Constants.kGlobalScope, out tempSymbolNode, out isAccessible); if (tempSymbolNode != null && !tempSymbolNode.isStatic && isAccessible) { message = String.Format(WarningMessage.kUsingNonStaticMemberInStaticContext, t.Value); } } buildStatus.LogWarning( ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, t.line, t.col); } else { string message = String.Format(WarningMessage.kUnboundIdentifierMsg, t.Value); buildStatus.LogWarning(WarningID.kIdUnboundIdentifier, message, compileStateTracker.CurrentDSFileName, t.line, t.col); } if (ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter != compileStateTracker.ExecMode) { inferedType.UID = (int)ProtoCore.PrimitiveType.kTypeNull; // Jun Comment: Specification // If resolution fails at this point a com.Design-Script.Imperative.Core.UnboundIdentifier // warning is emitted during pre-execute phase, and at the ID is bound to null. (R1 - Feb) int startpc = pc; EmitPushNull(); // Push the identifier local block dimensions = 0; EmitPushVarData(runtimeIndex, dimensions); ProtoCore.Type varType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, false, 0); // TODO Jun: Refactor Allocate() to just return the symbol node itself ProtoCore.DSASM.SymbolNode symnode = Allocate(globalClassIndex, globalClassIndex, globalProcIndex, t.Value, varType, ProtoCore.DSASM.Constants.kPrimitiveSize, false, ProtoCore.DSASM.AccessSpecifier.kPublic, ProtoCore.DSASM.MemoryRegion.kMemStack, t.line, t.col, graphNode); Debug.Assert(symnode != null); int symbolindex = symnode.symbolTableIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex) { symbolnode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList[symbolindex]; } else { symbolnode = codeBlock.symbolTable.symbolList[symbolindex]; } EmitInstrConsole(ProtoCore.DSASM.kw.pop, t.Value); EmitPopForSymbol(symnode); // Comment it out. It doesn't work for the following // case: // // x = foo.X; // x = bar.X; // // where bar hasn't defined yet, so a null assign // graph is generated for this case: // // bar = null; // x = %dot(.., {bar}, ...); // // unfortunately the expression UID of this null graph // node is 0, which is wrong. Some update routines have // the assumption that the exprUID of graph node is // incremental. // // We may generate SSA for all expressions to fix this // issue. -Yu Ke /* ProtoCore.AssociativeGraph.GraphNode nullAssignGraphNode = new ProtoCore.AssociativeGraph.GraphNode(); nullAssignGraphNode.PushSymbolReference(symbolnode); nullAssignGraphNode.procIndex = globalProcIndex; nullAssignGraphNode.classIndex = globalClassIndex; nullAssignGraphNode.updateBlock.startpc = startpc; nullAssignGraphNode.updateBlock.endpc = pc - 1; codeBlock.instrStream.dependencyGraph.Push(nullAssignGraphNode); */ } } if (null != t.ArrayDimensions) { dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions, graphNode, parentNode, subPass); } } else { if (compileStateTracker.ExecMode == ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter && !isAllocated) { // It happens when the debugger try to watch a variable // which has been out of scope (as watch is done through // execute an expression "t = v;" where v is the variable // to be watched. EmitPushNull(); return; } Validity.Assert(isAllocated); if (graphNode != null && IsAssociativeArrayIndexing && !CoreUtils.IsAutoGeneratedVar(symbolnode.name)) { ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode(); updateNode.symbol = symbolnode; updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol; if (graphNode.isIndexingLHS) { graphNode.dimensionNodeList.Add(updateNode); } else { int curDepIndex = graphNode.dependentList.Count - 1; if (curDepIndex >= 0) { var curDep = graphNode.dependentList[curDepIndex].updateNodeRefList[0].nodeList[0]; curDep.dimensionNodeList.Add(updateNode); if (null != firstSSAGraphNode) { curDepIndex = firstSSAGraphNode.dependentList.Count - 1; if (curDepIndex >= 0) { ProtoCore.AssociativeGraph.UpdateNode firstSSAUpdateNode = firstSSAGraphNode.dependentList[curDepIndex].updateNodeRefList[0].nodeList[0]; firstSSAUpdateNode.dimensionNodeList.Add(updateNode); } } } } } // If it is a property, replaced it with getter: %get_prop() if (symbolnode.classScope != ProtoCore.DSASM.Constants.kInvalidIndex && symbolnode.functionIndex == ProtoCore.DSASM.Constants.kGlobalScope && localProcedure != null) { string getterName = ProtoCore.DSASM.Constants.kGetterPrefix + t.Name; if (!string.Equals(localProcedure.name, getterName)) { var thisNode = nodeBuilder.BuildIdentfier(ProtoCore.DSDefinitions.Keyword.This); var identListNode = nodeBuilder.BuildIdentList(thisNode, t); EmitIdentifierListNode(identListNode, ref inferedType, false, graphNode, ProtoCore.DSASM.AssociativeSubCompilePass.kNone); if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } return; } } type = symbolnode.datatype; runtimeIndex = symbolnode.runtimeTableIndex; // The graph node always depends on this identifier if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } bool emitReplicationGuideFlag = emitReplicationGuide; emitReplicationGuide = false; if (null != t.ArrayDimensions) { dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions, graphNode, parentNode, subPass); } emitReplicationGuide = emitReplicationGuideFlag; //fix type's rank if (type.rank >= 0) { type.rank -= dimensions; if (type.rank < 0) { //throw new Exception("Exceed maximum rank!"); type.rank = 0; } } //check whether the value is an array if (type.rank == 0) { type.IsIndexable = false; } EmitPushVarData(runtimeIndex, dimensions); if (ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter == compileStateTracker.ExecMode) { EmitInstrConsole(ProtoCore.DSASM.kw.pushw, t.Value); EmitPushForSymbolW(symbolnode, t.line, t.col); } else { EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Value); EmitPushForSymbol(symbolnode, t); if (compileStateTracker.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide) { int guides = EmitReplicationGuides(t.ReplicationGuides); EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, guides + "[guide]"); EmitPushReplicationGuide(guides); } } if (ignoreRankCheck || compileStateTracker.TypeSystem.IsHigherRank(type.UID, inferedType.UID)) { inferedType = type; } // We need to get inferedType for boolean variable so that we can perform type check inferedType.UID = (isBooleanOp || (type.UID == (int)PrimitiveType.kTypeBool)) ? (int)PrimitiveType.kTypeBool : inferedType.UID; } }
public ProtoCore.DSASM.ProcedureNode TraverseDotFunctionCall(ProtoCore.AST.Node node, ProtoCore.AST.Node parentNode, int lefttype, int depth, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, ProtoCore.AST.AssociativeAST.BinaryExpressionNode bnode = null) { FunctionCallNode funcCall = null; ProtoCore.DSASM.ProcedureNode procCallNode = null; ProtoCore.DSASM.ProcedureNode procDotCallNode = null; string procName = null; List<ProtoCore.Type> arglist = new List<ProtoCore.Type>(); ProtoCore.Type dotCallType = new ProtoCore.Type(); dotCallType.UID = (int)PrimitiveType.kTypeVar; dotCallType.IsIndexable = false; bool isConstructor = false; bool isStaticCall = false; bool isStaticCallAllowed = false; bool isUnresolvedDot = false; bool isUnresolvedMethod = false; int classIndex = ProtoCore.DSASM.Constants.kInvalidIndex; string className = string.Empty; ProtoCore.AST.AssociativeAST.FunctionDotCallNode dotCall = node as ProtoCore.AST.AssociativeAST.FunctionDotCallNode; funcCall = dotCall.DotCall; procName = dotCall.FunctionCall.Function.Name; List<AssociativeNode> replicationGuide = (dotCall.FunctionCall.Function as IdentifierNode).ReplicationGuides; var dotCallFirstArgument = dotCall.DotCall.FormalArguments[0]; if (dotCallFirstArgument is FunctionDotCallNode) { isUnresolvedDot = true; } else if (dotCallFirstArgument is IdentifierNode || dotCallFirstArgument is ThisPointerNode) { // Check if the lhs identifer is a class name string lhsName = ""; int ci = Constants.kInvalidIndex; if (dotCallFirstArgument is IdentifierNode) { lhsName = (dotCallFirstArgument as IdentifierNode).Name; ci = compileStateTracker.ClassTable.IndexOf(lhsName); classIndex = ci; className = lhsName; // As a class name can be used as property name, we need to // check if this identifier is a property or a class name. // if (ci != Constants.kInvalidIndex && globalClassIndex != Constants.kInvalidIndex) { ProtoCore.DSASM.SymbolNode symbolnode; bool isAccessbile = false; bool hasAllocated = VerifyAllocation(lhsName, globalClassIndex, globalProcIndex, out symbolnode, out isAccessbile); // Well, found a property whose name is class name. Now // we need to check if the RHS function call is // constructor or not. if (hasAllocated && isAccessbile && symbolnode.functionIndex == ProtoCore.DSASM.Constants.kInvalidIndex) { var procnode = GetProcedureFromInstance(ci, dotCall.FunctionCall); if (procnode != null && !procnode.isConstructor) { ci = Constants.kInvalidIndex; lhsName = ""; } } } } if (ci != ProtoCore.DSASM.Constants.kInvalidIndex) { // It is a class name dotCall.DotCall.FormalArguments[0] = new IntNode { value = ci.ToString() }; dotCallFirstArgument = dotCall.DotCall.FormalArguments[0]; inferedType.UID = dotCallType.UID = ci; string rhsName = dotCall.FunctionCall.Function.Name; procCallNode = GetProcedureFromInstance(ci, dotCall.FunctionCall, graphNode); if (null != procCallNode) { isConstructor = procCallNode.isConstructor; // It's a static call if its not a constructor isStaticCall = !procCallNode.isConstructor; // If this is a static call and the first method found was not static // Look further if (isStaticCall && !procCallNode.isStatic) { ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.ClassTable.ClassNodes[ci].GetFirstStaticMemberFunction(procName); if (null != staticProcCallNode) { procCallNode = staticProcCallNode; } } isStaticCallAllowed = procCallNode.isStatic && isStaticCall; } else { ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.ClassTable.ClassNodes[ci].GetFirstStaticMemberFunction(procName); string functionName = dotCall.FunctionCall.Function.Name; string property; if (null != staticProcCallNode) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodHasInvalidArguments, functionName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else if (CoreUtils.TryGetPropertyName(functionName, out property)) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticProperty, lhsName, property); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticMethod, lhsName, functionName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } } } if (dotCall.DotCall.FormalArguments.Count == ProtoCore.DSASM.Constants.kDotCallArgCount) { if (dotCallFirstArgument is IdentifierNode) { ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool isAllocated = VerifyAllocation((dotCallFirstArgument as IdentifierNode).Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); if (isAllocated && symbolnode.datatype.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = symbolnode.datatype.UID; if (ProtoCore.DSASM.Constants.kInvalidIndex != inferedType.UID) { procCallNode = GetProcedureFromInstance(symbolnode.datatype.UID, dotCall.FunctionCall); } if (null != procCallNode) { if (procCallNode.isConstructor) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { // A constructor cannot be called from an instance string message = String.Format(ProtoCore.BuildData.WarningMessage.KCallingConstructorOnInstance, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingConstructorOnInstance, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } isUnresolvedDot = true; isUnresolvedMethod = true; } else { isAccessible = procCallNode.access == ProtoCore.DSASM.AccessSpecifier.kPublic || (procCallNode.access == ProtoCore.DSASM.AccessSpecifier.kPrivate && procCallNode.classScope == globalClassIndex); if (!isAccessible) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } } if (null != procCallNode) { int dynamicRhsIndex = int.Parse((dotCall.DotCall.FormalArguments[1] as IntNode).value); compileStateTracker.DynamicFunctionTable.functionTable[dynamicRhsIndex].classIndex = procCallNode.classScope; compileStateTracker.DynamicFunctionTable.functionTable[dynamicRhsIndex].procedureIndex = procCallNode.procId; compileStateTracker.DynamicFunctionTable.functionTable[dynamicRhsIndex].pc = procCallNode.pc; } } } } else { isUnresolvedDot = true; } } else if (dotCallFirstArgument is ThisPointerNode) { if (globalClassIndex != Constants.kInvalidIndex) { procCallNode = GetProcedureFromInstance(globalClassIndex, dotCall.FunctionCall); if (null != procCallNode && procCallNode.isConstructor) { dotCall.DotCall.FormalArguments[0] = new IntNode { value = globalClassIndex.ToString() }; dotCallFirstArgument = dotCall.DotCall.FormalArguments[0]; inferedType.UID = dotCallType.UID = ci; } } } } } else if (funcCall.FormalArguments[0] is IntNode) { inferedType.UID = dotCallType.UID = int.Parse((funcCall.FormalArguments[0] as IntNode).value); classIndex = inferedType.UID; procCallNode = GetProcedureFromInstance(dotCallType.UID, dotCall.FunctionCall, graphNode); if (null != procCallNode) { // It's a static call if its not a constructor isConstructor = procCallNode.isConstructor; isStaticCall = !procCallNode.isConstructor; // If this is a static call and the first method found was not static // Look further if (isStaticCall && !procCallNode.isStatic) { ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetFirstStaticMemberFunction(procName); if (null != staticProcCallNode) { procCallNode = staticProcCallNode; } } isStaticCallAllowed = procCallNode.isStatic && isStaticCall; className = compileStateTracker.ClassTable.ClassNodes[dotCallType.UID].name; if (isStaticCall && !isStaticCallAllowed) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { string property; className = compileStateTracker.ClassTable.ClassNodes[dotCallType.UID].name; ProtoCore.DSASM.ProcedureNode staticProcCallNode = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetFirstStaticMemberFunction(procName); if (null != staticProcCallNode) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodHasInvalidArguments, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else if (CoreUtils.TryGetPropertyName(procName, out property)) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticProperty, property, className); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingNonStaticMethod, procName, className); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, compileStateTracker.CurrentDSFileName, dotCall.line, dotCall.col); } } isUnresolvedMethod = true; } else { inferedType = procCallNode.returntype; } } } // Its an accceptable method at this point if (!isUnresolvedMethod) { int funtionArgCount = 0; //foreach (AssociativeNode paramNode in funcCall.FormalArguments) for (int n = 0; n < funcCall.FormalArguments.Count; ++n) { AssociativeNode paramNode = funcCall.FormalArguments[n]; ProtoCore.Type paramType = new ProtoCore.Type(); paramType.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; paramType.IsIndexable = false; emitReplicationGuide = false; // If it's a binary node then continue type check, otherwise disable type check and just take the type of paramNode itself // f(1+2.0) -> type check enabled - param is typed as double // f(2) -> type check disabled - param is typed as int enforceTypeCheck = !(paramNode is BinaryExpressionNode); // TODO Jun: Cleansify me // What im doing is just taking the second parameter of the dot op (The method call) // ...and adding it to the graph node dependencies if (ProtoCore.DSASM.Constants.kDotArgIndexDynTableIndex == n) { if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { if (!isConstructor) { if (null != procCallNode) { if (graphNode.dependentList.Count > 0) { ProtoCore.AssociativeGraph.UpdateNodeRef nodeRef = new ProtoCore.AssociativeGraph.UpdateNodeRef(); ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode(); ProtoCore.DSASM.ProcedureNode procNodeDummy = new ProtoCore.DSASM.ProcedureNode(); if (procCallNode.isAutoGenerated) { ProtoCore.DSASM.SymbolNode sym = new ProtoCore.DSASM.SymbolNode(); sym.name = procName.Remove(0, ProtoCore.DSASM.Constants.kSetterPrefix.Length); updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol; updateNode.symbol = sym; } else { procNodeDummy.name = procName; updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kMethod; updateNode.procNode = procNodeDummy; } graphNode.dependentList[0].updateNodeRefList[0].nodeList.Add(updateNode); } } else { // comment Jun: // This is dotarg whos first argument is also a dotarg // dotarg(dorarg...)...) if (graphNode.dependentList.Count > 0) { if (ProtoCore.Utils.CoreUtils.IsGetterSetter(procName)) { ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode(); ProtoCore.DSASM.SymbolNode sym = new ProtoCore.DSASM.SymbolNode(); sym.name = procName.Remove(0, ProtoCore.DSASM.Constants.kSetterPrefix.Length); updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol; updateNode.symbol = sym; graphNode.dependentList[0].updateNodeRefList[0].nodeList.Add(updateNode); } } } } } } // Traversing the first arg (the LHS pointer/Static instanct/Constructor if (ProtoCore.DSASM.Constants.kDotArgIndexPtr == n) { // Comment Jun: // Allow guides only on 'this' pointers for non getter/setter methods // No guides for 'this' pointers in constructors calls (There is no this pointer yet) // /* class C { def f(a : int) { return = 10; } } p = {C.C(), C.C()}; x = p<1>.f({1,2}<2>); // guides allowed on the pointer 'p' class A { x : var[]; constructor A() { x = {1,2}; } } a = A.A(); b = A.A(); c = a<1>.x<2>; // guides not allowed on getter */ if (!ProtoCore.Utils.CoreUtils.IsGetterSetter(procName) && !isConstructor) { emitReplicationGuide = true; } DfsTraverse(paramNode, ref paramType, false, graphNode, subPass, bnode); if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { if (isStaticCall && isStaticCallAllowed) { Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != classIndex); Validity.Assert(string.Empty != className); SymbolNode classSymbol = new SymbolNode(); classSymbol.name = className; classSymbol.classScope = classIndex; ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(classSymbol, ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol); graphNode.PushDependent(dependentNode); } } } // Traversing the actual arguments passed into the function (not the dot function) else if (ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs == n) { int defaultAdded = 0; // If its null this is the second call in a chained dot if (null != procCallNode) { // Check how many args were passed in.... against what is expected defaultAdded = procCallNode.argInfoList.Count - dotCall.FunctionCall.FormalArguments.Count; } // Enable graphnode dependencies if its a setter method bool allowDependentState = null != graphNode ? graphNode.allowDependents : false; if (ProtoCore.Utils.CoreUtils.IsSetter(procName)) { // If the arguments are not temporaries ProtoCore.AST.AssociativeAST.ExprListNode exprList = paramNode as ExprListNode; Validity.Assert(1 == exprList.list.Count); string varname = string.Empty; if (exprList.list[0] is IdentifierNode) { varname = (exprList.list[0] as IdentifierNode).Name; // Only allow the acutal function variables and SSA temp vars // TODO Jun: determine what temp could be passed in that is autodegenerated and non-SSA if (!ProtoCore.Utils.CoreUtils.IsAutoGeneratedVar(varname) || ProtoCore.Utils.CoreUtils.IsSSATemp(varname)) { graphNode.allowDependents = true; } } else { graphNode.allowDependents = true; } } emitReplicationGuide = true; if (defaultAdded > 0) { ProtoCore.AST.AssociativeAST.ExprListNode exprList = paramNode as ExprListNode; if (subPass != AssociativeSubCompilePass.kUnboundIdentifier) { for (int i = 0; i < defaultAdded; i++) { exprList.list.Add(new DefaultArgNode()); } } DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); funtionArgCount = exprList.list.Count; } else { Validity.Assert(paramNode is ProtoCore.AST.AssociativeAST.ExprListNode); ProtoCore.AST.AssociativeAST.ExprListNode exprList = paramNode as ProtoCore.AST.AssociativeAST.ExprListNode; // Comment Jun: This is a getter/setter or a an auto-generated thisarg function... // ...add the dynamic sv that will be resolved as a pointer at runtime if (!isStaticCall && !isConstructor) { //if (null != procCallNode && ProtoCore.Utils.CoreUtils.IsGetterSetter(procCallNode.name) && AssociativeSubCompilePass.kNone == subPass) // TODO Jun: pls get rid of subPass checking outside the core travesal if (ProtoCore.DSASM.AssociativeSubCompilePass.kNone == subPass) { exprList.list.Insert(0, new DynamicNode()); } } if (exprList.list.Count > 0) { foreach (ProtoCore.AST.AssociativeAST.AssociativeNode exprListNode in exprList.list) { bool repGuideState = emitReplicationGuide; if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { if (exprListNode is ProtoCore.AST.AssociativeAST.ExprListNode || exprListNode is ProtoCore.AST.AssociativeAST.GroupExpressionNode) { if (compileStateTracker.Options.TempReplicationGuideEmptyFlag) { // Emit the replication guide for the exprlist List<ProtoCore.AST.AssociativeAST.AssociativeNode> repGuideList = GetReplicationGuides(exprListNode); EmitReplicationGuides(repGuideList, true); emitReplicationGuide = false; // Pop off the guide if the current element was an array if (null != repGuideList) { EmitInstrConsole(ProtoCore.DSASM.kw.popg); EmitPopGuide(); } } } } else { emitReplicationGuide = false; } DfsTraverse(exprListNode, ref paramType, false, graphNode, subPass, bnode); emitReplicationGuide = repGuideState; } if (subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { EmitInstrConsole(ProtoCore.DSASM.kw.alloca, exprList.list.Count.ToString()); EmitPopArray(exprList.list.Count); if (exprList.ArrayDimensions != null) { int dimensions = DfsEmitArrayIndexHeap(exprList.ArrayDimensions, graphNode); EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, dimensions.ToString() + "[dim]"); EmitPushArrayIndex(dimensions); } } } else { if (exprList != null) { bool emitReplicationGuideState = emitReplicationGuide; emitReplicationGuide = false; DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); emitReplicationGuide = emitReplicationGuideState; } else { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); } } funtionArgCount = exprList.list.Count; } emitReplicationGuide = false; // Restore the state only if it is a setter method if (ProtoCore.Utils.CoreUtils.IsSetter(procName)) { graphNode.allowDependents = allowDependentState; } } else if (ProtoCore.DSASM.Constants.kDotArgIndexArgCount == n) { ProtoCore.AST.AssociativeAST.IntNode argNumNode = new ProtoCore.AST.AssociativeAST.IntNode() { value = funtionArgCount.ToString() }; DfsTraverse(argNumNode, ref paramType, false, graphNode, subPass); } else { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); } emitReplicationGuide = false; enforceTypeCheck = true; arglist.Add(paramType); } } if (subPass == ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { return null; } // Comment Jun: Append the lhs pointer as an argument to the overloaded function if (!isConstructor && !isStaticCall) { Validity.Assert(dotCall.DotCall.FormalArguments[ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs] is ExprListNode); ExprListNode functionArgs = dotCall.DotCall.FormalArguments[ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs] as ExprListNode; functionArgs.list.Insert(0, dotCall.DotCall.FormalArguments[ProtoCore.DSASM.Constants.kDotArgIndexPtr]); } if (isUnresolvedMethod) { EmitNullNode(new NullNode(), ref inferedType); return null; } procDotCallNode = compileStateTracker.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotArgMethodName, arglist, codeBlock); // From here on, handle the actual procedure call int type = ProtoCore.DSASM.Constants.kInvalidIndex; int refClassIndex = ProtoCore.DSASM.Constants.kInvalidIndex; if (parentNode != null && parentNode is ProtoCore.AST.AssociativeAST.IdentifierListNode) { ProtoCore.AST.Node leftnode = (parentNode as ProtoCore.AST.AssociativeAST.IdentifierListNode).LeftNode; if (leftnode != null && leftnode is ProtoCore.AST.AssociativeAST.IdentifierNode) { refClassIndex = compileStateTracker.ClassTable.IndexOf(leftnode.Name); } } if (dotCallFirstArgument is FunctionCallNode || dotCallFirstArgument is FunctionDotCallNode || dotCallFirstArgument is ExprListNode) { inferedType.UID = arglist[0].UID; } // If lefttype is a valid class then check if calling a constructor if ((int)ProtoCore.PrimitiveType.kInvalidType != inferedType.UID && (int)ProtoCore.PrimitiveType.kTypeVoid != inferedType.UID && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex; procCallNode = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetFirstMemberFunction(procName); } // Try function pointer firstly if ((procCallNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)) { bool isAccessibleFp; ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAllocated = VerifyAllocation(procName, globalClassIndex, globalProcIndex, out symbolnode, out isAccessibleFp); if (isAllocated) // not checking the type against function pointer, as the type could be var { procName = ProtoCore.DSASM.Constants.kFunctionPointerCall; // The graph node always depends on this function pointer if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } } } // Always try global function firstly. Because we dont have syntax // support for calling global function (say, ::foo()), if we try // member function firstly, there is no way to call a global function // For member function, we can use this.foo() to distinguish it from // global function. if ((procCallNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)) { procCallNode = compileStateTracker.GetFirstVisibleProcedure(procName, arglist, codeBlock); if (null != procCallNode) { type = ProtoCore.DSASM.Constants.kGlobalScope; if (compileStateTracker.TypeSystem.IsHigherRank(procCallNode.returntype.UID, inferedType.UID)) { inferedType = procCallNode.returntype; } } } // Try member functions in global class scope if ((procCallNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) && (parentNode == null)) { if (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) { int realType; bool isAccessible; bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex; ProtoCore.DSASM.ProcedureNode memProcNode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (memProcNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); procCallNode = memProcNode; inferedType = procCallNode.returntype; type = realType; if (!isAccessible) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procCallNode; } } } } if (isUnresolvedDot) { // Get the dot call procedure ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode; if (!isConstructor && !isStaticCall) { procNode = compileStateTracker.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotMethodName, null, codeBlock); } if(CoreUtils.IsGetter(procName)) { EmitFunctionCall(depth, type, arglist, procNode, funcCall, true); } else EmitFunctionCall(depth, type, arglist, procNode, funcCall, false, bnode); if (dotCallType.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = dotCallType.UID; } return procCallNode; } if (null != procCallNode) { if (procCallNode.isConstructor && (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && (globalProcIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && (globalClassIndex == inferedType.UID)) { ProtoCore.DSASM.ProcedureNode contextProcNode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; if (contextProcNode.isConstructor && string.Equals(contextProcNode.name, procCallNode.name) && contextProcNode.runtimeIndex == procCallNode.runtimeIndex) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingConstructorInConstructor, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingConstructorInConstructor, message, compileStateTracker.CurrentDSFileName, node.line, node.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procCallNode; } } inferedType = procCallNode.returntype; //if call is replication call if (procCallNode.isThisCallReplication) { inferedType.IsIndexable = true; inferedType.rank++; } // Get the dot call procedure ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode; if (!isConstructor && !isStaticCall) { procNode = compileStateTracker.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotMethodName, null, codeBlock); } if (CoreUtils.IsSetter(procName)) { EmitFunctionCall(depth, type, arglist, procNode, funcCall); } // Do not emit breakpoint at getters only - pratapa else if (CoreUtils.IsGetter(procName)) { EmitFunctionCall(depth, type, arglist, procNode, funcCall, true); } else { EmitFunctionCall(depth, type, arglist, procNode, funcCall, false, bnode); } if (dotCallType.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = dotCallType.UID; } if (isConstructor) { foreach (AssociativeNode paramNode in dotCall.FunctionCall.FormalArguments) { // Get the lhs symbol list ProtoCore.Type ltype = new ProtoCore.Type(); ltype.UID = globalClassIndex; ProtoCore.AssociativeGraph.UpdateNodeRef argNodeRef = new ProtoCore.AssociativeGraph.UpdateNodeRef(); DFSGetSymbolList(paramNode, ref ltype, argNodeRef); if (null != graphNode) { graphNode.updatedArguments.Add(argNodeRef); } } graphNode.firstProc = procCallNode; } return procCallNode; } else { // Function does not exist at this point but we try to reolve at runtime if (depth <= 0 && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { if (inferedType.UID != (int)PrimitiveType.kTypeVar) { if (!compileStateTracker.Options.SuppressFunctionResolutionWarning) { string property; if (CoreUtils.TryGetPropertyName(procName, out property)) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kPropertyNotFound, property); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kPropertyNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodNotFound, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } } inferedType.UID = (int)PrimitiveType.kTypeNull; } // Get the dot call procedure ProtoCore.DSASM.ProcedureNode procNode = procDotCallNode; if (!isConstructor && !isStaticCall) { procNode = compileStateTracker.GetFirstVisibleProcedure(ProtoCore.DSASM.Constants.kDotMethodName, null, codeBlock); } if (CoreUtils.IsGetter(procName)) { EmitFunctionCall(depth, type, arglist, procNode, funcCall, true); } else EmitFunctionCall(depth, type, arglist, procNode, funcCall, false, bnode); if (dotCallType.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = dotCallType.UID; } } else { if (procName == ProtoCore.DSASM.Constants.kFunctionPointerCall && depth == 0) { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(procName, arglist, lefttype); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); var iNode = nodeBuilder.BuildIdentfier(funcCall.Function.Name); EmitIdentifierNode(iNode, ref inferedType); } else { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(funcCall.Function.Name, arglist, lefttype); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); } // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, funcCall.Function.Name + "[dynamic]"); EmitDynamicCall(compileStateTracker.DynamicFunctionTable.functionTable.Count - 1, globalClassIndex, depth, funcCall.line, funcCall.col, funcCall.endLine, funcCall.endCol); // The function return value EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); if (compileStateTracker.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide) { int guides = EmitReplicationGuides(replicationGuide); EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, guides + "[guide]"); EmitPushReplicationGuide(guides); } //assign inferedType to var inferedType.UID = (int)PrimitiveType.kTypeVar; } } return procDotCallNode; }
public override ProtoCore.DSASM.ProcedureNode TraverseFunctionCall(ProtoCore.AST.Node node, ProtoCore.AST.Node parentNode, int lefttype, int depth, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, ProtoCore.AST.Node bnode = null) { FunctionCallNode funcCall = null; string procName = null; List<ProtoCore.Type> arglist = new List<ProtoCore.Type>(); ProtoCore.Type dotCallType = new ProtoCore.Type(); dotCallType.UID = (int)PrimitiveType.kTypeVar; dotCallType.IsIndexable = false; ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode(); if (node is ProtoCore.AST.AssociativeAST.FunctionDotCallNode) { return TraverseDotFunctionCall(node, parentNode, lefttype, depth, ref inferedType, graphNode, subPass, bnode as BinaryExpressionNode); } else { funcCall = node as FunctionCallNode; procName = funcCall.Function.Name; int classIndex = compileStateTracker.ClassTable.IndexOf(procName); bool isAccessible; int dummy; // To support unamed constructor if (classIndex != Constants.kInvalidIndex) { ProcedureNode constructor = compileStateTracker.ClassTable.ClassNodes[classIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out dummy, true); if (constructor != null && constructor.isConstructor) { FunctionCallNode rhsFNode = node as ProtoCore.AST.AssociativeAST.FunctionCallNode; AssociativeNode classNode = nodeBuilder.BuildIdentfier(procName); FunctionDotCallNode dotCallNode = ProtoCore.Utils.CoreUtils.GenerateCallDotNode(classNode, rhsFNode, compileStateTracker); return TraverseDotFunctionCall(dotCallNode, parentNode, lefttype, depth, ref inferedType, graphNode, subPass, bnode as BinaryExpressionNode); } } } foreach (AssociativeNode paramNode in funcCall.FormalArguments) { ProtoCore.Type paramType = new ProtoCore.Type(); paramType.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; paramType.IsIndexable = false; // The range expression function does not need replication guides emitReplicationGuide = !procName.Equals(ProtoCore.DSASM.Constants.kFunctionRangeExpression); // If it's a binary node then continue type check, otherwise disable type check and just take the type of paramNode itself // f(1+2.0) -> type check enabled - param is typed as double // f(2) -> type check disabled - param is typed as int enforceTypeCheck = !(paramNode is BinaryExpressionNode); DfsTraverse(paramNode, ref paramType, false, graphNode, subPass, bnode); emitReplicationGuide = false; enforceTypeCheck = true; arglist.Add(paramType); } if (subPass == ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { return null; } ProtoCore.DSASM.ProcedureNode procNode = null; int type = ProtoCore.DSASM.Constants.kInvalidIndex; int refClassIndex = ProtoCore.DSASM.Constants.kInvalidIndex; if (parentNode != null && parentNode is ProtoCore.AST.AssociativeAST.IdentifierListNode) { ProtoCore.AST.Node leftnode = (parentNode as ProtoCore.AST.AssociativeAST.IdentifierListNode).LeftNode; if (leftnode != null && leftnode is ProtoCore.AST.AssociativeAST.IdentifierNode) { refClassIndex = compileStateTracker.ClassTable.IndexOf(leftnode.Name); } } // Check for the actual method, not the dot method // If lefttype is a valid class then check if calling a constructor if ((int)ProtoCore.PrimitiveType.kInvalidType != inferedType.UID && (int)ProtoCore.PrimitiveType.kTypeVoid != inferedType.UID && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { bool isAccessible; int realType; bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex; procNode = compileStateTracker.ClassTable.ClassNodes[inferedType.UID].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (procNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); type = lefttype = realType; if (!isAccessible) { type = lefttype = realType; procNode = null; string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procNode; } } } // Try function pointer firstly if ((procNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)) { bool isAccessibleFp; ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAllocated = VerifyAllocation(procName, globalClassIndex, globalProcIndex, out symbolnode, out isAccessibleFp); if (isAllocated) // not checking the type against function pointer, as the type could be var { procName = ProtoCore.DSASM.Constants.kFunctionPointerCall; // The graph node always depends on this function pointer if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } } } // Always try global function firstly. Because we dont have syntax // support for calling global function (say, ::foo()), if we try // member function firstly, there is no way to call a global function // For member function, we can use this.foo() to distinguish it from // global function. if ((procNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall)) { procNode = compileStateTracker.GetFirstVisibleProcedure(procName, arglist, codeBlock); if (null != procNode) { type = ProtoCore.DSASM.Constants.kGlobalScope; if (compileStateTracker.TypeSystem.IsHigherRank(procNode.returntype.UID, inferedType.UID)) { inferedType = procNode.returntype; } } } // Try member functions in global class scope if ((procNode == null) && (procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) && (parentNode == null)) { if (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) { int realType; bool isAccessible; bool isStaticOrConstructor = refClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex; ProtoCore.DSASM.ProcedureNode memProcNode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(procName, arglist, globalClassIndex, out isAccessible, out realType, isStaticOrConstructor); if (memProcNode != null) { Debug.Assert(realType != ProtoCore.DSASM.Constants.kInvalidIndex); procNode = memProcNode; inferedType = procNode.returntype; type = realType; if (!isAccessible) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procNode; } } } } if (null != procNode) { if (procNode.isConstructor && (globalClassIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && (globalProcIndex != ProtoCore.DSASM.Constants.kInvalidIndex) && (globalClassIndex == inferedType.UID)) { ProtoCore.DSASM.ProcedureNode contextProcNode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; if (contextProcNode.isConstructor && string.Equals(contextProcNode.name, procNode.name) && contextProcNode.runtimeIndex == procNode.runtimeIndex) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kCallingConstructorInConstructor, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingConstructorInConstructor, message, compileStateTracker.CurrentDSFileName, node.line, node.col ); inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return procNode; } } inferedType = procNode.returntype; //if call is replication call if (procNode.isThisCallReplication) { inferedType.IsIndexable = true; inferedType.rank++; } if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { // // ==============Establishing graphnode links in modified arguments============= // // proc TraverseCall(node, graphnode) // ; Get the first procedure, this will only be the first visible procedure // ; Overloads will be handled at runtime // def fnode = getProcedure(node) // // ; For every argument in the function call, // ; attach the modified property list and append it to the graphnode update list // foreach arg in node.args // if fnode.updatedArgProps is not null // def noderef = arg.ident (or identlist) // noderef.append(fnode.updatedArgProps) // graphnode.pushUpdateRef(noderef) // end // end // end // // ============================================================================= // foreach (AssociativeNode paramNode in funcCall.FormalArguments) { // Get the lhs symbol list ProtoCore.Type ltype = new ProtoCore.Type(); ltype.UID = globalClassIndex; ProtoCore.AssociativeGraph.UpdateNodeRef argNodeRef = new ProtoCore.AssociativeGraph.UpdateNodeRef(); DFSGetSymbolList(paramNode, ref ltype, argNodeRef); if (null != graphNode) { graphNode.updatedArguments.Add(argNodeRef); } } // The function is at block 0 if its a constructor, member or at the globals scope. // Its at block 1 if its inside a language block. // Its limited to block 1 as of R1 since we dont support nested function declarations yet int blockId = procNode.runtimeIndex; //push value-not-provided default argument for (int i = arglist.Count; i < procNode.argInfoList.Count; i++) { EmitDefaultArgNode(); } // Push the function declaration block and indexed array // Jun TODO: Implementeation of indexing into a function call: // x = f()[0][1] int dimensions = 0; EmitPushVarData(blockId, dimensions); // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, procNode.name); // Do not emit breakpoints at built-in methods like _add/_sub etc. - pratapa if (procNode.isAssocOperator || procNode.name.Equals(ProtoCore.DSASM.Constants.kInlineConditionalMethodName)) { EmitCall(procNode.procId, type, depth, ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, procNode.pc); } // Break at function call inside dynamic lang block created for a 'true' or 'false' expression inside an inline conditional else if (compileStateTracker.DebugProps.breakOptions.HasFlag(DebugProperties.BreakpointOptions.EmitInlineConditionalBreakpoint)) { Validity.Assert(compileStateTracker.DebugProps.highlightRange != null); ProtoCore.CodeModel.CodePoint startInclusive = compileStateTracker.DebugProps.highlightRange.StartInclusive; ProtoCore.CodeModel.CodePoint endExclusive = compileStateTracker.DebugProps.highlightRange.EndExclusive; EmitCall(procNode.procId, type, depth, startInclusive.LineNo, startInclusive.CharNo, endExclusive.LineNo, endExclusive.CharNo, procNode.pc); } // Use startCol and endCol of binary expression node containing function call except if it's a setter else if (bnode != null && !procNode.name.StartsWith(Constants.kSetterPrefix)) { EmitCall(procNode.procId, type, depth, bnode.line, bnode.col, bnode.endLine, bnode.endCol, procNode.pc); } else { EmitCall(procNode.procId, type, depth, funcCall.line, funcCall.col, funcCall.endLine, funcCall.endCol, procNode.pc); } // The function return value EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); if (dotCallType.UID != (int)PrimitiveType.kTypeVar) { inferedType.UID = dotCallType.UID; } } } else { if (depth <= 0 && procName != ProtoCore.DSASM.Constants.kFunctionPointerCall) { string property; if (CoreUtils.TryGetPropertyName(procName, out property)) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kPropertyNotFound, property); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kPropertyNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodNotFound, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionNotFound, message, compileStateTracker.CurrentDSFileName, funcCall.line, funcCall.col); } inferedType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); } else { if (procName == ProtoCore.DSASM.Constants.kFunctionPointerCall && depth == 0) { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(procName, arglist, lefttype); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); var iNode = nodeBuilder.BuildIdentfier(funcCall.Function.Name); EmitIdentifierNode(iNode, ref inferedType); } else { ProtoCore.DSASM.DynamicFunctionNode dynamicFunctionNode = new ProtoCore.DSASM.DynamicFunctionNode(funcCall.Function.Name, arglist, lefttype); compileStateTracker.DynamicFunctionTable.functionTable.Add(dynamicFunctionNode); } // The function call EmitInstrConsole(ProtoCore.DSASM.kw.callr, funcCall.Function.Name + "[dynamic]"); EmitDynamicCall(compileStateTracker.DynamicFunctionTable.functionTable.Count - 1, globalClassIndex, depth, funcCall.line, funcCall.col, funcCall.endLine, funcCall.endCol); // The function return value EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); ProtoCore.DSASM.StackValue opReturn = new ProtoCore.DSASM.StackValue(); opReturn.optype = ProtoCore.DSASM.AddressType.Register; opReturn.opdata = (int)ProtoCore.DSASM.Registers.RX; EmitPush(opReturn); //assign inferedType to var inferedType.UID = (int)PrimitiveType.kTypeVar; } } return procNode; }
private void EmitLanguageBlockNode(ImperativeNode node, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode propogateUpdateGraphNode = null) { if (IsParsingGlobal() || IsParsingGlobalFunctionBody()) { LanguageBlockNode langblock = node as LanguageBlockNode; //(Fuqiang, Ayush) : Throwing an assert stops NUnit. Negative tests expect to catch a // CompilerException, so we throw that instead. //Validity.Assert(ProtoCore.Language.kInvalid != langblock.codeblock.language); if (ProtoCore.Language.kInvalid == langblock.codeblock.language) { throw new ProtoCore.Exceptions.CompileErrorsOccured("Invalid language block"); } ProtoCore.CompileTime.Context context = new ProtoCore.CompileTime.Context(); // Save the guid of the current scope (which is stored in the current graphnodes) to the nested language block. // This will be passed on to the nested language block that will be compiled if (propogateUpdateGraphNode != null) { context.guid = propogateUpdateGraphNode.guid; } int entry = 0; int blockId = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.Language.kImperative == langblock.codeblock.language) { // TODO Jun: Move the associative and all common string into some table buildStatus.LogSyntaxError(Resources.InvalidNestedImperativeBlock, core.CurrentDSFileName, langblock.line, langblock.col); } if (globalProcIndex != ProtoCore.DSASM.Constants.kInvalidIndex && core.ProcNode == null) core.ProcNode = codeBlock.procedureTable.procList[globalProcIndex]; core.Compilers[langblock.codeblock.language].Compile(out blockId, codeBlock, langblock.codeblock, context, codeBlock.EventSink, langblock.CodeBlockNode); if (propogateUpdateGraphNode != null) { propogateUpdateGraphNode.languageBlockId = blockId; CodeBlock childBlock = core.CompleteCodeBlockList[blockId]; foreach (var subGraphNode in childBlock.instrStream.dependencyGraph.GraphList) { foreach (var depentNode in subGraphNode.dependentList) { if (depentNode.updateNodeRefList != null && depentNode.updateNodeRefList.Count > 0 && depentNode.updateNodeRefList[0].nodeList != null && depentNode.updateNodeRefList[0].nodeList.Count > 0) { SymbolNode dependentSymbol = depentNode.updateNodeRefList[0].nodeList[0].symbol; int symbolBlockId = dependentSymbol.codeBlockId; if (symbolBlockId != Constants.kInvalidIndex) { CodeBlock symbolBlock = core.CompleteCodeBlockList[symbolBlockId]; if (!symbolBlock.IsMyAncestorBlock(codeBlock.codeBlockId)) { propogateUpdateGraphNode.PushDependent(depentNode); } } } } } } setBlkId(blockId); inferedType = core.InferedType; //Validity.Assert(codeBlock.children[codeBlock.children.Count - 1].blockType == ProtoCore.DSASM.CodeBlockType.kLanguage); codeBlock.children[codeBlock.children.Count - 1].Attributes = PopulateAttributes(langblock.Attributes); EmitInstrConsole("bounce " + blockId + ", " + entry.ToString()); EmitBounceIntrinsic(blockId, entry); // The callee language block will have stored its result into the RX register. EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regRX); StackValue opRes = StackValue.BuildRegister(Registers.RX); EmitPush(opRes); } }
private void EmitIdentifierNode(ImperativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null) { IdentifierNode t = node as IdentifierNode; if (t.Name.Equals(ProtoCore.DSDefinitions.Keyword.This)) { if (localProcedure != null) { if (localProcedure.IsStatic) { string message = ProtoCore.Properties.Resources.kUsingThisInStaticFunction; core.BuildStatus.LogWarning(WarningID.InvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode); EmitPushNull(); return; } else if (localProcedure.ClassID == Constants.kGlobalScope) { string message = ProtoCore.Properties.Resources.kInvalidThis; core.BuildStatus.LogWarning(WarningID.InvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode); EmitPushNull(); return; } else { EmitThisPointerNode(); return; } } else { string message = ProtoCore.Properties.Resources.kInvalidThis; core.BuildStatus.LogWarning(WarningID.InvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode); EmitPushNull(); return; } } int dimensions = 0; int runtimeIndex = codeBlock.symbolTable.RuntimeIndex; ProtoCore.Type type = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.Var, 0); ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool isAllocated = VerifyAllocation(t.Value, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); if (!isAllocated && null == t.ArrayDimensions) { //check if it is a function instance ProtoCore.DSASM.ProcedureNode procNode = null; procNode = CoreUtils.GetFunctionBySignature(t.Name, null, codeBlock); if (null != procNode) { if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.ID) { // A global function inferedType.UID = (int)PrimitiveType.FunctionPointer; int fptr = core.FunctionPointerTable.functionPointerDictionary.Count; var fptrNode = new ProtoCore.DSASM.FunctionPointerNode(procNode); core.FunctionPointerTable.functionPointerDictionary.TryAdd(fptr, fptrNode); core.FunctionPointerTable.functionPointerDictionary.TryGetBySecond(fptrNode, out fptr); EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Name); StackValue opFunctionPointer = StackValue.BuildFunctionPointer(fptr); EmitPush(opFunctionPointer, runtimeIndex, t.line, t.col); return; } } } if (!isAllocated || !isAccessible) { if (isAllocated) { if (!isAccessible) { string message = String.Format(ProtoCore.Properties.Resources.kPropertyIsInaccessible, t.Value); buildStatus.LogWarning(WarningID.AccessViolation, message, core.CurrentDSFileName, t.line, t.col, graphNode); } } else { string message = String.Format(ProtoCore.Properties.Resources.kUnboundIdentifierMsg, t.Value); var unboundSymbol = new SymbolNode { name = t.Value }; buildStatus.LogUnboundVariableWarning(unboundSymbol, message, core.CurrentDSFileName, t.line, t.col, graphNode); } inferedType.UID = (int)ProtoCore.PrimitiveType.Null; // Jun Comment: Specification excerpt // If resolution fails at this point a com.Design-Script.Imperative.Core.UnboundIdentifier // warning is emitted during pre-execute phase, and at the ID is bound to null. (R1 - Feb) EmitPushNull(); ProtoCore.Type varType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.Var, 0); symbolnode = Allocate(t.Value, globalProcIndex, varType); EmitInstrConsole(kw.pop, t.Value); EmitPopForSymbol(symbolnode, runtimeIndex); } else { type = symbolnode.datatype; runtimeIndex = symbolnode.runtimeTableIndex; if (core.Options.AssociativeToImperativePropagation) { // Comment Jun: If this symbol belongs to an outer block, then append it to this language blocks dependent if (symbolnode.codeBlockId != codeBlock.codeBlockId) { // A parent codeblock owns this symbol if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } } } } EmitInstrConsole(kw.push, t.Value); EmitPushForSymbol(symbolnode, runtimeIndex, t); if (null != t.ArrayDimensions) { dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions); } //fix type's rank //fix type's rank if (type.rank >= 0) { type.rank -= dimensions; if (type.rank < 0) { //throw new Exception("Exceed maximum rank!"); type.rank = 0; } } if (dimensions > 0) { EmitPushDimensions(dimensions); EmitLoadElement(symbolnode, runtimeIndex); } if (core.TypeSystem.IsHigherRank(type.UID, inferedType.UID)) { inferedType = type; } // We need to get inferedType for boolean variable so that we can perform type check inferedType.UID = (isBooleanOp || (type.UID == (int)PrimitiveType.Bool)) ? (int)PrimitiveType.Bool : type.UID; }