// TODO Jun: return failed status public int Append(SymbolNode node) { if (IndexOf(node) != Constants.kInvalidIndex) { return(Constants.kInvalidIndex); } int symbolTableIndex = symbolList.Count; node.symbolTableIndex = symbolTableIndex; symbolList[symbolTableIndex] = node; if (Constants.kGlobalScope == node.functionIndex) { size += node.size; } if (!lookAsideSymbolCache.ContainsKey(node.name)) { lookAsideSymbolCache.Add(node.name, new List <SymbolNode>()); } lookAsideSymbolCache[node.name].Add(node); return(symbolTableIndex); }
public bool Remove(SymbolNode node) { bool rtBool = true; rtBool = rtBool & nameToSymbolList.Remove(node.name); rtBool = rtBool & symbolList.Remove(node.symbolTableIndex); return(rtBool); }
public bool IsMemberVariable(SymbolNode symbol) { // Jun: // A fast version of the find member variable where we search the symboltable directly Validity.Assert(null != symbol); return(ProtoCore.DSASM.Constants.kInvalidIndex != symbols.IndexOf(symbol.name) // A symbol is a member if it doesnt belong to any function && ProtoCore.DSASM.Constants.kInvalidIndex == symbol.functionIndex); }
public bool Remove(SymbolNode node) { if (lookAsideSymbolCache.ContainsKey(node.name)) { if (lookAsideSymbolCache[node.name].Contains(node)) { lookAsideSymbolCache[node.name].Remove(node); } } return(symbolList.Remove(node.symbolTableIndex)); }
private void UpdateModifiedSymbols(SymbolNode symbol) { Validity.Assert(null != symbol); Validity.Assert(!string.IsNullOrEmpty(symbol.name)); Validity.Assert(null != mapModifiedSymbols); // TODO Jun: Turn this into a multi-key dictionary where the keys are: name, classindex and procindex string key = symbol.name; if (!mapModifiedSymbols.ContainsKey(key)) { mapModifiedSymbols.Add(key, symbol); } }
public void PushSymbolReference(ProtoCore.DSASM.SymbolNode symbol, ProtoCore.AssociativeGraph.UpdateNodeType type = UpdateNodeType.kSymbol) { Debug.Assert(null != symbol); Debug.Assert(null != updateNodeRefList); UpdateNode updateNode = new UpdateNode(); updateNode.symbol = symbol; updateNode.nodeType = type; UpdateNodeRef nodeRef = new UpdateNodeRef(); nodeRef.PushUpdateNode(updateNode); updateNodeRefList.Add(nodeRef); }
public void PushSymbolReference(ProtoCore.DSASM.SymbolNode symbol) { Debug.Assert(null != symbol); Debug.Assert(null != updateNodeRefList); UpdateNode updateNode = new UpdateNode(); updateNode.symbol = symbol; updateNode.nodeType = UpdateNodeType.kSymbol; UpdateNodeRef nodeRef = new UpdateNodeRef(); nodeRef.block = symbol.runtimeTableIndex; nodeRef.PushUpdateNode(updateNode); updateNodeRefList.Add(nodeRef); }
// TODO Jun: return failed status public int Append(SymbolNode node) { if (IndexOf(node) == ProtoCore.DSASM.Constants.kInvalidIndex) { //@SARANG -- make a common method out of this symbolList[symbolList.Count] = node; node.symbolTableIndex = symbolList.Count - 1; nameToSymbolList.Add(node.name, node); if (ProtoCore.DSASM.Constants.kGlobalScope == node.functionIndex) { size += node.size; } return(node.symbolTableIndex); } return(ProtoCore.DSASM.Constants.kInvalidIndex); }
/// <summary> /// Method to undefine a symbol from the symboltable entry and cache /// </summary> /// <param name="symbol"></param> public void UndefineSymbol(SymbolNode symbol) { // Dont remove from symbol table, but just nullify it. symbolList[symbol.symbolTableIndex] = new SymbolNode(); if (lookAsideSymbolCache.ContainsKey(symbol.name)) { List <SymbolNode> cachedSymbolList = lookAsideSymbolCache[symbol.name]; for (int n = 0; n < cachedSymbolList.Count; ++n) { SymbolNode cachedSymbol = cachedSymbolList[n]; if (cachedSymbol.name.Equals(symbol.name) && cachedSymbol.classScope == symbol.classScope && cachedSymbol.functionIndex == symbol.functionIndex) { // Dont remove from symbol table, but just nullify it. cachedSymbolList[n] = new SymbolNode(); break; } } } }
public void RemoveGlobalSymbols() { List <int> keysToRemove = new List <int>(); foreach (var symbol in symbolList) { bool removeGlobalsFromCurrentScope = symbol.Value.functionIndex == ProtoCore.DSASM.Constants.kInvalidIndex && symbol.Value.classScope == ProtoCore.DSASM.Constants.kInvalidIndex && string.IsNullOrEmpty(symbol.Value.ExternLib); if (removeGlobalsFromCurrentScope) { keysToRemove.Add(symbol.Key); } } foreach (var key in keysToRemove) { SymbolNode symbol = symbolList[key]; if (nameToSymbolList.ContainsValue(symbol.name, symbol)) { nameToSymbolList.Remove(symbol.name, symbol); } symbolList.Remove(key); } }
// Deperecate this function after further regression testing and just use DFSGetSymbolList public void DFSGetSymbolList_Simple(Node pNode, ref ProtoCore.Type lefttype, ref int functionindex, ProtoCore.AssociativeGraph.UpdateNodeRef nodeRef) { dynamic node = pNode; if (node is ProtoCore.AST.ImperativeAST.IdentifierListNode || node is ProtoCore.AST.AssociativeAST.IdentifierListNode) { dynamic bnode = node; DFSGetSymbolList_Simple(bnode.LeftNode, ref lefttype, ref functionindex, nodeRef); node = bnode.RightNode; } if (node is ProtoCore.AST.ImperativeAST.IdentifierNode || node is ProtoCore.AST.AssociativeAST.IdentifierNode) { dynamic identnode = node; ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool isAllocated = VerifyAllocation(identnode.Value, lefttype.UID, functionindex, out symbolnode, out isAccessible); if (isAllocated) { if (null == symbolnode) { // It is inaccessible from here due to access modifier. // Just attempt to retrieve the symbol int symindex = core.ClassTable.ClassNodes[lefttype.UID].GetFirstVisibleSymbolNoAccessCheck(identnode.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex != symindex) { symbolnode = core.ClassTable.ClassNodes[lefttype.UID].Symbols.symbolList[symindex]; } } // Since the variable was found, all succeeding nodes in the ident list are class members // Class members have a function scope of kGlobalScope as they are only local to the class, not with any member function functionindex = ProtoCore.DSASM.Constants.kGlobalScope; lefttype = symbolnode.datatype; ProtoCore.AssociativeGraph.UpdateNode updateNode = new AssociativeGraph.UpdateNode(); updateNode.symbol = symbolnode; updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol; nodeRef.PushUpdateNode(updateNode); } else { // Is it a class? int ci = core.ClassTable.IndexOf(identnode.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { lefttype.UID = ci; // Comment Jun: // Create a symbol node that contains information about the class type that contains static properties ProtoCore.DSASM.SymbolNode classSymbol = new DSASM.SymbolNode(); classSymbol.memregion = DSASM.MemoryRegion.kMemStatic; classSymbol.name = identnode.Value; classSymbol.classScope = ci; ProtoCore.AssociativeGraph.UpdateNode updateNode = new AssociativeGraph.UpdateNode(); updateNode.symbol = classSymbol; updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol; nodeRef.PushUpdateNode(updateNode); } else { // In this case, the lhs type is undefined // Just attempt to create a symbol node string ident = identnode.Value; if (0 != ident.CompareTo(ProtoCore.DSDefinitions.Keyword.This)) { symbolnode = new SymbolNode(); symbolnode.name = identnode.Value; ProtoCore.AssociativeGraph.UpdateNode updateNode = new AssociativeGraph.UpdateNode(); updateNode.symbol = symbolnode; updateNode.nodeType = AssociativeGraph.UpdateNodeType.kSymbol; nodeRef.PushUpdateNode(updateNode); } } } } else if (node is ProtoCore.AST.ImperativeAST.FunctionCallNode || node is ProtoCore.AST.AssociativeAST.FunctionCallNode) { string functionName = node.Function.Value; if (ProtoCore.Utils.CoreUtils.IsGetterSetter(functionName)) { string property; if (CoreUtils.TryGetPropertyName(functionName, out property)) { functionName = property; } ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool isAllocated = VerifyAllocation(functionName, lefttype.UID, globalProcIndex, out symbolnode, out isAccessible); if (isAllocated) { if (null == symbolnode) { // It is inaccessible from here due to access modifier. // Just attempt to retrieve the symbol int symindex = core.ClassTable.ClassNodes[lefttype.UID].GetFirstVisibleSymbolNoAccessCheck(functionName); if (ProtoCore.DSASM.Constants.kInvalidIndex != symindex) { symbolnode = core.ClassTable.ClassNodes[lefttype.UID].Symbols.symbolList[symindex]; } } lefttype = symbolnode.datatype; ProtoCore.AssociativeGraph.UpdateNode updateNode = new AssociativeGraph.UpdateNode(); updateNode.symbol = symbolnode; updateNode.nodeType = AssociativeGraph.UpdateNodeType.kSymbol; nodeRef.PushUpdateNode(updateNode); } } else { ProtoCore.AssociativeGraph.UpdateNode updateNode = new AssociativeGraph.UpdateNode(); ProtoCore.DSASM.ProcedureNode procNodeDummy = new DSASM.ProcedureNode(); procNodeDummy.Name = functionName; updateNode.procNode = procNodeDummy; updateNode.nodeType = AssociativeGraph.UpdateNodeType.kMethod; nodeRef.PushUpdateNode(updateNode); } } }
public int GetStackIndex(SymbolNode symbolNode) { int offset = symbolNode.index; int depth = 0; int blockOffset = 0; // TODO Jun: the property 'localFunctionIndex' must be deprecated and just use 'functionIndex'. // The GC currenlty has an issue of needing to reset 'functionIndex' at codegen bool isGlobal = Constants.kInvalidIndex == symbolNode.absoluteClassScope && Constants.kGlobalScope == symbolNode.absoluteFunctionIndex; if (!isGlobal) { depth = (int)GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexStackFrameDepth).opdata; blockOffset = depth * StackFrame.kStackFrameSize; } offset -= blockOffset; return offset; }
private int AllocateArg( string ident, int funcIndex, ProtoCore.Type datatype, int size = 1, int datasize = ProtoCore.DSASM.Constants.kPrimitiveSize, ImperativeNode nodeArray = null, ProtoCore.DSASM.MemoryRegion region = ProtoCore.DSASM.MemoryRegion.kMemStack) { ProtoCore.DSASM.SymbolNode symbolnode = new ProtoCore.DSASM.SymbolNode( ident, ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, funcIndex, datatype, datatype, size, datasize, true, codeBlock.symbolTable.runtimeIndex, region); symbolnode.codeBlockId = codeBlock.codeBlockId; if (this.isEmittingImportNode) symbolnode.ExternLib = compileStateTracker.CurrentDSFileName; int symbolindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex != codeBlock.symbolTable.IndexOf(symbolnode)) { buildStatus.LogSemanticError("redefinition of identifier '" + ident + "'"); } else { int locOffset = localProcedure.localCount; locOffset = localProcedure.localCount; symbolnode.index = -1 - ProtoCore.DSASM.StackFrame.kStackFrameSize - (locOffset + argOffset); ++argOffset; symbolindex = codeBlock.symbolTable.Append(symbolnode); } return symbolindex; }
private void EmitConstructorDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone) { ConstructorDefinitionNode funcDef = node as ConstructorDefinitionNode; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingMemberFunctionSig()) { Debug.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.name = funcDef.Name; localProcedure.pc = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.localCount = 0;// Defer till all locals are allocated localProcedure.returntype.UID = globalClassIndex; localProcedure.returntype.IsIndexable = false; localProcedure.isConstructor = true; localProcedure.runtimeIndex = 0; localProcedure.isExternal = funcDef.IsExternLib; Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class"); localProcedure.localCount = 0; localProcedure.classScope = globalClassIndex; int peekFunctionindex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList.Count; // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); if (null != funcDef.Signature) { int argNumber = 0; foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ++argNumber; IdentifierNode paramNode = null; bool aIsDefault = false; ProtoCore.AST.Node aDefaultExpression = null; if (argNode.NameNode is IdentifierNode) { paramNode = argNode.NameNode as IdentifierNode; } else if (argNode.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = argNode.NameNode as BinaryExpressionNode; paramNode = bNode.LeftNode as IdentifierNode; aIsDefault = true; aDefaultExpression = bNode; //buildStatus.LogSemanticError("Default parameters are not supported"); //throw new BuildHaltException(); } else { Debug.Assert(false, "Check generated AST"); } ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(paramNode.Value, argType)); localProcedure.argTypeList.Add(argType); ProtoCore.DSASM.ArgumentInfo argInfo = new ProtoCore.DSASM.ArgumentInfo { Name = paramNode.Value, isDefault = aIsDefault, defaultExpression = aDefaultExpression }; localProcedure.argInfoList.Add(argInfo); } } int findex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.Append(localProcedure); // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != findex) { Debug.Assert(peekFunctionindex == localProcedure.procId); argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, findex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("44B557F1"); } }); } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kMethodAlreadyDefined, localProcedure.name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kFunctionAlreadyDefined, message, compileStateTracker.CurrentDSFileName, funcDef.line, funcDef.col); funcDef.skipMe = true; } } else if (IsParsingMemberFunctionBody()) { EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature, true)); // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode); argList.Add(argType); } } globalProcIndex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.IndexOfExact(funcDef.Name, argList); Debug.Assert(null == localProcedure); localProcedure = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex]; Debug.Assert(null != localProcedure); localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.pc = pc; EmitInstrConsole(ProtoCore.DSASM.kw.allocc, localProcedure.name); EmitAllocc(globalClassIndex); setConstructorStartPC = true; EmitCallingForBaseConstructor(globalClassIndex, funcDef.baseConstr); ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { // Traverse default assignment for the class emitDebugInfo = false; foreach (BinaryExpressionNode bNode in compileStateTracker.ClassTable.ClassNodes[globalClassIndex].defaultArgExprList) { ProtoCore.AssociativeGraph.GraphNode graphNode = new ProtoCore.AssociativeGraph.GraphNode(); graphNode.isParent = true; graphNode.exprUID = bNode.exprUID; graphNode.modBlkUID = bNode.modBlkUID; graphNode.procIndex = globalProcIndex; graphNode.classIndex = globalClassIndex; graphNode.isAutoGenerated = true; EmitBinaryExpressionNode(bNode, ref inferedType, false, graphNode, subPass); } //Traverse default argument for the constructor foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.argInfoList) { if (!argNode.isDefault) { continue; } BinaryExpressionNode bNode = argNode.defaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp = nodeBuilder.BuildIdentfier(Constants.kTempDefaultArg); BinaryExpressionNode bNodeTemp = new BinaryExpressionNode(); bNodeTemp.LeftNode = iNodeTemp; bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign; bNodeTemp.RightNode = bNode.LeftNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.IsAutoGenerated = true; BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } emitDebugInfo = true; // Traverse definition foreach (AssociativeNode bnode in funcDef.FunctionBody.Body) { inferedType.UID = (int)PrimitiveType.kTypeVoid; inferedType.rank = 0; if (bnode is LanguageBlockNode) { // Build a binaryn node with a temporary lhs for every stand-alone language block var iNode = nodeBuilder.BuildIdentfier(compileStateTracker.GenerateTempLangageVar()); BinaryExpressionNode langBlockNode = new BinaryExpressionNode(); langBlockNode.LeftNode = iNode; langBlockNode.Optr = ProtoCore.DSASM.Operator.assign; langBlockNode.RightNode = bnode; DfsTraverse(langBlockNode, ref inferedType, false, null, subPass); } else { DfsTraverse(bnode, ref inferedType, false, null, subPass); } } // All locals have been stack allocated, update the local count of this function localProcedure.localCount = compileStateTracker.BaseOffset; compileStateTracker.ClassTable.ClassNodes[globalClassIndex].vtable.procList[globalProcIndex].localCount = compileStateTracker.BaseOffset; // Update the param stack indices of this function foreach (ProtoCore.DSASM.SymbolNode symnode in compileStateTracker.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList.Values) { if (symnode.functionIndex == globalProcIndex && symnode.isArgument) { symnode.index -= localProcedure.localCount; } } // JIL FEP ProtoCore.Lang.JILActivationRecord record = new ProtoCore.Lang.JILActivationRecord(); record.pc = localProcedure.pc; record.locals = localProcedure.localCount; record.classIndex = globalClassIndex; record.funcIndex = globalProcIndex; // Construct the fep arguments fep = new ProtoCore.Lang.JILFunctionEndPoint(record); } else { ProtoCore.Lang.JILActivationRecord jRecord = new ProtoCore.Lang.JILActivationRecord(); jRecord.pc = localProcedure.pc; jRecord.locals = localProcedure.localCount; jRecord.classIndex = globalClassIndex; jRecord.funcIndex = localProcedure.procId; ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = false; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.argTypeList; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.argTypeList.Count]; fep.procedureNode = localProcedure; localProcedure.argTypeList.CopyTo(fep.FormalParams, 0); // TODO Jun: 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables // Determine whether this still needs to be aligned to the actual 'classIndex' variable // The factors that will affect this is whether the 2 function tables (compiler and callsite) need to be merged int classIndexAtCallsite = globalClassIndex + 1; compileStateTracker.FunctionTable.AddFunctionEndPointer(classIndexAtCallsite, funcDef.Name, fep); int startpc = pc; // Constructors auto return EmitInstrConsole(ProtoCore.DSASM.kw.retc); // Stepping out of a constructor body will have the execution cursor // placed right at the closing curly bracket of the constructor definition. // int closeCurlyBracketLine = 0, closeCurlyBracketColumn = -1; if (null != funcDef.FunctionBody) { closeCurlyBracketLine = funcDef.FunctionBody.endLine; closeCurlyBracketColumn = funcDef.FunctionBody.endCol; } // The execution cursor covers exactly one character -- the closing // curly bracket. Note that we decrement the start-column by one here // because end-column of "FunctionBody" here is *after* the closing // curly bracket, so we want one before that. // EmitRetc(closeCurlyBracketLine, closeCurlyBracketColumn - 1, closeCurlyBracketLine, closeCurlyBracketColumn); // Build and append a graphnode for this return statememt ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode(); returnNode.name = ProtoCore.DSDefinitions.Keyword.Return; ProtoCore.AssociativeGraph.GraphNode retNode = new ProtoCore.AssociativeGraph.GraphNode(); //retNode.symbol = returnNode; retNode.PushSymbolReference(returnNode); retNode.procIndex = globalProcIndex; retNode.classIndex = globalClassIndex; retNode.updateBlock.startpc = startpc; retNode.updateBlock.endpc = pc - 1; codeBlock.instrStream.dependencyGraph.Push(retNode); EmitCompileLogFunctionEnd(); } // Constructors have no return statemetns, reset variables here compileStateTracker.ProcNode = localProcedure = null; globalProcIndex = ProtoCore.DSASM.Constants.kGlobalScope; compileStateTracker.BaseOffset = 0; argOffset = 0; classOffset = 0; codeBlock.blockType = originalBlockType; }
private void EmitBinaryExpressionNode(AssociativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, bool isTempExpression = false) { BinaryExpressionNode bnode = null; if (!IsParsingGlobal() && !IsParsingGlobalFunctionBody() && !IsParsingMemberFunctionBody()) return; bool isBooleanOperation = false; bnode = node as BinaryExpressionNode; ProtoCore.Type leftType = new ProtoCore.Type(); leftType.UID = (int)ProtoCore.PrimitiveType.kTypeVar; leftType.IsIndexable = false; ProtoCore.Type rightType = new ProtoCore.Type(); rightType.UID = (int)ProtoCore.PrimitiveType.kTypeVar; rightType.IsIndexable = false; DebugProperties.BreakpointOptions oldOptions = compileStateTracker.DebugProps.breakOptions; /* proc emitbinaryexpression(node) if node is assignment if graphnode is not valid graphnode = BuildNewGraphNode() end dfstraverse(node.right, graphnode) def lefttype = invalid def updateNodeRef = null dfsgetsymbollist(node.left, lefttype, updateNodeRef) // Get the first procedure call in the rhs // This stack is populated on traversing the entire RHS def firstProc = functionCallStack.first() graphnode.pushUpdateRef(updateNodeRef) // Auto-generate the updateNodeRefs for this graphnode given the list stored in the first procedure found in the assignment expression foreach noderef in firstProc.updatedProperties def autogenRef = updateNodeRef autogenRef.append(noderef) graphnode.pushUpdateRef(autogenRef) end // See if the leftmost symbol(updateNodeRef) of the lhs expression is a property of the current class. // If it is, then push the lhs updateNodeRef to the list of modified properties in the procedure node def symbol = classtable[ci].verifyalloc(updateNodeRef[0]) if symbol is valid def localproc = getlocalproc(ci,fi) localproc.push(updateNodeRef) end functionCallStack.Clear(); end end */ /* Building the graphnode dependencies from the SSA transformed identifier list is illustrated in the following functions: ssaPtrList = new List proc EmitBinaryExpression(bnode, graphnode) if bnode is assignment graphnode = new graphnode if bnode is an SSA pointer expression if bnode.rhs is an identifier // Push the start pointer ssaPtrList.push(node.rhs) else if bnode.rhs is an identifierlist // Push the rhs of the dot operator ssaPtrList.push(node.rhs.rhs) else Assert unhandled end end emit(bnode.rhs) emit(bnode.lhs) if (bnode is an SSA pointer expression and bnode is the last expression in the SSA factor/term ssaPtrList.Clear() end end end */ // If this is an assignment statement, setup the top level graph node bool isGraphInScope = false; if (ProtoCore.DSASM.Operator.assign == bnode.Optr) { if (null == graphNode) { isGraphInScope = true; EmitCompileLog("==============Start Node==============\n"); graphNode = new ProtoCore.AssociativeGraph.GraphNode(); graphNode.isParent = true; graphNode.exprUID = bnode.exprUID; graphNode.modBlkUID = bnode.modBlkUID; graphNode.procIndex = globalProcIndex; graphNode.classIndex = globalClassIndex; graphNode.languageBlockId = codeBlock.codeBlockId; if (bnode.isSSAFirstAssignment) { firstSSAGraphNode = graphNode; } // All associative code is SSA'd and we want to keep track of the original identifier nodes of an identifier list: // i.e. x.y.z // These identifiers will be used to populate the real graph nodes dependencies if (bnode.isSSAPointerAssignment) { Validity.Assert(null != ssaPointerList); if (bnode.RightNode is IdentifierNode) { ssaPointerList.Add(bnode.RightNode); } else if (bnode.RightNode is IdentifierListNode) { ssaPointerList.Add((bnode.RightNode as IdentifierListNode).RightNode); } else if (bnode.RightNode is FunctionDotCallNode) { FunctionDotCallNode dotcall = bnode.RightNode as FunctionDotCallNode; Validity.Assert(dotcall.FunctionCall.Function is IdentifierNode); if (ProtoCore.Utils.CoreUtils.IsGetterSetter(dotcall.FunctionCall.Function.Name)) { // This function is an internal getter or setter, store the identifier node ssaPointerList.Add(dotcall.FunctionCall.Function); } else { // This function is a member function, store the functioncall node ssaPointerList.Add(dotcall.FunctionCall); } } else if (bnode.RightNode is FunctionCallNode) { FunctionCallNode fcall = bnode.RightNode as FunctionCallNode; Validity.Assert(fcall.Function is IdentifierNode); ssaPointerList.Add(fcall.Function); } else { Validity.Assert(false); } /* The following functions on codegen will perform the static call backtracking: string staticClass = null bool resolveStatic = false proc EmitBinaryExpr(node) if node.right is identifier if node.right is a class staticClass = node.right.name resolveStatic = true end end end proc EmitIdentifierList(node, graphnode) if resolveStatic node.left = new IdentifierNode(staticClass) end end */ if (bnode.RightNode is IdentifierNode) { string identName = (bnode.RightNode as IdentifierNode).Name; if (compileStateTracker.ClassTable.DoesExist(identName)) { ssaPointerList.Clear(); staticClass = identName; resolveStatic = true; return; } } } // // Comment Jun: // If the expression ID of the assignment node in the context execDirtyFlag list is false, // it means that it was already executed. This needs to be marked as not dirty if (compileStateTracker.Options.IsDeltaExecution) { if (context.exprExecutionFlags.ContainsKey(bnode.exprUID)) { graphNode.isDirty = context.exprExecutionFlags[bnode.exprUID]; } } } if (bnode.LeftNode is IdentifierListNode) { EmitLHSIdentifierListForBinaryExpr(bnode, ref inferedType, isBooleanOp, graphNode, subPass); if (isGraphInScope) { EmitCompileLog("==============End Node==============\n"); } return; } else if (bnode.LeftNode is IdentifierNode) { if (bnode.LeftNode.Name.Equals(ProtoCore.DSDefinitions.Keyword.This)) { string errorMessage = ProtoCore.BuildData.WarningMessage.kInvalidThis; if (localProcedure != null) { if (localProcedure.isStatic) { errorMessage = ProtoCore.BuildData.WarningMessage.kUsingThisInStaticFunction; } else if (localProcedure.classScope == Constants.kGlobalScope) { errorMessage = ProtoCore.BuildData.WarningMessage.kInvalidThis; } else { errorMessage = ProtoCore.BuildData.WarningMessage.kAssingToThis; } } compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, errorMessage, compileStateTracker.CurrentDSFileName, bnode.line, bnode.col); if (isGraphInScope) { EmitCompileLog("==============End Node==============\n"); } return; } if (EmitLHSThisDotProperyForBinaryExpr(bnode, ref inferedType, isBooleanOp, graphNode, subPass)) { if (isGraphInScope) { EmitCompileLog("==============End Node==============\n"); } return; } } } else //(ProtoCore.DSASM.Operator.assign != b.Optr) { // Traversing the left node if this binary expression is not an assignment // isBooleanOperation = ProtoCore.DSASM.Operator.lt == bnode.Optr || ProtoCore.DSASM.Operator.gt == bnode.Optr || ProtoCore.DSASM.Operator.le == bnode.Optr || ProtoCore.DSASM.Operator.ge == bnode.Optr || ProtoCore.DSASM.Operator.eq == bnode.Optr || ProtoCore.DSASM.Operator.nq == bnode.Optr || ProtoCore.DSASM.Operator.and == bnode.Optr || ProtoCore.DSASM.Operator.or == bnode.Optr; DfsTraverse(bnode.LeftNode, ref inferedType, isBooleanOperation, graphNode, subPass); if (inferedType.UID == (int)PrimitiveType.kTypeFunctionPointer && subPass != ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier && emitDebugInfo) { buildStatus.LogSemanticError("Function pointer is not allowed at binary expression other than assignment!", compileStateTracker.CurrentDSFileName, bnode.LeftNode.line, bnode.LeftNode.col); } leftType.UID = inferedType.UID; leftType.IsIndexable = inferedType.IsIndexable; } int startpc = ProtoCore.DSASM.Constants.kInvalidIndex; // (Ayush) in case of PostFixNode, only traverse the identifier now. Post fix operation will be applied later. #if ENABLE_INC_DEC_FIX if (bnode.RightNode is PostFixNode) { DfsTraverse((bnode.RightNode as PostFixNode).Identifier, ref inferedType, isBooleanOperation, graphNode); } else { #endif if ((ProtoCore.DSASM.Operator.assign == bnode.Optr) && (bnode.RightNode is LanguageBlockNode)) { inferedType.UID = (int)ProtoCore.PrimitiveType.kTypeVar; inferedType.IsIndexable = false; } if (null != localProcedure && localProcedure.isConstructor && setConstructorStartPC) { startpc -= 1; setConstructorStartPC = false; } if (bnode.RightNode == null && bnode.Optr == Operator.assign && bnode.LeftNode is IdentifierNode) { DebugProperties.BreakpointOptions newOptions = oldOptions; newOptions |= DebugProperties.BreakpointOptions.SuppressNullVarDeclarationBreakpoint; compileStateTracker.DebugProps.breakOptions = newOptions; IdentifierNode t = bnode.LeftNode as IdentifierNode; ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool hasAllocated = VerifyAllocation(t.Value, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); if (hasAllocated) { bool allowDependent = graphNode.allowDependents; graphNode.allowDependents = false; bnode.RightNode = nodeBuilder.BuildIdentfier(t.Value); graphNode.allowDependents = false; } else { bnode.RightNode = new NullNode(); } } // Keep track of current pc, because when travese right node it // may generate null assignment ( x = null; if x hasn't been defined // yet - Yu Ke startpc = pc; DfsTraverse(bnode.RightNode, ref inferedType, isBooleanOperation, graphNode, subPass); #if ENABLE_INC_DEC_FIX } #endif rightType.UID = inferedType.UID; rightType.IsIndexable = inferedType.IsIndexable; BinaryExpressionNode rightNode = bnode.RightNode as BinaryExpressionNode; if ((rightNode != null) && (ProtoCore.DSASM.Operator.assign == rightNode.Optr)) { DfsTraverse(rightNode.LeftNode, ref inferedType, false, graphNode); } if (bnode.Optr != ProtoCore.DSASM.Operator.assign) { if (subPass == ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier) { return; } if (inferedType.UID == (int)PrimitiveType.kTypeFunctionPointer && emitDebugInfo) { buildStatus.LogSemanticError("Function pointer is not allowed at binary expression other than assignment!", compileStateTracker.CurrentDSFileName, bnode.RightNode.line, bnode.RightNode.col); } EmitBinaryOperation(leftType, rightType, bnode.Optr); isBooleanOp = false; //if post fix, now traverse the post fix #if ENABLE_INC_DEC_FIX if (bnode.RightNode is PostFixNode) EmitPostFixNode(bnode.RightNode, ref inferedType); #endif return; } Debug.Assert(null != graphNode); if (!isTempExpression) { // Only set startpc if isn't temporary assignment expression if (compileStateTracker.Options.IsDeltaExecution) graphNode.updateBlock.startpc = startpc; else graphNode.updateBlock.startpc = pc; } currentBinaryExprUID = bnode.exprUID; // These have been integrated into "EmitGetterSetterForIdentList" so // that stepping through class properties can be supported. Setting // these values here will cause issues with statements like this to // be highlighted in its entirety (all the way up to closing bracket // without highlighting the semi-colon). // // x = foo(a, b); // // bnode.RightNode.line = bnode.line; // bnode.RightNode.col = bnode.col; // bnode.RightNode.endLine = bnode.endLine; // bnode.RightNode.endCol = bnode.endCol; // Traverse the entire RHS expression DfsTraverse(bnode.RightNode, ref inferedType, isBooleanOperation, graphNode, ProtoCore.DSASM.AssociativeSubCompilePass.kNone, bnode); subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier; if (bnode.LeftNode is IdentifierNode) { // TODO Jun: Cleansify this block where the lhs is being handled. // For one, make the return as a return node IdentifierNode t = bnode.LeftNode as IdentifierNode; ProtoCore.DSASM.SymbolNode symbolnode = null; ProtoCore.AssociativeGraph.UpdateNodeRef leftNodeGlobalRef = null; string s = t.Value; if (s == ProtoCore.DSDefinitions.Keyword.Return) { Debug.Assert(null == symbolnode); symbolnode = new ProtoCore.DSASM.SymbolNode(); symbolnode.name = s; symbolnode.isTemp = s.StartsWith("%"); symbolnode.functionIndex = globalProcIndex; symbolnode.classScope = globalClassIndex; EmitReturnStatement(node, inferedType); // Comment Jun: The inline conditional holds a graphnode and traversing its body will set isReturn = true // Resolve that here as an inline conditional is obviosuly not a return graphnode if (!graphNode.isInlineConditional) { graphNode.isReturn = true; } } else { leftNodeGlobalRef = GetUpdatedNodeRef(bnode.LeftNode); // right node is statement which wont return any value, so push null to stack if ((bnode.RightNode is IfStatementNode) || (bnode.RightNode is ForLoopNode)) { EmitPushNull(); } { // check whether the variable name is a function name bool isAccessibleFp; int realType; ProtoCore.DSASM.ProcedureNode procNode = null; if (globalClassIndex != ProtoCore.DSASM.Constants.kGlobalScope) { procNode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(t.Name, null, globalClassIndex, out isAccessibleFp, out realType); } if (procNode == null) { procNode = compileStateTracker.GetFirstVisibleProcedure(t.Name, null, codeBlock); } if (procNode != null) { if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId && emitDebugInfo) { buildStatus.LogSemanticError("\"" + t.Name + "\"" + " is a function and not allowed as a variable name", compileStateTracker.CurrentDSFileName, t.line, t.col); } } } //int type = (int)ProtoCore.PrimitiveType.kTypeVoid; bool isAccessible = false; bool isAllocated = VerifyAllocation(t.Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); int runtimeIndex = (!isAllocated || !isAccessible) ? codeBlock.symbolTable.runtimeIndex : symbolnode.runtimeTableIndex; if (isAllocated && !isAccessible) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kPropertyIsInaccessible, t.Name); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, t.line, t.col); } int dimensions = 0; if (null != t.ArrayDimensions) { graphNode.isIndexingLHS = true; dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions, graphNode, bnode); } // Comment Jun: Attempt to get the modified argument arrays in the current method // Comment Jun: As of R1 - arrays are copy constructed and cannot propagate update unless explicitly returned //ProtoCore.AssociativeGraph.UpdateNodeRef leftNodeArgArray = AutoGenerateUpdateArgumentArrayReference(bnode.LeftNode, graphNode); ProtoCore.Type castType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, false); var tident = bnode.LeftNode as TypedIdentifierNode; if (tident != null) { int castUID = tident.datatype.UID; if ((int)PrimitiveType.kInvalidType == castUID) { castUID = compileStateTracker.ClassTable.IndexOf(tident.datatype.Name); } if ((int)PrimitiveType.kInvalidType == castUID) { castType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kInvalidType, false); castType.Name = tident.datatype.Name; castType.rank = tident.datatype.rank; castType.IsIndexable = (castType.rank != 0); } else { castType = compileStateTracker.TypeSystem.BuildTypeObject(castUID, tident.datatype.IsIndexable, tident.datatype.rank); } } if (ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex) { // In a class if (ProtoCore.DSASM.Constants.kInvalidIndex == globalProcIndex) { string message = "A binary assignment inside a class must be inside a function (AB5E3EC1)"; buildStatus.LogSemanticError(message, compileStateTracker.CurrentDSFileName, bnode.line, bnode.col); throw new BuildHaltException(message); } // TODO Jun: refactor this by having symbol table functions for retrieval of node index int symbol = ProtoCore.DSASM.Constants.kInvalidIndex; bool isMemVar = false; if (symbolnode != null) { if (symbolnode.classScope != ProtoCore.DSASM.Constants.kInvalidIndex && symbolnode.functionIndex == ProtoCore.DSASM.Constants.kGlobalScope) { isMemVar = true; } symbol = symbolnode.symbolTableIndex; } ProtoCore.DSASM.StackValue op = new ProtoCore.DSASM.StackValue(); if (!isMemVar) { // This is local variable // TODO Jun: If this local var exists globally, should it allocate a local copy? if (!isAllocated || !isAccessible) { symbolnode = Allocate(globalClassIndex, globalClassIndex, globalProcIndex, t.Name, inferedType, ProtoCore.DSASM.Constants.kPrimitiveSize, false, ProtoCore.DSASM.AccessSpecifier.kPublic, ProtoCore.DSASM.MemoryRegion.kMemStack, bnode.line, bnode.col); // Add the symbols during watching process to the watch symbol list. if (compileStateTracker.ExecMode == ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { compileStateTracker.watchSymbolList.Add(symbolnode); } Debug.Assert(symbolnode != null); } else { symbolnode.datatype = inferedType; } if (bnode.LeftNode is TypedIdentifierNode) { symbolnode.SetStaticType(castType); } castType = symbolnode.staticType; EmitPushVarData(runtimeIndex, dimensions, castType.UID, castType.rank); symbol = symbolnode.symbolTableIndex; if (t.Name == ProtoCore.DSASM.Constants.kTempArg) { EmitInstrConsole(ProtoCore.DSASM.kw.pop, t.Name); EmitPopForSymbol(symbolnode); } else { if (compileStateTracker.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { EmitInstrConsole(ProtoCore.DSASM.kw.pop, t.Name); EmitPopForSymbol(symbolnode, node.line, node.col, node.endLine, node.endCol); } else { EmitInstrConsole(ProtoCore.DSASM.kw.popw, t.Name); EmitPopForSymbolW(symbolnode, node.line, node.col, node.endLine, node.endCol); } } } else { if (bnode.LeftNode is TypedIdentifierNode) { symbolnode.SetStaticType(castType); } castType = symbolnode.staticType; EmitPushVarData(runtimeIndex, dimensions, castType.UID, castType.rank); EmitInstrConsole(ProtoCore.DSASM.kw.popm, t.Name); op.optype = (symbolnode.isStatic) ? ProtoCore.DSASM.AddressType.StaticMemVarIndex : ProtoCore.DSASM.AddressType.MemVarIndex; op.opdata = symbol; EmitPopm(op, node.line, node.col, node.endLine, node.endCol); } //if (t.Name[0] != '%') { AutoGenerateUpdateReference(bnode.LeftNode, graphNode); } // Dependency if (!isTempExpression) { // Dependency graph top level symbol graphNode.PushSymbolReference(symbolnode); EmitDependency(bnode.exprUID, bnode.modBlkUID, bnode.isSSAAssignment); functionCallStack.Clear(); } } else { if (!isAllocated) { symbolnode = Allocate(globalClassIndex, globalClassIndex, globalProcIndex, t.Name, inferedType, ProtoCore.DSASM.Constants.kPrimitiveSize, false, ProtoCore.DSASM.AccessSpecifier.kPublic, ProtoCore.DSASM.MemoryRegion.kMemStack, bnode.line, bnode.col); if (compileStateTracker.ExecMode == ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { compileStateTracker.watchSymbolList.Add(symbolnode); } if (dimensions > 0) { symbolnode.datatype.rank = dimensions; } } else if (dimensions == 0) { symbolnode.datatype = inferedType; } // // Jun Comment: // Update system uses the following registers: // _ex stores prev value of ident 't' - VM assigned // _fx stores new value - VM assigned // if (bnode.LeftNode is TypedIdentifierNode) { symbolnode.SetStaticType(castType); } castType = symbolnode.staticType; EmitPushVarData(runtimeIndex, dimensions, castType.UID, castType.rank); if (compileStateTracker.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { EmitInstrConsole(ProtoCore.DSASM.kw.pop, symbolnode.name); EmitPopForSymbol(symbolnode, node.line, node.col, node.endLine, node.endCol); } else { EmitInstrConsole(ProtoCore.DSASM.kw.popw, symbolnode.name); EmitPopForSymbolW(symbolnode, node.line, node.col, node.endLine, node.endCol); } AutoGenerateUpdateReference(bnode.LeftNode, graphNode); // Dependency if (!isTempExpression) { // Dependency graph top level symbol graphNode.PushSymbolReference(symbolnode); EmitDependency(bnode.exprUID, bnode.modBlkUID, bnode.isSSAAssignment); functionCallStack.Clear(); } } } // Dependency graph top level symbol //graphNode.symbol = symbolnode; // Assign the end pc to this graph node's update block // Dependency graph construction is complete for this expression if (!isTempExpression) { if (null != leftNodeGlobalRef) { if (null != localProcedure) { // Track for updated globals only in user defined functions if (!localProcedure.isAssocOperator && !localProcedure.isAutoGenerated) { localProcedure.updatedGlobals.Push(leftNodeGlobalRef); } } } graphNode.ResolveLHSArrayIndex(); graphNode.updateBlock.endpc = pc - 1; codeBlock.instrStream.dependencyGraph.Push(graphNode); SymbolNode cyclicSymbol1 = null; SymbolNode cyclicSymbol2 = null; if (compileStateTracker.Options.staticCycleCheck) { //UpdateGraphNodeDependency(graphNode); if (!CyclicDependencyTest(graphNode, ref cyclicSymbol1, ref cyclicSymbol2)) { Validity.Assert(null != cyclicSymbol1); Validity.Assert(null != cyclicSymbol2); // // Set the first symbol that triggers the cycle to null ProtoCore.AssociativeGraph.GraphNode nullAssignGraphNode1 = new ProtoCore.AssociativeGraph.GraphNode(); nullAssignGraphNode1.updateBlock.startpc = pc; EmitPushNull(); EmitPushVarData(cyclicSymbol1.runtimeTableIndex, 0); EmitInstrConsole(ProtoCore.DSASM.kw.pop, cyclicSymbol1.name); EmitPopForSymbol(cyclicSymbol1, node.line, node.col, node.endLine, node.endCol); nullAssignGraphNode1.PushSymbolReference(cyclicSymbol1); nullAssignGraphNode1.procIndex = globalProcIndex; nullAssignGraphNode1.classIndex = globalClassIndex; nullAssignGraphNode1.updateBlock.endpc = pc - 1; codeBlock.instrStream.dependencyGraph.Push(nullAssignGraphNode1); EmitDependency(ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, false); // // Set the second symbol that triggers the cycle to null ProtoCore.AssociativeGraph.GraphNode nullAssignGraphNode2 = new ProtoCore.AssociativeGraph.GraphNode(); nullAssignGraphNode2.updateBlock.startpc = pc; EmitPushNull(); EmitPushVarData(cyclicSymbol2.runtimeTableIndex, 0); EmitInstrConsole(ProtoCore.DSASM.kw.pop, cyclicSymbol2.name); EmitPopForSymbol(cyclicSymbol2, node.line, node.col, node.endLine, node.endCol); nullAssignGraphNode2.PushSymbolReference(cyclicSymbol2); nullAssignGraphNode2.procIndex = globalProcIndex; nullAssignGraphNode2.classIndex = globalClassIndex; nullAssignGraphNode2.updateBlock.endpc = pc - 1; codeBlock.instrStream.dependencyGraph.Push(nullAssignGraphNode2); EmitDependency(ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, false); } } if (isGraphInScope) { EmitCompileLog("==============End Node==============\n"); } } // Jun Comment: If it just so happens that the inline conditional is in the return statement if (graphNode.isInlineConditional) { graphNode.isReturn = false; if (0 == graphNode.updateNodeRefList.Count) { graphNode.isReturn = true; } } } else { string message = "Illegal assignment (90787393)"; buildStatus.LogSemanticError(message, compileStateTracker.CurrentDSFileName, bnode.line, bnode.col); throw new BuildHaltException(message); } compileStateTracker.DebugProps.breakOptions = oldOptions; //if post fix, now traverse the post fix #if ENABLE_INC_DEC_FIX if (bnode.RightNode is PostFixNode) EmitPostFixNode(bnode.RightNode, ref inferedType); #endif }
private ProtoCore.DSASM.SymbolNode Allocate( int classIndex, // In which class table this variable will be allocated to ? int classScope, // Variable's class scope. For example, it is a variable in base class int funcIndex, // In which function this variable is defined? string ident, ProtoCore.Type datatype, int datasize = ProtoCore.DSASM.Constants.kPrimitiveSize, bool isStatic = false, ProtoCore.DSASM.AccessSpecifier access = ProtoCore.DSASM.AccessSpecifier.kPublic, ProtoCore.DSASM.MemoryRegion region = ProtoCore.DSASM.MemoryRegion.kMemStack, int line = -1, int col = -1, GraphNode graphNode = null ) { bool allocateForBaseVar = classScope < classIndex; bool isProperty = classIndex != Constants.kInvalidIndex && funcIndex == Constants.kInvalidIndex; if (!allocateForBaseVar && !isProperty && compileStateTracker.ClassTable.IndexOf(ident) != ProtoCore.DSASM.Constants.kInvalidIndex) buildStatus.LogSemanticError(ident + " is a class name, can't be used as a variable.", null, line, col, graphNode); ProtoCore.DSASM.SymbolNode symbolnode = new ProtoCore.DSASM.SymbolNode(); symbolnode.name = ident; symbolnode.isTemp = ident.StartsWith("%"); symbolnode.size = datasize; symbolnode.functionIndex = funcIndex; symbolnode.absoluteFunctionIndex = funcIndex; symbolnode.datatype = datatype; symbolnode.staticType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, false); symbolnode.isArgument = false; symbolnode.memregion = region; symbolnode.classScope = classScope; symbolnode.absoluteClassScope = classScope; symbolnode.runtimeTableIndex = codeBlock.symbolTable.runtimeIndex; symbolnode.isStatic = isStatic; symbolnode.access = access; symbolnode.codeBlockId = codeBlock.codeBlockId; if (this.isEmittingImportNode) symbolnode.ExternLib = compileStateTracker.CurrentDSFileName; int symbolindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (IsInLanguageBlockDefinedInFunction()) { symbolnode.classScope = Constants.kGlobalScope; symbolnode.functionIndex = Constants.kGlobalScope; } if (ProtoCore.DSASM.Constants.kInvalidIndex != classIndex && !IsInLanguageBlockDefinedInFunction()) { // NOTE: the following comment and code is OBSOLETE - member // variable is not supported now // // Yu Ke: it is possible that class table contains same-named // symbols if a class inherits some member variables from base // class, so we need to check name + class index + function // index. // //if (core.classTable.list[classIndex].symbols.IndexOf(ident, classIndex, funcIndex) != (int)ProtoCore.DSASM.Constants.kInvalidIndex) // return null; symbolindex = compileStateTracker.ClassTable.ClassNodes[classIndex].symbols.IndexOf(ident); if (symbolindex != ProtoCore.DSASM.Constants.kInvalidIndex) { ProtoCore.DSASM.SymbolNode node = compileStateTracker.ClassTable.ClassNodes[classIndex].symbols.symbolList[symbolindex]; if (node.functionIndex == ProtoCore.DSASM.Constants.kGlobalScope && funcIndex == ProtoCore.DSASM.Constants.kGlobalScope) return null; } symbolindex = compileStateTracker.ClassTable.ClassNodes[classIndex].symbols.Append(symbolnode); if (symbolindex == ProtoCore.DSASM.Constants.kInvalidIndex) { return null; } if (isStatic) { Debug.Assert(funcIndex == ProtoCore.DSASM.Constants.kGlobalScope); ProtoCore.DSASM.SymbolNode staticSymbolnode = new ProtoCore.DSASM.SymbolNode(); staticSymbolnode.name = ident; staticSymbolnode.isTemp = ident.StartsWith("%"); staticSymbolnode.size = datasize; staticSymbolnode.functionIndex = funcIndex; staticSymbolnode.datatype = datatype; staticSymbolnode.staticType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, false); staticSymbolnode.isArgument = false; staticSymbolnode.memregion = region; staticSymbolnode.classScope = classScope; staticSymbolnode.runtimeTableIndex = codeBlock.symbolTable.runtimeIndex; staticSymbolnode.isStatic = isStatic; staticSymbolnode.access = access; staticSymbolnode.codeBlockId = codeBlock.codeBlockId; if (this.isEmittingImportNode) staticSymbolnode.ExternLib = compileStateTracker.CurrentDSFileName; // If inherits a static property from base class, that propery // symbol should have been added to code block's symbol table, // so we just update symbolTableIndex int staticSymbolindex = codeBlock.symbolTable.IndexOf(ident, classScope); if (staticSymbolindex == ProtoCore.DSASM.Constants.kInvalidIndex) { AllocateVar(staticSymbolnode); staticSymbolindex = codeBlock.symbolTable.Append(staticSymbolnode); if (staticSymbolindex == ProtoCore.DSASM.Constants.kInvalidIndex) { return null; } staticSymbolnode.symbolTableIndex = staticSymbolindex; } symbolnode.symbolTableIndex = staticSymbolindex; } else { AllocateVar(symbolnode); } } else { // Do not import global symbols from external libraries //if(this.isEmittingImportNode && core.IsParsingPreloadedAssembly) //{ // bool importGlobalSymbolFromLib = !string.IsNullOrEmpty(symbolnode.ExternLib) && // symbolnode.functionIndex == -1 && symbolnode.classScope == -1; // if (importGlobalSymbolFromLib) // { // return symbolnode; // } //} AllocateVar(symbolnode); symbolindex = codeBlock.symbolTable.Append(symbolnode); if (symbolindex == ProtoCore.DSASM.Constants.kInvalidIndex) { return null; } symbolnode.symbolTableIndex = symbolindex; } // TODO Jun: Set the symbol table index of the first local variable of 'funcIndex' if (null != localProcedure && null == localProcedure.firstLocal && !IsInLanguageBlockDefinedInFunction()) { localProcedure.firstLocal = symbolnode.index; } if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolindex) { return null; } return symbolnode; }
public bool IsMemberVariable(SymbolNode symbol) { // Jun: // A fast version of the find member variable where we search the symboltable directly Validity.Assert(null != symbol); return ProtoCore.DSASM.Constants.kInvalidIndex != Symbols.IndexOf(symbol.name) // A symbol is a member if it doesnt belong to any function && ProtoCore.DSASM.Constants.kInvalidIndex == symbol.functionIndex; }
public int IndexOf(SymbolNode symbol) { return(symbol.symbolTableIndex); }
public bool DoesSymbolExist(SymbolNode symbol) { return(IndexOf(symbol) != ProtoCore.DSASM.Constants.kInvalidIndex); }
public bool IsEqual(SymbolNode rhs) { return(functionIndex == rhs.functionIndex && name == rhs.name); }
private int AllocateArg(string ident, int funcIndex, ProtoCore.Type datatype) { ProtoCore.DSASM.SymbolNode symbolnode = new ProtoCore.DSASM.SymbolNode( ident, ProtoCore.DSASM.Constants.kInvalidIndex, funcIndex, datatype, datatype, true, codeBlock.symbolTable.RuntimeIndex, MemoryRegion.MemStack); symbolnode.codeBlockId = codeBlock.codeBlockId; if (this.isEmittingImportNode) symbolnode.ExternLib = core.CurrentDSFileName; int symbolindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex != codeBlock.symbolTable.IndexOf(symbolnode)) { buildStatus.LogSemanticError(String.Format(Resources.IdentifierRedefinition,ident)); } else { int locOffset = localProcedure.LocalCount; locOffset = localProcedure.LocalCount; symbolnode.index = -1 - ProtoCore.DSASM.StackFrame.StackFrameSize - (locOffset + argOffset); ++argOffset; symbolindex = codeBlock.symbolTable.Append(symbolnode); } return symbolindex; }
public bool IsEqualAtScope(SymbolNode rhs) { return(functionIndex == rhs.functionIndex && name == rhs.name && classScope == rhs.classScope && codeBlockId == rhs.codeBlockId); }
protected bool DfsEmitIdentList( Node pNode, Node parentNode, int contextClassScope, ref ProtoCore.Type lefttype, ref int depth, ref ProtoCore.Type finalType, bool isLeftidentList, ref bool isFirstIdent, ref bool isMethodCallPresent, ref ProtoCore.DSASM.SymbolNode firstSymbol, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, ProtoCore.AST.Node binaryExpNode = null) { dynamic node = pNode; if (node is ProtoCore.AST.ImperativeAST.IdentifierListNode || node is ProtoCore.AST.AssociativeAST.IdentifierListNode) { dynamic bnode = node; if (ProtoCore.DSASM.Operator.dot != bnode.Optr) { string message = "The left hand side of an operation can only contain an indirection operator '.' (48D67B9B)"; buildStatus.LogSemanticError(message, core.CurrentDSFileName, bnode.line, bnode.col); throw new BuildHaltException(message); } DfsEmitIdentList(bnode.LeftNode, bnode, contextClassScope, ref lefttype, ref depth, ref finalType, isLeftidentList, ref isFirstIdent, ref isMethodCallPresent, ref firstSymbol, graphNode, subPass); if (lefttype.rank > 0) { lefttype.UID = finalType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return false; } node = bnode.RightNode; } if (node is ProtoCore.AST.ImperativeAST.GroupExpressionNode) { ProtoCore.AST.ImperativeAST.ArrayNode array = node.ArrayDimensions; node = node.Expression; node.ArrayDimensions = array; } else if (node is ProtoCore.AST.AssociativeAST.GroupExpressionNode) { ProtoCore.AST.AssociativeAST.ArrayNode array = node.ArrayDimensions; List<ProtoCore.AST.AssociativeAST.AssociativeNode> replicationGuides = node.ReplicationGuides; node = node.Expression; node.ArrayDimensions = array; node.ReplicationGuides = replicationGuides; } if (node is ProtoCore.AST.ImperativeAST.IdentifierNode || node is ProtoCore.AST.AssociativeAST.IdentifierNode) { dynamic identnode = node; int ci = core.ClassTable.IndexOf(identnode.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { finalType.UID = lefttype.UID = ci; } else if (identnode.Value == ProtoCore.DSDefinitions.Keyword.This) { finalType.UID = lefttype.UID = contextClassScope; EmitInstrConsole(ProtoCore.DSASM.kw.push, 0 + "[dim]"); StackValue opdim = StackValue.BuildArrayDimension(0); EmitPush(opdim); EmitThisPointerNode(); depth++; return true; } else { ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAllocated = false; bool isAccessible = false; if (lefttype.UID != -1) { isAllocated = VerifyAllocation(identnode.Value, lefttype.UID, globalProcIndex, out symbolnode, out isAccessible); } else { isAllocated = VerifyAllocation(identnode.Value, contextClassScope, globalProcIndex, out symbolnode, out isAccessible); Validity.Assert(null == firstSymbol); firstSymbol = symbolnode; } bool callOnClass = false; string leftClassName = ""; int leftci = Constants.kInvalidIndex; if (pNode is ProtoCore.AST.ImperativeAST.IdentifierListNode || pNode is ProtoCore.AST.AssociativeAST.IdentifierListNode) { dynamic leftnode = ((dynamic)pNode).LeftNode; if (leftnode != null && (leftnode is ProtoCore.AST.ImperativeAST.IdentifierNode || leftnode is ProtoCore.AST.AssociativeAST.IdentifierNode)) { leftClassName = leftnode.Name; leftci = core.ClassTable.IndexOf(leftClassName); if (leftci != ProtoCore.DSASM.Constants.kInvalidIndex) { callOnClass = true; EmitInstrConsole(ProtoCore.DSASM.kw.push, 0 + "[dim]"); StackValue dynamicOpdim = StackValue.BuildArrayDimension(0); EmitPush(dynamicOpdim); EmitInstrConsole(ProtoCore.DSASM.kw.pushm, leftClassName); StackValue classOp = StackValue.BuildClassIndex(leftci); EmitPushm(classOp, globalClassIndex, codeBlock.codeBlockId); depth = depth + 1; } } } if (null == symbolnode) //unbound identifier { if (isAllocated && !isAccessible) { string message = String.Format(Resources.kPropertyIsInaccessible, identnode.Value); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode); lefttype.UID = finalType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return false; } else { string message = String.Format(Resources.kUnboundIdentifierMsg, identnode.Value); var unboundSymbol = new SymbolNode { name = identnode.Value }; buildStatus.LogUnboundVariableWarning(unboundSymbol, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode); } if (depth == 0) { lefttype.UID = finalType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); depth = 1; return false; } else { DSASM.DyanmicVariableNode dynamicVariableNode = new DSASM.DyanmicVariableNode(identnode.Value, globalProcIndex, globalClassIndex); core.DynamicVariableTable.variableTable.Add(dynamicVariableNode); int dim = 0; if (null != identnode.ArrayDimensions) { dim = DfsEmitArrayIndexHeap(identnode.ArrayDimensions, graphNode); } EmitInstrConsole(ProtoCore.DSASM.kw.push, dim + "[dim]"); StackValue dynamicOpdim = StackValue.BuildArrayDimension(dim); EmitPush(dynamicOpdim); EmitInstrConsole(ProtoCore.DSASM.kw.pushm, identnode.Value + "[dynamic]"); StackValue dynamicOp = StackValue.BuildDynamic(core.DynamicVariableTable.variableTable.Count - 1); EmitPushm(dynamicOp, symbolnode == null ? globalClassIndex : symbolnode.classScope, DSASM.Constants.kInvalidIndex); lefttype.UID = finalType.UID = (int)PrimitiveType.kTypeVar; depth++; return true; } } else { if (callOnClass && !symbolnode.isStatic) { string procName = identnode.Name; string property; ProtoCore.DSASM.ProcedureNode staticProcCallNode = core.ClassTable.ClassNodes[leftci].GetFirstStaticFunctionBy(procName); if (null != staticProcCallNode) { string message = String.Format(Resources.kMethodHasInvalidArguments, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode); } else if (CoreUtils.TryGetPropertyName(procName, out property)) { string message = String.Format(Resources.kPropertyIsInaccessible, property); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode); } else { string message = String.Format(Resources.kMethodIsInaccessible, procName); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kCallingNonStaticMethodOnClass, message, core.CurrentDSFileName, identnode.line, identnode.col, graphNode); } lefttype.UID = finalType.UID = (int)PrimitiveType.kTypeNull; EmitPushNull(); return false; } } // // The graph node depends on the first identifier in this identifier list // Where: // p = f(1); // px = p.x; // px dependent on p // p = f(2); // if (isFirstIdent && null != graphNode) { isFirstIdent = false; //ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); //dependentNode.symbol = symbolnode; //dependentNode.symbolList.Add(symbolnode); //graphNode.PushDependent(dependentNode); } /* Dont try to figure out the type at compile time if it is * an array, it is just not reliable because each element in * an array can have different types */ if (!symbolnode.datatype.IsIndexable || symbolnode.datatype.rank < 0) lefttype = symbolnode.datatype; int dimensions = 0; // Get the symbols' table index int runtimeIndex = symbolnode.runtimeTableIndex; ProtoCore.DSASM.AddressType operandType = ProtoCore.DSASM.AddressType.Pointer; if (null != identnode.ArrayDimensions) { dimensions = DfsEmitArrayIndexHeap(identnode.ArrayDimensions, graphNode); operandType = ProtoCore.DSASM.AddressType.ArrayPointer; } if (lefttype.rank >= 0) { lefttype.rank -= dimensions; if (lefttype.rank < 0) { lefttype.rank = 0; } } if (0 == depth || (symbolnode != null && symbolnode.isStatic)) { if (ProtoCore.DSASM.Constants.kGlobalScope == symbolnode.functionIndex && ProtoCore.DSASM.Constants.kInvalidIndex != symbolnode.classScope) { // member var operandType = symbolnode.isStatic ? ProtoCore.DSASM.AddressType.StaticMemVarIndex : ProtoCore.DSASM.AddressType.MemVarIndex; } else { operandType = ProtoCore.DSASM.AddressType.VarIndex; } } StackValue op = new StackValue(); op.optype = operandType; op.opdata = symbolnode.symbolTableIndex; // TODO Jun: Performance. // Is it faster to have a 'push' specific to arrays to prevent pushing dimension for push instruction? EmitInstrConsole(ProtoCore.DSASM.kw.push, dimensions + "[dim]"); StackValue opdim = StackValue.BuildArrayDimension(dimensions); EmitPush(opdim); if (isLeftidentList || depth == 0) { EmitInstrConsole(ProtoCore.DSASM.kw.pushm, identnode.Value); EmitPushm(op, symbolnode == null ? globalClassIndex : symbolnode.classScope, runtimeIndex); } else { // change to dynamic call to facilitate update mechanism DSASM.DyanmicVariableNode dynamicVariableNode = new DSASM.DyanmicVariableNode(identnode.Name, globalProcIndex, globalClassIndex); core.DynamicVariableTable.variableTable.Add(dynamicVariableNode); StackValue dynamicOp = StackValue.BuildDynamic(core.DynamicVariableTable.variableTable.Count - 1); EmitInstrConsole(ProtoCore.DSASM.kw.pushm, identnode.Value + "[dynamic]"); EmitPushm(dynamicOp, symbolnode == null ? globalClassIndex : symbolnode.classScope, runtimeIndex); } depth = depth + 1; finalType = lefttype; } return true; } else if (node is ProtoCore.AST.ImperativeAST.FunctionCallNode || node is ProtoCore.AST.AssociativeAST.FunctionCallNode) { // A function call must always track dependents bool allowDependents = true; if (null != graphNode) { allowDependents = graphNode.allowDependents; graphNode.allowDependents = true; } if (binaryExpNode != null) { ProtoCore.Utils.NodeUtils.SetNodeLocation(node, binaryExpNode, binaryExpNode); } ProtoCore.DSASM.ProcedureNode procnode = TraverseFunctionCall(node, pNode, lefttype.UID, depth, ref finalType, graphNode, subPass, binaryExpNode); // Restore the graphNode dependent state if (null != graphNode) { graphNode.allowDependents = allowDependents; } // This is the first non-auto generated procedure found in the identifier list if (null != procnode) { if (!procnode.IsConstructor && !procnode.Name.Equals(ProtoCore.DSASM.Constants.kStaticPropertiesInitializer)) { functionCallStack.Add(procnode); if (null != graphNode) { graphNode.firstProcRefIndex = graphNode.dependentList.Count - 1; } } isMethodCallPresent = !isMethodCallPresent && !procnode.IsAutoGenerated && !procnode.IsConstructor; } //finalType.UID = isBooleanOp ? (int)PrimitiveType.kTypeBool : finalType.UID; lefttype = finalType; depth = 1; } else { string message = "The left side of operator '.' must be an identifier. (B9AEA3A6)"; buildStatus.LogSemanticError(message, core.CurrentDSFileName, node.line, node.col); throw new BuildHaltException(message); } return false; }
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.kInvalidThis, 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.kInvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode); EmitPushNull(); return; } else { EmitThisPointerNode(); return; } } else { string message = ProtoCore.Properties.Resources.kInvalidThis; core.BuildStatus.LogWarning(WarningID.kInvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode); EmitPushNull(); return; } } int dimensions = 0; int runtimeIndex = codeBlock.symbolTable.RuntimeIndex; ProtoCore.Type type = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0); 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; 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.GetFirstVisibleProcedure(t.Name, null, codeBlock); if (null != procNode) { if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.ID) { // A global function inferedType.UID = (int)PrimitiveType.kTypeFunctionPointer; 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); EmitPushVarData(0); 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.kAccessViolation, 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.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(dimensions); ProtoCore.Type varType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0); symbolnode = Allocate(t.Value, globalProcIndex, varType); EmitInstrConsole(ProtoCore.DSASM.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); } } } } 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; } } EmitPushVarData(dimensions); EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Value); EmitPushForSymbol(symbolnode, runtimeIndex, t); 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.kTypeBool)) ? (int)PrimitiveType.kTypeBool : type.UID; }
protected void EmitPopForSymbol(SymbolNode symbol, int blockId, int line = ProtoCore.DSASM.Constants.kInvalidIndex, int col = ProtoCore.DSASM.Constants.kInvalidIndex, int eline = ProtoCore.DSASM.Constants.kInvalidIndex, int ecol = ProtoCore.DSASM.Constants.kInvalidIndex) { Validity.Assert(symbol != null); if (symbol == null) { return; } Instruction instr = new Instruction(); instr.opCode = ProtoCore.DSASM.OpCode.POP; instr.op1 = BuildOperand(symbol); instr.op2 = StackValue.BuildClassIndex(symbol.classScope); instr.op3 = StackValue.BuildBlockIndex(blockId); ++pc; bool outputBreakpoint = false; DebugProperties.BreakpointOptions options = core.DebuggerProperties.breakOptions; if (options.HasFlag(DebugProperties.BreakpointOptions.EmitPopForTempBreakpoint)) outputBreakpoint = true; // Do not emit breakpoints for null or var type declarations if (!core.DebuggerProperties.breakOptions.HasFlag(DebugProperties.BreakpointOptions.SuppressNullVarDeclarationBreakpoint)) { // Don't need no pop for temp (unless caller demands it). if (outputBreakpoint || !symbol.name.StartsWith("%")) instr.debug = GetDebugObject(line, col, eline, ecol, pc); } AppendInstruction(instr, line, col); }
private ProtoCore.DSASM.SymbolNode Allocate( string ident, int funcIndex, ProtoCore.Type datatype, int size = 1, int datasize = ProtoCore.DSASM.Constants.kPrimitiveSize, ImperativeNode nodeArray = null, ProtoCore.DSASM.MemoryRegion region = ProtoCore.DSASM.MemoryRegion.kMemStack) { if (core.ClassTable.IndexOf(ident) != ProtoCore.DSASM.Constants.kInvalidIndex) buildStatus.LogSemanticError(String.Format(Resources.ClassNameAsVariableError,ident)); ProtoCore.DSASM.SymbolNode symbolnode = new ProtoCore.DSASM.SymbolNode( ident, ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, funcIndex, datatype, TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, Constants.kArbitraryRank), size, datasize, false, codeBlock.symbolTable.RuntimeIndex, region, false, null, globalClassIndex, ProtoCore.CompilerDefinitions.AccessModifier.kPublic, false, codeBlock.codeBlockId); if (this.isEmittingImportNode) symbolnode.ExternLib = core.CurrentDSFileName; Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == symbolnode.symbolTableIndex); if (null == nodeArray) { AllocateVar(symbolnode); } else { AllocateArray(symbolnode, nodeArray); } // This is to handle that a variable is defined in a language // block which defined in a function, so the variable's scope // is that language block instead of function if (IsInLanguageBlockDefinedInFunction()) { symbolnode.classScope = Constants.kGlobalScope; symbolnode.functionIndex = Constants.kGlobalScope; } int symbolindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex && !IsInLanguageBlockDefinedInFunction()) { symbolindex = core.ClassTable.ClassNodes[globalClassIndex].symbols.Append(symbolnode); } else { symbolindex = codeBlock.symbolTable.Append(symbolnode); } symbolnode.symbolTableIndex = symbolindex; return symbolnode; }
/// <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; }
private bool CyclicDependencyTest(ProtoCore.AssociativeGraph.GraphNode node, ref SymbolNode cyclicSymbol1, ref SymbolNode cyclicSymbol2) { if (null == node || node.updateNodeRefList.Count == 0) { return true; } var indexMap = new Dictionary<GraphNode, int>(); var lowlinkMap = new Dictionary<GraphNode, int>(); var S = new Stack<GraphNode>(); int index = 0; for (int n = 0; n < codeBlock.instrStream.dependencyGraph.GraphList.Count; ++n) { ProtoCore.AssociativeGraph.GraphNode subNode = codeBlock.instrStream.dependencyGraph.GraphList[n]; indexMap[subNode] = Constants.kInvalidIndex; } var dependencyList = StrongConnectComponent(node, ref index, lowlinkMap, indexMap, S); if (dependencyList == null) { return true; } else { GraphNode firstNode = dependencyList[0]; GraphNode lastNode = node; string symbol1 = firstNode.updateNodeRefList[0].nodeList[0].symbol.name; string symbol2 = lastNode.updateNodeRefList[0].nodeList[0].symbol.name; string message = String.Format(ProtoCore.BuildData.WarningMessage.kInvalidStaticCyclicDependency, symbol1, symbol2); compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidStaticCyclicDependency, message, compileStateTracker.CurrentDSFileName); firstNode.isCyclic = true; cyclicSymbol1 = firstNode.updateNodeRefList[0].nodeList[0].symbol; cyclicSymbol2 = lastNode.updateNodeRefList[0].nodeList[0].symbol; firstNode.cyclePoint = lastNode; return false; } }
private ProtoCore.DSASM.SymbolNode Allocate( int classIndex, // In which class table this variable will be allocated to ? int classScope, // Variable's class scope. For example, it is a variable in base class int funcIndex, // In which function this variable is defined? string ident, ProtoCore.Type datatype, int datasize = ProtoCore.DSASM.Constants.kPrimitiveSize, bool isStatic = false, ProtoCore.CompilerDefinitions.AccessModifier access = ProtoCore.CompilerDefinitions.AccessModifier.kPublic, ProtoCore.DSASM.MemoryRegion region = ProtoCore.DSASM.MemoryRegion.kMemStack, int line = -1, int col = -1, GraphNode graphNode = null ) { bool allocateForBaseVar = classScope < classIndex; bool isProperty = classIndex != Constants.kInvalidIndex && funcIndex == Constants.kInvalidIndex; if (!allocateForBaseVar && !isProperty && core.ClassTable.IndexOf(ident) != ProtoCore.DSASM.Constants.kInvalidIndex) buildStatus.LogSemanticError(String.Format(Resources.ClassNameAsVariableError, ident), null, line, col, graphNode); ProtoCore.DSASM.SymbolNode symbolnode = new ProtoCore.DSASM.SymbolNode(); symbolnode.name = ident; symbolnode.isTemp = ident.StartsWith("%"); symbolnode.size = datasize; symbolnode.functionIndex = funcIndex; symbolnode.absoluteFunctionIndex = funcIndex; symbolnode.datatype = datatype; symbolnode.staticType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, Constants.kArbitraryRank); symbolnode.isArgument = false; symbolnode.memregion = region; symbolnode.classScope = classScope; symbolnode.absoluteClassScope = classScope; symbolnode.runtimeTableIndex = codeBlock.symbolTable.RuntimeIndex; symbolnode.isStatic = isStatic; symbolnode.access = access; symbolnode.codeBlockId = codeBlock.codeBlockId; if (this.isEmittingImportNode) symbolnode.ExternLib = core.CurrentDSFileName; int symbolindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (IsInLanguageBlockDefinedInFunction()) { symbolnode.classScope = Constants.kGlobalScope; symbolnode.functionIndex = Constants.kGlobalScope; } if (ProtoCore.DSASM.Constants.kInvalidIndex != classIndex && !IsInLanguageBlockDefinedInFunction()) { // NOTE: the following comment and code is OBSOLETE - member // variable is not supported now // // Yu Ke: it is possible that class table contains same-named // symbols if a class inherits some member variables from base // class, so we need to check name + class index + function // index. // //if (core.classTable.list[classIndex].symbols.IndexOf(ident, classIndex, funcIndex) != (int)ProtoCore.DSASM.Constants.kInvalidIndex) // return null; symbolindex = core.ClassTable.ClassNodes[classIndex].Symbols.IndexOf(ident); if (symbolindex != ProtoCore.DSASM.Constants.kInvalidIndex) { ProtoCore.DSASM.SymbolNode node = core.ClassTable.ClassNodes[classIndex].Symbols.symbolList[symbolindex]; if (node.functionIndex == ProtoCore.DSASM.Constants.kGlobalScope && funcIndex == ProtoCore.DSASM.Constants.kGlobalScope) return null; } symbolindex = core.ClassTable.ClassNodes[classIndex].Symbols.Append(symbolnode); if (symbolindex == ProtoCore.DSASM.Constants.kInvalidIndex) { return null; } if (isStatic) { Validity.Assert(funcIndex == ProtoCore.DSASM.Constants.kGlobalScope); ProtoCore.DSASM.SymbolNode staticSymbolnode = new ProtoCore.DSASM.SymbolNode(); staticSymbolnode.name = ident; staticSymbolnode.isTemp = ident.StartsWith("%"); staticSymbolnode.size = datasize; staticSymbolnode.functionIndex = funcIndex; staticSymbolnode.datatype = datatype; staticSymbolnode.staticType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, Constants.kArbitraryRank); staticSymbolnode.isArgument = false; staticSymbolnode.memregion = region; staticSymbolnode.classScope = classScope; staticSymbolnode.runtimeTableIndex = codeBlock.symbolTable.RuntimeIndex; staticSymbolnode.isStatic = isStatic; staticSymbolnode.access = access; staticSymbolnode.codeBlockId = codeBlock.codeBlockId; if (this.isEmittingImportNode) staticSymbolnode.ExternLib = core.CurrentDSFileName; // If inherits a static property from base class, that propery // symbol should have been added to code block's symbol table, // so we just update symbolTableIndex int staticSymbolindex = codeBlock.symbolTable.IndexOf(ident, classScope); if (staticSymbolindex == ProtoCore.DSASM.Constants.kInvalidIndex) { AllocateVar(staticSymbolnode); staticSymbolindex = codeBlock.symbolTable.Append(staticSymbolnode); if (staticSymbolindex == ProtoCore.DSASM.Constants.kInvalidIndex) { return null; } staticSymbolnode.symbolTableIndex = staticSymbolindex; } symbolnode.symbolTableIndex = staticSymbolindex; } else { AllocateVar(symbolnode); } } else { AllocateVar(symbolnode); symbolindex = codeBlock.symbolTable.Append(symbolnode); if (symbolindex == ProtoCore.DSASM.Constants.kInvalidIndex) { return null; } symbolnode.symbolTableIndex = symbolindex; } if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolindex) { return null; } return symbolnode; }
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; }
private int AllocateArg( string ident, int funcIndex, ProtoCore.Type datatype, int size = 1, int datasize = ProtoCore.DSASM.Constants.kPrimitiveSize, AssociativeNode nodeArray = null, ProtoCore.DSASM.MemoryRegion region = ProtoCore.DSASM.MemoryRegion.kMemStack) { ProtoCore.DSASM.SymbolNode node = new ProtoCore.DSASM.SymbolNode( ident, ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, funcIndex, datatype, datatype, size, datasize, true, codeBlock.symbolTable.RuntimeIndex, region, false, null, globalClassIndex); node.name = ident; node.isTemp = ident.StartsWith("%"); node.size = datasize; node.functionIndex = funcIndex; node.absoluteFunctionIndex = funcIndex; node.datatype = datatype; node.isArgument = true; node.memregion = ProtoCore.DSASM.MemoryRegion.kMemStack; node.classScope = globalClassIndex; node.absoluteClassScope = globalClassIndex; node.codeBlockId = codeBlock.codeBlockId; if (this.isEmittingImportNode) node.ExternLib = core.CurrentDSFileName; // Comment Jun: The local count will be adjusted and all dependent symbol offsets after the function body has been traversed int locOffset = 0; // This will be offseted by the local count after locals have been allocated node.index = -1 - ProtoCore.DSASM.StackFrame.kStackFrameSize - (locOffset + argOffset); ++argOffset; int symbolindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex) { symbolindex = core.ClassTable.ClassNodes[globalClassIndex].Symbols.Append(node); } else { symbolindex = codeBlock.symbolTable.Append(node); } return symbolindex; }
private ProtoCore.DSASM.SymbolNode Allocate( string ident, int funcIndex, ProtoCore.Type datatype, int size = 1, int datasize = ProtoCore.DSASM.Constants.kPrimitiveSize, ImperativeNode nodeArray = null, ProtoCore.DSASM.MemoryRegion region = ProtoCore.DSASM.MemoryRegion.kMemStack) { if (compileStateTracker.ClassTable.IndexOf(ident) != ProtoCore.DSASM.Constants.kInvalidIndex) buildStatus.LogSemanticError(ident + " is a class name, can't be used as a variable."); ProtoCore.DSASM.SymbolNode symbolnode = new ProtoCore.DSASM.SymbolNode( ident, ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, funcIndex, datatype, compileStateTracker.TypeSystem.BuildTypeObject((int)PrimitiveType.kTypeVar, false), size, datasize, false, codeBlock.symbolTable.runtimeIndex, region, false, null, globalClassIndex, ProtoCore.DSASM.AccessSpecifier.kPublic, false, codeBlock.codeBlockId); if (this.isEmittingImportNode) symbolnode.ExternLib = compileStateTracker.CurrentDSFileName; Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == symbolnode.symbolTableIndex); if (null == nodeArray) { AllocateVar(symbolnode); } else { AllocateArray(symbolnode, nodeArray); } // This is to handle that a variable is defined in a language // block which defined in a function, so the variable's scope // is that language block instead of function if (IsInLanguageBlockDefinedInFunction()) { symbolnode.classScope = Constants.kGlobalScope; symbolnode.functionIndex = Constants.kGlobalScope; } int symbolindex = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex && !IsInLanguageBlockDefinedInFunction()) { symbolindex = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].symbols.Append(symbolnode); } else { // Do not import global symbols from external libraries //if (this.isEmittingImportNode && core.IsParsingPreloadedAssembly) //{ // bool importGlobalSymbolFromLib = !string.IsNullOrEmpty(symbolnode.ExternLib) && // symbolnode.functionIndex == -1 && symbolnode.classScope == -1; // if (importGlobalSymbolFromLib) // { // return symbolnode; // } //} symbolindex = codeBlock.symbolTable.Append(symbolnode); } // TODO Jun: Set the symbol table index of the first local variable of 'funcIndex' // This will no longer required once the functiontable is refactored to include a symbol table // if the current codeblock is a while block, the procedureTable will be null if (null != localProcedure && null == localProcedure.firstLocal && !IsInLanguageBlockDefinedInFunction()) { localProcedure.firstLocal = symbolnode.index; } if (ProtoCore.DSASM.MemoryRegion.kMemHeap == symbolnode.memregion) { EmitInstrConsole(ProtoCore.DSASM.kw.alloca, symbolindex.ToString()); EmitAlloc(symbolindex); } symbolnode.symbolTableIndex = symbolindex; return symbolnode; }
protected override void EmitReturnNull() { int startpc = pc; EmitPushNull(); EmitReturnToRegister(); // Build and append a graphnode for this return statememt ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode(); returnNode.name = ProtoCore.DSDefinitions.Keyword.Return; ProtoCore.AssociativeGraph.GraphNode retNode = new ProtoCore.AssociativeGraph.GraphNode(); //retNode.symbol = returnNode; retNode.PushSymbolReference(returnNode); retNode.procIndex = globalProcIndex; retNode.classIndex = globalClassIndex; retNode.updateBlock.startpc = startpc; retNode.updateBlock.endpc = pc - 1; retNode.isReturn = true; PushGraphNode(retNode); }
protected void EmitPopForSymbolW(SymbolNode symbol, int blockId, int line = ProtoCore.DSASM.Constants.kInvalidIndex, int col = ProtoCore.DSASM.Constants.kInvalidIndex, int eline = ProtoCore.DSASM.Constants.kInvalidIndex, int ecol = ProtoCore.DSASM.Constants.kInvalidIndex) { Validity.Assert(symbol != null); if (symbol == null) { return; } Instruction instr = new Instruction(); instr.opCode = ProtoCore.DSASM.OpCode.POPW; instr.op1 = BuildOperand(symbol); instr.op2 = StackValue.BuildClassIndex(symbol.classScope); instr.op3 = StackValue.BuildBlockIndex(blockId); ++pc; AppendInstruction(instr); }
public StackValue GetAtRelative(SymbolNode symbol) { int n = GetRelative(GetStackIndex(symbol)); return Stack[n]; }
private bool CyclicDependencyTest(ProtoCore.AssociativeGraph.GraphNode node, ref SymbolNode cyclicSymbol1, ref SymbolNode cyclicSymbol2) { if (null == node || node.updateNodeRefList.Count == 0) { return true; } var indexMap = new Dictionary<GraphNode, int>(); var lowlinkMap = new Dictionary<GraphNode, int>(); var S = new Stack<GraphNode>(); int index = 0; for (int n = 0; n < codeBlock.instrStream.dependencyGraph.GraphList.Count; ++n) { ProtoCore.AssociativeGraph.GraphNode subNode = codeBlock.instrStream.dependencyGraph.GraphList[n]; indexMap[subNode] = Constants.kInvalidIndex; } var dependencyList = StrongConnectComponent(node, ref index, lowlinkMap, indexMap, S); if (dependencyList == null) { return true; } else { GraphNode firstNode = dependencyList[0]; GraphNode lastNode = node; foreach (var n in dependencyList.GroupBy(x => x.guid).Select(y => y.First())) { core.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidStaticCyclicDependency, ProtoCore.Properties.Resources.kInvalidStaticCyclicDependency, core.CurrentDSFileName, graphNode: n); } firstNode.isCyclic = true; cyclicSymbol1 = firstNode.updateNodeRefList[0].nodeList[0].symbol; cyclicSymbol2 = lastNode.updateNodeRefList[0].nodeList[0].symbol; firstNode.cyclePoint = lastNode; return false; } }
protected void EmitPushForSymbol(SymbolNode symbol, int blockId, ProtoCore.AST.Node identNode) { SetEntry(); Instruction instr = new Instruction(); instr.opCode = ProtoCore.DSASM.OpCode.PUSH; instr.op1 = BuildOperand(symbol); instr.op2 = StackValue.BuildClassIndex(symbol.classScope); instr.op3 = StackValue.BuildBlockIndex(blockId); ++pc; DebugProperties.BreakpointOptions options = core.DebuggerProperties.breakOptions; if (options.HasFlag(DebugProperties.BreakpointOptions.EmitIdentifierBreakpoint)) { instr.debug = GetDebugObject(identNode.line, identNode.col, identNode.endLine, identNode.endCol, pc); } AppendInstruction(instr, identNode.line, identNode.col); }
private void EmitConstructorDefinitionNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, GraphNode gNode = null) { ConstructorDefinitionNode funcDef = node as ConstructorDefinitionNode; ProtoCore.DSASM.CodeBlockType originalBlockType = codeBlock.blockType; codeBlock.blockType = ProtoCore.DSASM.CodeBlockType.kFunction; if (IsParsingMemberFunctionSig()) { Validity.Assert(null == localProcedure); localProcedure = new ProtoCore.DSASM.ProcedureNode(); localProcedure.Name = funcDef.Name; localProcedure.PC = ProtoCore.DSASM.Constants.kInvalidIndex; localProcedure.LocalCount = 0;// Defer till all locals are allocated ProtoCore.Type returnType = localProcedure.ReturnType; if (globalClassIndex != -1) returnType.Name = core.ClassTable.ClassNodes[globalClassIndex].Name; returnType.UID = globalClassIndex; returnType.rank = 0; localProcedure.ReturnType = returnType; localProcedure.IsConstructor = true; localProcedure.RuntimeIndex = 0; localProcedure.IsExternal = funcDef.IsExternLib; Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex, "A constructor node must be associated with class"); localProcedure.LocalCount = 0; localProcedure.ClassID = globalClassIndex; localProcedure.MethodAttribute = funcDef.MethodAttributes; int peekFunctionindex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures.Count; // Append arg symbols List<KeyValuePair<string, ProtoCore.Type>> argsToBeAllocated = new List<KeyValuePair<string, ProtoCore.Type>>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { var argInfo = BuildArgumentInfoFromVarDeclNode(argNode); localProcedure.ArgumentInfos.Add(argInfo); var argType = BuildArgumentTypeFromVarDeclNode(argNode, gNode); localProcedure.ArgumentTypes.Add(argType); argsToBeAllocated.Add(new KeyValuePair<string, ProtoCore.Type>(argInfo.Name, argType)); } localProcedure.IsVarArg = funcDef.Signature.IsVarArg; } int findex = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Append(localProcedure); // Comment Jun: Catch this assert given the condition as this type of mismatch should never occur if (ProtoCore.DSASM.Constants.kInvalidIndex != findex) { Validity.Assert(peekFunctionindex == localProcedure.ID); argsToBeAllocated.ForEach(arg => { int symbolIndex = AllocateArg(arg.Key, findex, arg.Value); if (ProtoCore.DSASM.Constants.kInvalidIndex == symbolIndex) { throw new BuildHaltException("44B557F1"); } }); } else { string message = String.Format(ProtoCore.Properties.Resources.kMethodAlreadyDefined, localProcedure.Name); buildStatus.LogWarning(WarningID.kFunctionAlreadyDefined, message, core.CurrentDSFileName, funcDef.line, funcDef.col, gNode); funcDef.skipMe = true; } } else if (IsParsingMemberFunctionBody()) { EmitCompileLogFunctionStart(GetFunctionSignatureString(funcDef.Name, funcDef.ReturnType, funcDef.Signature, true)); // Build arglist for comparison List<ProtoCore.Type> argList = new List<ProtoCore.Type>(); if (null != funcDef.Signature) { foreach (VarDeclNode argNode in funcDef.Signature.Arguments) { ProtoCore.Type argType = BuildArgumentTypeFromVarDeclNode(argNode, gNode); argList.Add(argType); } } var procNode = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.GetFunctionBySignature(funcDef.Name, argList); globalProcIndex = procNode == null ? Constants.kInvalidIndex : procNode.ID; Validity.Assert(null == localProcedure); localProcedure = core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[globalProcIndex]; Validity.Assert(null != localProcedure); localProcedure.Attributes = PopulateAttributes(funcDef.Attributes); // Its only on the parse body pass where the real pc is determined. Update this procedures' pc //Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex == localProcedure.pc); localProcedure.PC = pc; EmitInstrConsole(ProtoCore.DSASM.kw.allocc, localProcedure.Name); EmitAllocc(globalClassIndex); setConstructorStartPC = true; EmitCallingForBaseConstructor(globalClassIndex, funcDef.BaseConstructor); ProtoCore.FunctionEndPoint fep = null; if (!funcDef.IsExternLib) { // Traverse default assignment for the class emitDebugInfo = false; List<AssociativeNode> defaultArgList = core.ClassTable.ClassNodes[globalClassIndex].DefaultArgExprList; defaultArgList = BuildSSA(defaultArgList, context); foreach (BinaryExpressionNode bNode in defaultArgList) { ProtoCore.AssociativeGraph.GraphNode graphNode = new ProtoCore.AssociativeGraph.GraphNode(); graphNode.exprUID = bNode.ExpressionUID; graphNode.ssaExpressionUID = bNode.SSAExpressionUID; graphNode.procIndex = globalProcIndex; graphNode.classIndex = globalClassIndex; graphNode.languageBlockId = codeBlock.codeBlockId; graphNode.isAutoGenerated = true; bNode.IsProcedureOwned = graphNode.ProcedureOwned = true; EmitBinaryExpressionNode(bNode, ref inferedType, false, graphNode, subPass); } //Traverse default argument for the constructor foreach (ProtoCore.DSASM.ArgumentInfo argNode in localProcedure.ArgumentInfos) { if (!argNode.IsDefault) { continue; } BinaryExpressionNode bNode = argNode.DefaultExpression as BinaryExpressionNode; // build a temporay node for statement : temp = defaultarg; var iNodeTemp =AstFactory.BuildIdentifier(Constants.kTempDefaultArg); BinaryExpressionNode bNodeTemp = new BinaryExpressionNode(); bNodeTemp.LeftNode = iNodeTemp; bNodeTemp.Optr = ProtoCore.DSASM.Operator.assign; bNodeTemp.RightNode = bNode.LeftNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); //duild an inline conditional node for statement: defaultarg = (temp == DefaultArgNode) ? defaultValue : temp; InlineConditionalNode icNode = new InlineConditionalNode(); icNode.IsAutoGenerated = true; BinaryExpressionNode cExprNode = new BinaryExpressionNode(); cExprNode.Optr = ProtoCore.DSASM.Operator.eq; cExprNode.LeftNode = iNodeTemp; cExprNode.RightNode = new DefaultArgNode(); icNode.ConditionExpression = cExprNode; icNode.TrueExpression = bNode.RightNode; icNode.FalseExpression = iNodeTemp; bNodeTemp.LeftNode = bNode.LeftNode; bNodeTemp.RightNode = icNode; EmitBinaryExpressionNode(bNodeTemp, ref inferedType); } emitDebugInfo = true; EmitCodeBlock(funcDef.FunctionBody.Body, ref inferedType, subPass, true); // Build dependency within the function ProtoCore.AssociativeEngine.Utils.BuildGraphNodeDependencies( codeBlock.instrStream.dependencyGraph.GetGraphNodesAtScope(globalClassIndex, globalProcIndex)); // All locals have been stack allocated, update the local count of this function localProcedure.LocalCount = core.BaseOffset; core.ClassTable.ClassNodes[globalClassIndex].ProcTable.Procedures[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.ID; ProtoCore.Lang.FFIActivationRecord record = new ProtoCore.Lang.FFIActivationRecord(); record.JILRecord = jRecord; record.FunctionName = funcDef.Name; record.ModuleName = funcDef.ExternLibName; record.ModuleType = "dll"; record.IsDNI = false; record.ReturnType = funcDef.ReturnType; record.ParameterTypes = localProcedure.ArgumentTypes; fep = new ProtoCore.Lang.FFIFunctionEndPoint(record); } // Construct the fep arguments fep.FormalParams = new ProtoCore.Type[localProcedure.ArgumentTypes.Count]; fep.procedureNode = localProcedure; localProcedure.ArgumentTypes.CopyTo(fep.FormalParams, 0); // 'classIndexAtCallsite' is the class index as it is stored at the callsite function tables int classIndexAtCallsite = globalClassIndex + 1; core.FunctionTable.InitGlobalFunctionEntry(classIndexAtCallsite); Dictionary<string, FunctionGroup> fgroup = core.FunctionTable.GlobalFuncTable[classIndexAtCallsite]; if (!fgroup.ContainsKey(funcDef.Name)) { // Create a new function group in this class ProtoCore.FunctionGroup funcGroup = new ProtoCore.FunctionGroup(); funcGroup.FunctionEndPoints.Add(fep); // Add this group to the class function tables core.FunctionTable.GlobalFuncTable[classIndexAtCallsite].Add(funcDef.Name, funcGroup); } else { // Add this fep into the exisitng function group core.FunctionTable.GlobalFuncTable[classIndexAtCallsite][funcDef.Name].FunctionEndPoints.Add(fep); } int startpc = pc; // Constructors auto return EmitInstrConsole(ProtoCore.DSASM.kw.retc); // Stepping out of a constructor body will have the execution cursor // placed right at the closing curly bracket of the constructor definition. // int closeCurlyBracketLine = 0, closeCurlyBracketColumn = -1; if (null != funcDef.FunctionBody) { closeCurlyBracketLine = funcDef.FunctionBody.endLine; closeCurlyBracketColumn = funcDef.FunctionBody.endCol; } // The execution cursor covers exactly one character -- the closing // curly bracket. Note that we decrement the start-column by one here // because end-column of "FunctionBody" here is *after* the closing // curly bracket, so we want one before that. // EmitRetc(closeCurlyBracketLine, closeCurlyBracketColumn - 1, closeCurlyBracketLine, closeCurlyBracketColumn); // Build and append a graphnode for this return statememt ProtoCore.DSASM.SymbolNode returnNode = new ProtoCore.DSASM.SymbolNode(); returnNode.name = ProtoCore.DSDefinitions.Keyword.Return; ProtoCore.AssociativeGraph.GraphNode retNode = new ProtoCore.AssociativeGraph.GraphNode(); //retNode.symbol = returnNode; retNode.PushSymbolReference(returnNode); retNode.procIndex = globalProcIndex; retNode.classIndex = globalClassIndex; retNode.updateBlock.startpc = startpc; retNode.updateBlock.endpc = pc - 1; PushGraphNode(retNode); EmitCompileLogFunctionEnd(); } // 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; }
protected void EmitPushForSymbolW(SymbolNode symbol, int blockId, int line = ProtoCore.DSASM.Constants.kInvalidIndex, int col = ProtoCore.DSASM.Constants.kInvalidIndex) { SetEntry(); Instruction instr = new Instruction(); instr.opCode = ProtoCore.DSASM.OpCode.PUSHW; instr.op1 = BuildOperand(symbol); instr.op2 = StackValue.BuildClassIndex(symbol.classScope); instr.op3 = StackValue.BuildBlockIndex(blockId); ++pc; //instr.debug = GetDebugObject(line, col, pc); AppendInstruction(instr); }
private void EmitBinaryExpressionNode(AssociativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, bool isTempExpression = false) { BinaryExpressionNode bnode = null; if (!IsParsingGlobal() && !IsParsingGlobalFunctionBody() && !IsParsingMemberFunctionBody()) return; bool isBooleanOperation = false; bnode = node as BinaryExpressionNode; ProtoCore.Type leftType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0); ProtoCore.Type rightType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0); DebugProperties.BreakpointOptions oldOptions = core.DebuggerProperties.breakOptions; // If this is an assignment statement, setup the top level graph node bool isGraphInScope = false; if (ProtoCore.DSASM.Operator.assign == bnode.Optr) { if (null == graphNode) { isGraphInScope = true; EmitCompileLog("==============Start Node==============\n"); graphNode = new ProtoCore.AssociativeGraph.GraphNode(); graphNode.AstID = bnode.ID; graphNode.OriginalAstID = bnode.OriginalAstID; graphNode.exprUID = bnode.ExpressionUID; graphNode.ssaSubExpressionID = bnode.SSASubExpressionID; graphNode.ssaExpressionUID = bnode.SSAExpressionUID; graphNode.IsModifier = bnode.IsModifier; graphNode.guid = bnode.guid; graphNode.procIndex = globalProcIndex; graphNode.classIndex = globalClassIndex; graphNode.languageBlockId = codeBlock.codeBlockId; graphNode.ProcedureOwned = bnode.IsProcedureOwned; // // Comment Jun: // If the expression ID of the assignment node in the context execDirtyFlag list is false, // it means that it was already executed. This needs to be marked as not dirty if (core.Options.IsDeltaExecution) { if (context.exprExecutionFlags.ContainsKey(bnode.ExpressionUID)) { graphNode.isDirty = context.exprExecutionFlags[bnode.ExpressionUID]; } } } if (bnode.isSSAFirstAssignment) { firstSSAGraphNode = graphNode; } HandlePointerList(bnode); if (bnode.LeftNode is IdentifierListNode) { // If the lhs is an identifierlist then emit the entire expression here // This also handles the dependencies of expressions where the lhs is a member variable (this.x = y) EmitLHSIdentifierListForBinaryExpr(bnode, ref inferedType, isBooleanOp, graphNode, subPass); if (isGraphInScope) { EmitCompileLog("==============End Node==============\n"); } return; } else if (bnode.LeftNode is IdentifierNode) { if (bnode.LeftNode.Name.Equals(ProtoCore.DSDefinitions.Keyword.This)) { string errorMessage = ProtoCore.Properties.Resources.kInvalidThis; if (localProcedure != null) { if (localProcedure.IsStatic) { errorMessage = ProtoCore.Properties.Resources.kUsingThisInStaticFunction; } else if (localProcedure.ClassID == Constants.kGlobalScope) { errorMessage = ProtoCore.Properties.Resources.kInvalidThis; } else { errorMessage = ProtoCore.Properties.Resources.kAssingToThis; } } core.BuildStatus.LogWarning(WarningID.kInvalidThis, errorMessage, core.CurrentDSFileName, bnode.line, bnode.col, graphNode); if (isGraphInScope) { EmitCompileLog("==============End Node==============\n"); } return; } if (EmitLHSThisDotProperyForBinaryExpr(bnode, ref inferedType, isBooleanOp, graphNode, subPass)) { if (isGraphInScope) { EmitCompileLog("==============End Node==============\n"); } return; } } } else //(ProtoCore.DSASM.Operator.assign != b.Optr) { // Traversing the left node if this binary expression is not an assignment // isBooleanOperation = ProtoCore.DSASM.Operator.lt == bnode.Optr || ProtoCore.DSASM.Operator.gt == bnode.Optr || ProtoCore.DSASM.Operator.le == bnode.Optr || ProtoCore.DSASM.Operator.ge == bnode.Optr || ProtoCore.DSASM.Operator.eq == bnode.Optr || ProtoCore.DSASM.Operator.nq == bnode.Optr || ProtoCore.DSASM.Operator.and == bnode.Optr || ProtoCore.DSASM.Operator.or == bnode.Optr; DfsTraverse(bnode.LeftNode, ref inferedType, isBooleanOperation, graphNode, subPass); if (inferedType.UID == (int)PrimitiveType.kTypeFunctionPointer && subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier && emitDebugInfo) { buildStatus.LogSemanticError(Resources.FunctionPointerNotAllowedAtBinaryExpression, core.CurrentDSFileName, bnode.LeftNode.line, bnode.LeftNode.col); } leftType.UID = inferedType.UID; leftType.rank = inferedType.rank; } int startpc = ProtoCore.DSASM.Constants.kInvalidIndex; if ((ProtoCore.DSASM.Operator.assign == bnode.Optr) && (bnode.RightNode is LanguageBlockNode)) { inferedType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0); } if (null != localProcedure && localProcedure.IsConstructor && setConstructorStartPC) { startpc -= 1; setConstructorStartPC = false; } if (bnode.RightNode == null && bnode.Optr == Operator.assign && bnode.LeftNode is IdentifierNode) { DebugProperties.BreakpointOptions newOptions = oldOptions; newOptions |= DebugProperties.BreakpointOptions.SuppressNullVarDeclarationBreakpoint; core.DebuggerProperties.breakOptions = newOptions; IdentifierNode t = bnode.LeftNode as IdentifierNode; ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool hasAllocated = VerifyAllocation(t.Value, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); if (hasAllocated) { bool allowDependent = graphNode.allowDependents; graphNode.allowDependents = false; bnode.RightNode =AstFactory.BuildIdentifier(t.Value); graphNode.allowDependents = false; } else { bnode.RightNode = new NullNode(); } } // Keep track of current pc, because when travese right node it // may generate null assignment ( x = null; if x hasn't been defined // yet - Yu Ke startpc = pc; DfsTraverse(bnode.RightNode, ref inferedType, isBooleanOperation, graphNode, subPass, node); rightType.UID = inferedType.UID; rightType.rank = inferedType.rank; BinaryExpressionNode rightNode = bnode.RightNode as BinaryExpressionNode; if ((rightNode != null) && (ProtoCore.DSASM.Operator.assign == rightNode.Optr)) { DfsTraverse(rightNode.LeftNode, ref inferedType, false, graphNode); } if (bnode.Optr != ProtoCore.DSASM.Operator.assign) { if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { return; } if (inferedType.UID == (int)PrimitiveType.kTypeFunctionPointer && emitDebugInfo) { buildStatus.LogSemanticError(Resources.FunctionPointerNotAllowedAtBinaryExpression, core.CurrentDSFileName, bnode.RightNode.line, bnode.RightNode.col); } EmitBinaryOperation(leftType, rightType, bnode.Optr); isBooleanOp = false; return; } Validity.Assert(null != graphNode); if (!isTempExpression) { graphNode.updateBlock.startpc = pc; } currentBinaryExprUID = bnode.ExpressionUID; // These have been integrated into "EmitGetterSetterForIdentList" so // that stepping through class properties can be supported. Setting // these values here will cause issues with statements like this to // be highlighted in its entirety (all the way up to closing bracket // without highlighting the semi-colon). // // x = foo(a, b); // // bnode.RightNode.line = bnode.line; // bnode.RightNode.col = bnode.col; // bnode.RightNode.endLine = bnode.endLine; // bnode.RightNode.endCol = bnode.endCol; // Traverse the entire RHS expression DfsTraverse(bnode.RightNode, ref inferedType, isBooleanOperation, graphNode, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, bnode); subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier; if (bnode.LeftNode is IdentifierNode) { // TODO Jun: Cleansify this block where the lhs is being handled. // For one, make the return as a return node IdentifierNode t = bnode.LeftNode as IdentifierNode; ProtoCore.DSASM.SymbolNode symbolnode = null; ProtoCore.AssociativeGraph.UpdateNodeRef leftNodeGlobalRef = null; string s = t.Value; if (s == ProtoCore.DSDefinitions.Keyword.Return) { Validity.Assert(null == symbolnode); symbolnode = new ProtoCore.DSASM.SymbolNode(); symbolnode.name = s; symbolnode.isTemp = s.StartsWith("%"); symbolnode.functionIndex = globalProcIndex; symbolnode.classScope = globalClassIndex; EmitReturnStatement(node, inferedType); // Comment Jun: The inline conditional holds a graphnode and traversing its body will set isReturn = true // Resolve that here as an inline conditional is obviosuly not a return graphnode if (!graphNode.isInlineConditional) { graphNode.isReturn = true; } } else { leftNodeGlobalRef = GetUpdatedNodeRef(bnode.LeftNode); // check whether the variable name is a function name if (globalClassIndex != ProtoCore.DSASM.Constants.kGlobalScope) { bool isAccessibleFp; int realType; var procNode = core.ClassTable.ClassNodes[globalClassIndex].GetMemberFunction(t.Name, null, globalClassIndex, out isAccessibleFp, out realType); if (procNode != null && procNode.ID != Constants.kInvalidIndex && emitDebugInfo) { buildStatus.LogSemanticError(String.Format(Resources.FunctionAsVariableError, t.Name), core.CurrentDSFileName, t.line, t.col); } } //int type = (int)ProtoCore.PrimitiveType.kTypeVoid; bool isLocalDeclaration = t.IsLocal; bool isAccessible = false; bool isAllocated = false; if (isLocalDeclaration) { isAllocated = VerifyAllocationInScope(t.Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); } else { isAllocated = VerifyAllocation(t.Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); } int runtimeIndex = (!isAllocated || !isAccessible) ? codeBlock.symbolTable.RuntimeIndex : symbolnode.runtimeTableIndex; if (isAllocated && !isAccessible) { string message = String.Format(ProtoCore.Properties.Resources.kPropertyIsInaccessible, t.Name); buildStatus.LogWarning(WarningID.kAccessViolation, message, core.CurrentDSFileName, t.line, t.col, graphNode); } int dimensions = 0; if (null != t.ArrayDimensions) { graphNode.isIndexingLHS = true; dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions, graphNode, bnode); } // Comment Jun: Attempt to get the modified argument arrays in the current method // Comment Jun: As of R1 - arrays are copy constructed and cannot propagate update unless explicitly returned ProtoCore.Type castType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, Constants.kArbitraryRank); var tident = bnode.LeftNode as TypedIdentifierNode; if (tident != null) { int castUID = core.ClassTable.IndexOf(tident.datatype.Name); if ((int)PrimitiveType.kInvalidType == castUID) { castType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kInvalidType, 0); castType.Name = tident.datatype.Name; castType.rank = tident.datatype.rank; } else { castType = core.TypeSystem.BuildTypeObject(castUID, tident.datatype.rank); } } if (ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex) { // In a class if (ProtoCore.DSASM.Constants.kInvalidIndex == globalProcIndex) { string message = "A binary assignment inside a class must be inside a function (AB5E3EC1)"; buildStatus.LogSemanticError(message, core.CurrentDSFileName, bnode.line, bnode.col); throw new BuildHaltException(message); } // TODO Jun: refactor this by having symbol table functions for retrieval of node index int symbol = ProtoCore.DSASM.Constants.kInvalidIndex; bool isMemVar = false; if (symbolnode != null) { if (symbolnode.classScope != ProtoCore.DSASM.Constants.kInvalidIndex && symbolnode.functionIndex == ProtoCore.DSASM.Constants.kGlobalScope) { isMemVar = true; } symbol = symbolnode.symbolTableIndex; } if (!isMemVar) { // This is local variable // TODO Jun: If this local var exists globally, should it allocate a local copy? if (!isAllocated || !isAccessible) { symbolnode = Allocate(globalClassIndex, globalClassIndex, globalProcIndex, t.Name, inferedType, ProtoCore.DSASM.Constants.kPrimitiveSize, false, ProtoCore.CompilerDefinitions.AccessModifier.kPublic, ProtoCore.DSASM.MemoryRegion.kMemStack, bnode.line, bnode.col); // Add the symbols during watching process to the watch symbol list. if (core.Options.RunMode == ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { core.watchSymbolList.Add(symbolnode); } Validity.Assert(symbolnode != null); } else { symbolnode.datatype = inferedType; } if (bnode.LeftNode is TypedIdentifierNode) { symbolnode.SetStaticType(castType); } castType = symbolnode.staticType; EmitPushVarData(dimensions, castType.UID, castType.rank); symbol = symbolnode.symbolTableIndex; if (t.Name == ProtoCore.DSASM.Constants.kTempArg) { EmitInstrConsole(ProtoCore.DSASM.kw.pop, t.Name); EmitPopForSymbol(symbolnode, runtimeIndex); } else { if (core.Options.RunMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { EmitInstrConsole(ProtoCore.DSASM.kw.pop, t.Name); EmitPopForSymbol(symbolnode, runtimeIndex, node.line, node.col, node.endLine, node.endCol); } else { EmitInstrConsole(ProtoCore.DSASM.kw.popw, t.Name); EmitPopForSymbolW(symbolnode, runtimeIndex, node.line, node.col, node.endLine, node.endCol); } } } else { if (bnode.LeftNode is TypedIdentifierNode) { symbolnode.SetStaticType(castType); } castType = symbolnode.staticType; EmitPushVarData(dimensions, castType.UID, castType.rank); EmitInstrConsole(ProtoCore.DSASM.kw.popm, t.Name); if (symbolnode.isStatic) { var op = StackValue.BuildStaticMemVarIndex(symbol); EmitPopm(op, runtimeIndex, node.line, node.col, node.endLine, node.endCol); } else { var op = StackValue.BuildMemVarIndex(symbol); EmitPopm(op, runtimeIndex, node.line, node.col, node.endLine, node.endCol); } } //if (t.Name[0] != '%') { AutoGenerateUpdateReference(bnode.LeftNode, graphNode); } // Dependency if (!isTempExpression) { // Dependency graph top level symbol graphNode.PushSymbolReference(symbolnode); EmitDependency(bnode.ExpressionUID, bnode.modBlkUID, bnode.isSSAAssignment); functionCallStack.Clear(); } } else { if (!isAllocated) { symbolnode = Allocate(globalClassIndex, globalClassIndex, globalProcIndex, t.Name, inferedType, ProtoCore.DSASM.Constants.kPrimitiveSize, false, ProtoCore.CompilerDefinitions.AccessModifier.kPublic, ProtoCore.DSASM.MemoryRegion.kMemStack, bnode.line, bnode.col); if (core.Options.RunMode == ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { core.watchSymbolList.Add(symbolnode); } if (dimensions > 0) { symbolnode.datatype.rank = dimensions; } } else if (dimensions == 0) { symbolnode.datatype = inferedType; } // // Jun Comment: // Update system uses the following registers: // _ex stores prev value of ident 't' - VM assigned // _fx stores new value - VM assigned // if (bnode.LeftNode is TypedIdentifierNode) { symbolnode.SetStaticType(castType); } castType = symbolnode.staticType; if (bnode.IsInputExpression) { StackValue regLX = StackValue.BuildRegister(Registers.LX); EmitInstrConsole(ProtoCore.DSASM.kw.pop, ProtoCore.DSASM.kw.regLX); EmitPop(regLX, globalClassIndex); graphNode.updateBlock.updateRegisterStartPC = pc; EmitInstrConsole(ProtoCore.DSASM.kw.push, ProtoCore.DSASM.kw.regLX); EmitPush(regLX); } EmitPushVarData(dimensions, castType.UID, castType.rank); if (core.Options.RunMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { EmitInstrConsole(ProtoCore.DSASM.kw.pop, symbolnode.name); EmitPopForSymbol(symbolnode, runtimeIndex, node.line, node.col, node.endLine, node.endCol); } else { EmitInstrConsole(ProtoCore.DSASM.kw.popw, symbolnode.name); EmitPopForSymbolW(symbolnode, runtimeIndex, node.line, node.col, node.endLine, node.endCol); } AutoGenerateUpdateReference(bnode.LeftNode, graphNode); // Dependency if (!isTempExpression) { // Dependency graph top level symbol graphNode.PushSymbolReference(symbolnode); EmitDependency(bnode.ExpressionUID, bnode.modBlkUID, bnode.isSSAAssignment); functionCallStack.Clear(); } } } // Dependency graph top level symbol //graphNode.symbol = symbolnode; // Assign the end pc to this graph node's update block // Dependency graph construction is complete for this expression if (!isTempExpression) { if (null != leftNodeGlobalRef) { if (null != localProcedure) { // Track for updated globals only in user defined functions if (!localProcedure.IsAssocOperator && !localProcedure.IsAutoGenerated) { localProcedure.UpdatedGlobalVariables.Push(leftNodeGlobalRef); } } } { if (!graphNode.IsSSANode() && !ProtoCore.AssociativeEngine.Utils.IsTempVarLHS(graphNode)) { // This is the last expression in the SSA'd expression // Backtrack and assign the this last final assignment graphnode to its associated SSA graphnodes for (int n = codeBlock.instrStream.dependencyGraph.GraphList.Count - 1; n >= 0; --n) { GraphNode currentNode = codeBlock.instrStream.dependencyGraph.GraphList[n]; bool isWithinSameScope = currentNode.classIndex == graphNode.classIndex && currentNode.procIndex == graphNode.procIndex; bool isWithinSameExpressionID = currentNode.exprUID == graphNode.exprUID; if (isWithinSameScope && isWithinSameExpressionID) { graphNode.IsLastNodeInSSA = true; if (null == codeBlock.instrStream.dependencyGraph.GraphList[n].lastGraphNode) { codeBlock.instrStream.dependencyGraph.GraphList[n].lastGraphNode = graphNode; } } } } } graphNode.ResolveLHSArrayIndex(); graphNode.updateBlock.endpc = pc - 1; PushGraphNode(graphNode); if (core.InlineConditionalBodyGraphNodes.Count > 0) { core.InlineConditionalBodyGraphNodes.Last().Add(graphNode); } SymbolNode cyclicSymbol1 = null; SymbolNode cyclicSymbol2 = null; if (core.Options.staticCycleCheck) { if (!CyclicDependencyTest(graphNode, ref cyclicSymbol1, ref cyclicSymbol2)) { Validity.Assert(null != cyclicSymbol1); Validity.Assert(null != cyclicSymbol2); // // Set the first symbol that triggers the cycle to null ProtoCore.AssociativeGraph.GraphNode nullAssignGraphNode1 = new ProtoCore.AssociativeGraph.GraphNode(); nullAssignGraphNode1.updateBlock.startpc = pc; EmitPushNull(); EmitPushVarData(0); EmitInstrConsole(ProtoCore.DSASM.kw.pop, cyclicSymbol1.name); EmitPopForSymbol(cyclicSymbol1, cyclicSymbol1.runtimeTableIndex, node.line, node.col, node.endLine, node.endCol); nullAssignGraphNode1.PushSymbolReference(cyclicSymbol1); nullAssignGraphNode1.procIndex = globalProcIndex; nullAssignGraphNode1.classIndex = globalClassIndex; nullAssignGraphNode1.updateBlock.endpc = pc - 1; PushGraphNode(nullAssignGraphNode1); EmitDependency(ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, false); // // Set the second symbol that triggers the cycle to null ProtoCore.AssociativeGraph.GraphNode nullAssignGraphNode2 = new ProtoCore.AssociativeGraph.GraphNode(); nullAssignGraphNode2.updateBlock.startpc = pc; EmitPushNull(); EmitPushVarData(0); EmitInstrConsole(ProtoCore.DSASM.kw.pop, cyclicSymbol2.name); EmitPopForSymbol(cyclicSymbol2, cyclicSymbol2.runtimeTableIndex, node.line, node.col, node.endLine, node.endCol); nullAssignGraphNode2.PushSymbolReference(cyclicSymbol2); nullAssignGraphNode2.procIndex = globalProcIndex; nullAssignGraphNode2.classIndex = globalClassIndex; nullAssignGraphNode2.updateBlock.endpc = pc - 1; PushGraphNode(nullAssignGraphNode2); EmitDependency(ProtoCore.DSASM.Constants.kInvalidIndex, ProtoCore.DSASM.Constants.kInvalidIndex, false); } } if (isGraphInScope) { EmitCompileLog("==============End Node==============\n"); } } // Jun Comment: If it just so happens that the inline conditional is in the return statement if (graphNode.isInlineConditional) { graphNode.isReturn = false; if (0 == graphNode.updateNodeRefList.Count) { graphNode.isReturn = true; } } } else { string message = "Illegal assignment (90787393)"; buildStatus.LogSemanticError(message, core.CurrentDSFileName, bnode.line, bnode.col); throw new BuildHaltException(message); } core.DebuggerProperties.breakOptions = oldOptions; }
protected void EmitStringNode( Node node, ref Type inferedType, AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone) { if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { return; } dynamic sNode = node; if (!enforceTypeCheck || core.TypeSystem.IsHigherRank((int)PrimitiveType.kTypeString, inferedType.UID)) { inferedType.UID = (int)PrimitiveType.kTypeString; } if (core.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide) { EmitInstrConsole(ProtoCore.DSASM.kw.push, 0 + "[guide]"); StackValue opNumGuides = StackValue.BuildReplicationGuide(0); EmitPush(opNumGuides); } string value = (string)sNode.Value; StackValue svString = core.Heap.AllocateFixedString(value); if (core.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide) { EmitInstrConsole(kw.pushg, "\"" + value + "\""); EmitPushG(svString, node.line, node.col); } else { EmitInstrConsole(kw.push, "\"" + value + "\""); EmitPush(svString, node.line, node.col); } if (IsAssociativeArrayIndexing && graphNode != null && graphNode.isIndexingLHS) { SymbolNode literalSymbol = new SymbolNode(); literalSymbol.name = value; var dimNode = new AssociativeGraph.UpdateNode(); dimNode.symbol = literalSymbol; dimNode.nodeType = AssociativeGraph.UpdateNodeType.kLiteral; graphNode.dimensionNodeList.Add(dimNode); } }
private void TraverseDotCallArguments(FunctionCallNode funcCall, FunctionDotCallNode dotCall, ProcedureNode procCallNode, List<ProtoCore.Type> arglist, string procName, int classIndex, string className, bool isStaticCall, bool isConstructor, GraphNode graphNode, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass, BinaryExpressionNode bnode) { // Update graph dependencies if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier && graphNode != null) { if (isStaticCall) { Validity.Assert(classIndex != Constants.kInvalidIndex); Validity.Assert(!string.IsNullOrEmpty(className)); SymbolNode classSymbol = new SymbolNode(); classSymbol.name = className; classSymbol.classScope = classIndex; PushSymbolAsDependent(classSymbol, graphNode); } } int funtionArgCount = 0; for (int n = 0; n < funcCall.FormalArguments.Count; ++n) { if (isStaticCall || isConstructor) { if (n != Constants.kDotArgIndexArrayArgs) { continue; } } AssociativeNode paramNode = funcCall.FormalArguments[n]; ProtoCore.Type paramType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0); emitReplicationGuide = false; // If it's a binary node then continue type check, otherwise // disable type check and just take the type of paramNode itself enforceTypeCheck = !(paramNode is BinaryExpressionNode); if (ProtoCore.DSASM.Constants.kDotArgIndexPtr == n) { // Traversing the first arg (the LHS pointer/Static instanct/Constructor // Replication guides only allowed on method, e.g., // // x = p<1>.f({1,2}<2>); // // But not on getter, e.g., // // c = a<1>.x<2>; if (!CoreUtils.IsGetterSetter(procName) && !isConstructor) { emitReplicationGuide = true; } DfsTraverse(paramNode, ref paramType, false, graphNode, subPass, bnode); } else if (ProtoCore.DSASM.Constants.kDotArgIndexArrayArgs == n) { // Traversing the actual arguments passed into the function // (not the dot function) int defaultArgNumber = 0; // If its null this is the second call in a chained dot if (null != procCallNode) { defaultArgNumber = procCallNode.ArgumentInfos.Count - dotCall.FunctionCall.FormalArguments.Count; } // Enable graphnode dependencies if its a setter method bool allowDependentState = null != graphNode ? graphNode.allowDependents : false; if (CoreUtils.IsSetter(procName)) { // If the arguments are not temporaries ExprListNode exprList = paramNode as ExprListNode; Validity.Assert(1 == exprList.Exprs.Count); string varname = string.Empty; if (exprList.Exprs[0] is IdentifierNode) { varname = (exprList.Exprs[0] as IdentifierNode).Name; if (!CoreUtils.IsAutoGeneratedVar(varname)) { graphNode.allowDependents = true; } else if (CoreUtils.IsSSATemp(varname) && core.Options.GenerateSSA) { graphNode.allowDependents = true; } } else { graphNode.allowDependents = true; } } emitReplicationGuide = true; if (defaultArgNumber > 0) { ExprListNode exprList = paramNode as ExprListNode; if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { for (int i = 0; i < defaultArgNumber; i++) { exprList.Exprs.Add(new DefaultArgNode()); } } if (!isStaticCall && !isConstructor) { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); funtionArgCount = exprList.Exprs.Count; } else { foreach (AssociativeNode exprListNode in exprList.Exprs) { bool repGuideState = emitReplicationGuide; if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { emitReplicationGuide = false; } DfsTraverse(exprListNode, ref paramType, false, graphNode, subPass, bnode); emitReplicationGuide = repGuideState; arglist.Add(paramType); } } } else { ExprListNode exprList = paramNode as ExprListNode; // Comment Jun: This is a getter/setter or a an auto-generated thisarg function... // ...add the dynamic sv that will be resolved as a pointer at runtime if (!isStaticCall && !isConstructor) { // TODO Jun: pls get rid of subPass checking outside the core travesal if (ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone == subPass) { exprList.Exprs.Insert(0, new DynamicNode()); } } if (exprList.Exprs.Count > 0) { foreach (AssociativeNode exprListNode in exprList.Exprs) { bool repGuideState = emitReplicationGuide; if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { emitReplicationGuide = false; } DfsTraverse(exprListNode, ref paramType, false, graphNode, subPass, bnode); emitReplicationGuide = repGuideState; arglist.Add(paramType); } if (subPass != ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier && !isStaticCall && !isConstructor) { EmitInstrConsole(ProtoCore.DSASM.kw.alloca, exprList.Exprs.Count.ToString()); EmitPopArray(exprList.Exprs.Count); if (exprList.ArrayDimensions != null) { int dimensions = DfsEmitArrayIndexHeap(exprList.ArrayDimensions, graphNode); EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, dimensions.ToString() + "[dim]"); EmitPushArrayIndex(dimensions); } } } else { if (!isStaticCall && !isConstructor) { if (exprList != null) { bool emitReplicationGuideState = emitReplicationGuide; emitReplicationGuide = false; DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); emitReplicationGuide = emitReplicationGuideState; } else { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); } } } funtionArgCount = exprList.Exprs.Count; } emitReplicationGuide = false; // Restore the state only if it is a setter method if (ProtoCore.Utils.CoreUtils.IsSetter(procName)) { graphNode.allowDependents = allowDependentState; } } else if (ProtoCore.DSASM.Constants.kDotArgIndexArgCount == n) { IntNode argNumNode = new IntNode(funtionArgCount); DfsTraverse(argNumNode, ref paramType, false, graphNode, subPass); } else { DfsTraverse(paramNode, ref paramType, false, graphNode, subPass); } emitReplicationGuide = false; enforceTypeCheck = true; if (!isStaticCall || !isConstructor) { arglist.Add(paramType); } } }
protected void EmitDoubleNode(Node node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone) { if (subPass == ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier) { return; } double value; if (node is AST.ImperativeAST.DoubleNode) { value = (node as AST.ImperativeAST.DoubleNode).Value; } else if (node is AST.AssociativeAST.DoubleNode) { value = (node as AST.AssociativeAST.DoubleNode).Value; } else { throw new InvalidDataException("The input node is not DoubleNode"); } if (!enforceTypeCheck || core.TypeSystem.IsHigherRank((int)PrimitiveType.kTypeDouble, inferedType.UID)) { inferedType.UID = (int)PrimitiveType.kTypeDouble; } inferedType.UID = isBooleanOp ? (int)PrimitiveType.kTypeBool : inferedType.UID; if (core.Options.TempReplicationGuideEmptyFlag) { if (emitReplicationGuide) { int replicationGuides = 0; // Push the number of guides EmitInstrConsole(ProtoCore.DSASM.kw.push, replicationGuides + "[guide]"); StackValue opNumGuides = StackValue.BuildReplicationGuide(replicationGuides); EmitPush(opNumGuides); } } StackValue op = StackValue.BuildDouble(value); if (core.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide) { EmitInstrConsole(ProtoCore.DSASM.kw.pushg, value.ToString()); EmitPushG(op, node.line, node.col); } else { EmitInstrConsole(ProtoCore.DSASM.kw.push, value.ToString()); EmitPush(op, node.line, node.col); } if (IsAssociativeArrayIndexing) { if (null != graphNode) { // Get the last dependent which is the current identifier being indexed into SymbolNode literalSymbol = new SymbolNode(); literalSymbol.name = value.ToString(); AssociativeGraph.UpdateNode intNode = new AssociativeGraph.UpdateNode(); intNode.symbol = literalSymbol; intNode.nodeType = AssociativeGraph.UpdateNodeType.kLiteral; if (graphNode.isIndexingLHS) { graphNode.dimensionNodeList.Add(intNode); } else { int lastDependentIndex = graphNode.dependentList.Count - 1; ProtoCore.AssociativeGraph.UpdateNode currentDependentNode = graphNode.dependentList[lastDependentIndex].updateNodeRefList[0].nodeList[0]; currentDependentNode.dimensionNodeList.Add(intNode); if (core.Options.GenerateSSA) { if (null != firstSSAGraphNode) { lastDependentIndex = firstSSAGraphNode.dependentList.Count - 1; ProtoCore.AssociativeGraph.UpdateNode firstSSAUpdateNode = firstSSAGraphNode.dependentList[lastDependentIndex].updateNodeRefList[0].nodeList[0]; firstSSAUpdateNode.dimensionNodeList.Add(intNode); } } } } } }