/* proc EmitIdentNode(identnode, graphnode) if ssa // Check an if this identifier is array indexed // The array index is a secondary property and is not the original array property of the AST. this is required because this array index is meant only to resolve graphnode dependency with arrays if node.arrayindex.secondary is valid dimension = traverse(node.arrayindex.secondary) // Create a new dependent with the array indexing dependent = new GraphNode(identnode.name, dimension) graphnode.pushdependent(dependent) end end end */ private void EmitIdentifierNode(AssociativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone, BinaryExpressionNode parentNode = null) { IdentifierNode t = node as IdentifierNode; if (t.Name.Equals(ProtoCore.DSDefinitions.Keyword.This)) { if (subPass != AssociativeSubCompilePass.kNone) { return; } if (localProcedure != null) { if (localProcedure.isStatic) { string message = ProtoCore.BuildData.WarningMessage.kUsingThisInStaticFunction; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } else if (localProcedure.classScope == Constants.kGlobalScope) { string message = ProtoCore.BuildData.WarningMessage.kInvalidThis; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } else { EmitThisPointerNode(subPass); return; } } else { string message = ProtoCore.BuildData.WarningMessage.kInvalidThis; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } } int dimensions = 0; ProtoCore.DSASM.SymbolNode symbolnode = null; int runtimeIndex = codeBlock.symbolTable.runtimeIndex; ProtoCore.Type type = new ProtoCore.Type(); type.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; type.IsIndexable = false; bool isAccessible = false; if (null == t.ArrayDimensions) { //check if it is a function instance ProtoCore.DSASM.ProcedureNode procNode = null; procNode = compileStateTracker.GetFirstVisibleProcedure(t.Name, null, codeBlock); if (null != procNode) { if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { // A global function inferedType.IsIndexable = false; inferedType.UID = (int)PrimitiveType.kTypeFunctionPointer; if (ProtoCore.DSASM.AssociativeSubCompilePass.kUnboundIdentifier != subPass) { int fptr = compileStateTracker.FunctionPointerTable.functionPointerDictionary.Count; ProtoCore.DSASM.FunctionPointerNode fptrNode = new ProtoCore.DSASM.FunctionPointerNode(procNode.procId, procNode.runtimeIndex); compileStateTracker.FunctionPointerTable.functionPointerDictionary.TryAdd(fptr, fptrNode); compileStateTracker.FunctionPointerTable.functionPointerDictionary.TryGetBySecond(fptrNode, out fptr); EmitPushVarData(runtimeIndex, 0); EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Name); ProtoCore.DSASM.StackValue opFunctionPointer = new ProtoCore.DSASM.StackValue(); opFunctionPointer.optype = ProtoCore.DSASM.AddressType.FunctionPointer; opFunctionPointer.opdata = fptr; opFunctionPointer.opdata_d = fptr; EmitPush(opFunctionPointer, t.line, t.col); } return; } } } bool isAllocated = VerifyAllocation(t.Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); // If its executing in interpreter mode - attempt to find and anubond identifer in a child block // Remove this, because if we are watching cases like: //c1 = [Imperative] //{ // a = 1; // b = 2; //} // //c2 = [Associative] //{ // a = 3; // b = 4; //} //After c2 is executed, the watch value for a, b will be 1, 2. //if (ProtoCore.DSASM.ExecutionMode.kExpressionInterpreter == core.ExecMode) //{ // if (!isAllocated) // { // isAllocated = VerifyAllocationIncludingChildBlock(t.Name, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); // } //} if (AssociativeSubCompilePass.kUnboundIdentifier == subPass) { if (symbolnode == null) { if (isAllocated) { string message = String.Format(WarningMessage.kPropertyIsInaccessible, t.Value); if (localProcedure != null && localProcedure.isStatic) { SymbolNode tempSymbolNode; VerifyAllocation( t.Name, globalClassIndex, Constants.kGlobalScope, out tempSymbolNode, out isAccessible); if (tempSymbolNode != null && !tempSymbolNode.isStatic && isAccessible) { message = String.Format(WarningMessage.kUsingNonStaticMemberInStaticContext, t.Value); } } buildStatus.LogWarning( ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, t.line, t.col); } else { string message = String.Format(WarningMessage.kUnboundIdentifierMsg, t.Value); buildStatus.LogWarning(WarningID.kIdUnboundIdentifier, message, compileStateTracker.CurrentDSFileName, t.line, t.col); } if (ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter != compileStateTracker.ExecMode) { inferedType.UID = (int)ProtoCore.PrimitiveType.kTypeNull; // Jun Comment: Specification // If resolution fails at this point a com.Design-Script.Imperative.Core.UnboundIdentifier // warning is emitted during pre-execute phase, and at the ID is bound to null. (R1 - Feb) int startpc = pc; EmitPushNull(); // Push the identifier local block dimensions = 0; EmitPushVarData(runtimeIndex, dimensions); ProtoCore.Type varType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, false, 0); // TODO Jun: Refactor Allocate() to just return the symbol node itself ProtoCore.DSASM.SymbolNode symnode = Allocate(globalClassIndex, globalClassIndex, globalProcIndex, t.Value, varType, ProtoCore.DSASM.Constants.kPrimitiveSize, false, ProtoCore.DSASM.AccessSpecifier.kPublic, ProtoCore.DSASM.MemoryRegion.kMemStack, t.line, t.col, graphNode); Debug.Assert(symnode != null); int symbolindex = symnode.symbolTableIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex != globalClassIndex) { symbolnode = compileStateTracker.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList[symbolindex]; } else { symbolnode = codeBlock.symbolTable.symbolList[symbolindex]; } EmitInstrConsole(ProtoCore.DSASM.kw.pop, t.Value); EmitPopForSymbol(symnode); // Comment it out. It doesn't work for the following // case: // // x = foo.X; // x = bar.X; // // where bar hasn't defined yet, so a null assign // graph is generated for this case: // // bar = null; // x = %dot(.., {bar}, ...); // // unfortunately the expression UID of this null graph // node is 0, which is wrong. Some update routines have // the assumption that the exprUID of graph node is // incremental. // // We may generate SSA for all expressions to fix this // issue. -Yu Ke /* ProtoCore.AssociativeGraph.GraphNode nullAssignGraphNode = new ProtoCore.AssociativeGraph.GraphNode(); nullAssignGraphNode.PushSymbolReference(symbolnode); nullAssignGraphNode.procIndex = globalProcIndex; nullAssignGraphNode.classIndex = globalClassIndex; nullAssignGraphNode.updateBlock.startpc = startpc; nullAssignGraphNode.updateBlock.endpc = pc - 1; codeBlock.instrStream.dependencyGraph.Push(nullAssignGraphNode); */ } } if (null != t.ArrayDimensions) { dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions, graphNode, parentNode, subPass); } } else { if (compileStateTracker.ExecMode == ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter && !isAllocated) { // It happens when the debugger try to watch a variable // which has been out of scope (as watch is done through // execute an expression "t = v;" where v is the variable // to be watched. EmitPushNull(); return; } Validity.Assert(isAllocated); if (graphNode != null && IsAssociativeArrayIndexing && !CoreUtils.IsAutoGeneratedVar(symbolnode.name)) { ProtoCore.AssociativeGraph.UpdateNode updateNode = new ProtoCore.AssociativeGraph.UpdateNode(); updateNode.symbol = symbolnode; updateNode.nodeType = ProtoCore.AssociativeGraph.UpdateNodeType.kSymbol; if (graphNode.isIndexingLHS) { graphNode.dimensionNodeList.Add(updateNode); } else { int curDepIndex = graphNode.dependentList.Count - 1; if (curDepIndex >= 0) { var curDep = graphNode.dependentList[curDepIndex].updateNodeRefList[0].nodeList[0]; curDep.dimensionNodeList.Add(updateNode); if (null != firstSSAGraphNode) { curDepIndex = firstSSAGraphNode.dependentList.Count - 1; if (curDepIndex >= 0) { ProtoCore.AssociativeGraph.UpdateNode firstSSAUpdateNode = firstSSAGraphNode.dependentList[curDepIndex].updateNodeRefList[0].nodeList[0]; firstSSAUpdateNode.dimensionNodeList.Add(updateNode); } } } } } // If it is a property, replaced it with getter: %get_prop() if (symbolnode.classScope != ProtoCore.DSASM.Constants.kInvalidIndex && symbolnode.functionIndex == ProtoCore.DSASM.Constants.kGlobalScope && localProcedure != null) { string getterName = ProtoCore.DSASM.Constants.kGetterPrefix + t.Name; if (!string.Equals(localProcedure.name, getterName)) { var thisNode = nodeBuilder.BuildIdentfier(ProtoCore.DSDefinitions.Keyword.This); var identListNode = nodeBuilder.BuildIdentList(thisNode, t); EmitIdentifierListNode(identListNode, ref inferedType, false, graphNode, ProtoCore.DSASM.AssociativeSubCompilePass.kNone); if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } return; } } type = symbolnode.datatype; runtimeIndex = symbolnode.runtimeTableIndex; // The graph node always depends on this identifier if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } bool emitReplicationGuideFlag = emitReplicationGuide; emitReplicationGuide = false; if (null != t.ArrayDimensions) { dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions, graphNode, parentNode, subPass); } emitReplicationGuide = emitReplicationGuideFlag; //fix type's rank if (type.rank >= 0) { type.rank -= dimensions; if (type.rank < 0) { //throw new Exception("Exceed maximum rank!"); type.rank = 0; } } //check whether the value is an array if (type.rank == 0) { type.IsIndexable = false; } EmitPushVarData(runtimeIndex, dimensions); if (ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter == compileStateTracker.ExecMode) { EmitInstrConsole(ProtoCore.DSASM.kw.pushw, t.Value); EmitPushForSymbolW(symbolnode, t.line, t.col); } else { EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Value); EmitPushForSymbol(symbolnode, t); if (compileStateTracker.Options.TempReplicationGuideEmptyFlag && emitReplicationGuide) { int guides = EmitReplicationGuides(t.ReplicationGuides); EmitInstrConsole(ProtoCore.DSASM.kw.pushindex, guides + "[guide]"); EmitPushReplicationGuide(guides); } } if (ignoreRankCheck || compileStateTracker.TypeSystem.IsHigherRank(type.UID, inferedType.UID)) { inferedType = type; } // We need to get inferedType for boolean variable so that we can perform type check inferedType.UID = (isBooleanOp || (type.UID == (int)PrimitiveType.kTypeBool)) ? (int)PrimitiveType.kTypeBool : inferedType.UID; } }
private void EmitIdentifierNode(ImperativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null) { IdentifierNode t = node as IdentifierNode; if (t.Name.Equals(ProtoCore.DSDefinitions.Kw.kw_this)) { if (localProcedure != null) { if (localProcedure.isStatic) { string message = ProtoCore.BuildData.WarningMessage.kUsingThisInStaticFunction; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } else if (localProcedure.classScope == Constants.kGlobalScope) { string message = ProtoCore.BuildData.WarningMessage.kInvalidThis; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } else { EmitThisPointerNode(); return; } } else { string message = ProtoCore.BuildData.WarningMessage.kInvalidThis; compileStateTracker.BuildStatus.LogWarning(ProtoCore.BuildData.WarningID.kInvalidThis, message, compileStateTracker.CurrentDSFileName, t.line, t.col); EmitPushNull(); return; } } int dimensions = 0; int runtimeIndex = codeBlock.symbolTable.runtimeIndex; ProtoCore.Type type = new ProtoCore.Type(); type.UID = (int)ProtoCore.PrimitiveType.kTypeVoid; type.IsIndexable = false; ProtoCore.DSASM.SymbolNode symbolnode = null; //bool isAllocated = VerifyAllocation(t.Value, out blockId, out localAllocBlock, out symindex, ref type); //bool allocatedLocally = isAllocated && core.runtimeTableIndex == localAllocBlock; //bool allocatedExternally = isAllocated && core.runtimeTableIndex > localAllocBlock; //bool isVisible = isAllocated && core.runtimeTableIndex >= localAllocBlock; bool isAccessible = false; if (null == t.ArrayDimensions) { //check if it is a function instance ProtoCore.DSASM.ProcedureNode procNode = null; procNode = compileStateTracker.GetFirstVisibleProcedure(t.Name, null, codeBlock); if (null != procNode) { if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.procId) { // A global function inferedType.IsIndexable = false; inferedType.UID = (int)PrimitiveType.kTypeFunctionPointer; int fptr = compileStateTracker.FunctionPointerTable.functionPointerDictionary.Count; ProtoCore.DSASM.FunctionPointerNode fptrNode = new ProtoCore.DSASM.FunctionPointerNode(procNode.procId, procNode.runtimeIndex); compileStateTracker.FunctionPointerTable.functionPointerDictionary.TryAdd(fptr, fptrNode); compileStateTracker.FunctionPointerTable.functionPointerDictionary.TryGetBySecond(fptrNode, out fptr); EmitPushVarData(runtimeIndex, 0); EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Name); ProtoCore.DSASM.StackValue opFunctionPointer = new ProtoCore.DSASM.StackValue(); opFunctionPointer.optype = ProtoCore.DSASM.AddressType.FunctionPointer; opFunctionPointer.opdata = fptr; opFunctionPointer.opdata_d = fptr; EmitPush(opFunctionPointer, t.line, t.col); return; } } } bool isAllocated = VerifyAllocation(t.Value, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); if (!isAllocated || !isAccessible) { if (isAllocated) { if (!isAccessible) { string message = String.Format(ProtoCore.BuildData.WarningMessage.kPropertyIsInaccessible, t.Value); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kAccessViolation, message, compileStateTracker.CurrentDSFileName, t.line, t.col); } } else { string message = String.Format(ProtoCore.BuildData.WarningMessage.kUnboundIdentifierMsg, t.Value); buildStatus.LogWarning(ProtoCore.BuildData.WarningID.kIdUnboundIdentifier, message, compileStateTracker.CurrentDSFileName, t.line, t.col); } inferedType.UID = (int)ProtoCore.PrimitiveType.kTypeNull; // Jun Comment: Specification excerpt // If resolution fails at this point a com.Design-Script.Imperative.Core.UnboundIdentifier // warning is emitted during pre-execute phase, and at the ID is bound to null. (R1 - Feb) EmitPushNull(); EmitPushVarData(runtimeIndex, dimensions); ProtoCore.Type varType = compileStateTracker.TypeSystem.BuildTypeObject((int)PrimitiveType.kTypeVar, false, 0); symbolnode = Allocate(t.Value, globalProcIndex, varType); EmitInstrConsole(ProtoCore.DSASM.kw.pop, t.Value); EmitPopForSymbol(symbolnode); } else { type = symbolnode.datatype; runtimeIndex = symbolnode.runtimeTableIndex; if (compileStateTracker.Options.AssociativeToImperativePropagation) { // Comment Jun: If this symbol belongs to an outer block, then append it to this language blocks dependent if (symbolnode.codeBlockId != codeBlock.codeBlockId) { // A parent codeblock owns this symbol if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } } } } if (null != t.ArrayDimensions) { dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions); } //fix type's rank //fix type's rank if (type.rank >= 0) { type.rank -= dimensions; if (type.rank < 0) { //throw new Exception("Exceed maximum rank!"); type.rank = 0; } } //check whether the value is an array if (type.rank == 0) { type.IsIndexable = false; } EmitPushVarData(runtimeIndex, dimensions); EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Value); EmitPushForSymbol(symbolnode, t); if (compileStateTracker.TypeSystem.IsHigherRank(type.UID, inferedType.UID)) { inferedType = type; } // We need to get inferedType for boolean variable so that we can perform type check inferedType.UID = (isBooleanOp || (type.UID == (int)PrimitiveType.kTypeBool)) ? (int)PrimitiveType.kTypeBool : type.UID; }
private void EmitIdentifierNode(ImperativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null) { IdentifierNode t = node as IdentifierNode; if (t.Name.Equals(ProtoCore.DSDefinitions.Keyword.This)) { if (localProcedure != null) { if (localProcedure.IsStatic) { string message = ProtoCore.Properties.Resources.kUsingThisInStaticFunction; core.BuildStatus.LogWarning(WarningID.InvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode); EmitPushNull(); return; } else if (localProcedure.ClassID == Constants.kGlobalScope) { string message = ProtoCore.Properties.Resources.kInvalidThis; core.BuildStatus.LogWarning(WarningID.InvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode); EmitPushNull(); return; } else { EmitThisPointerNode(); return; } } else { string message = ProtoCore.Properties.Resources.kInvalidThis; core.BuildStatus.LogWarning(WarningID.InvalidThis, message, core.CurrentDSFileName, t.line, t.col, graphNode); EmitPushNull(); return; } } int dimensions = 0; int runtimeIndex = codeBlock.symbolTable.RuntimeIndex; ProtoCore.Type type = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.Var, 0); ProtoCore.DSASM.SymbolNode symbolnode = null; bool isAccessible = false; bool isAllocated = VerifyAllocation(t.Value, globalClassIndex, globalProcIndex, out symbolnode, out isAccessible); if (!isAllocated && null == t.ArrayDimensions) { //check if it is a function instance ProtoCore.DSASM.ProcedureNode procNode = null; procNode = CoreUtils.GetFunctionBySignature(t.Name, null, codeBlock); if (null != procNode) { if (ProtoCore.DSASM.Constants.kInvalidIndex != procNode.ID) { // A global function inferedType.UID = (int)PrimitiveType.FunctionPointer; int fptr = core.FunctionPointerTable.functionPointerDictionary.Count; var fptrNode = new ProtoCore.DSASM.FunctionPointerNode(procNode); core.FunctionPointerTable.functionPointerDictionary.TryAdd(fptr, fptrNode); core.FunctionPointerTable.functionPointerDictionary.TryGetBySecond(fptrNode, out fptr); EmitInstrConsole(ProtoCore.DSASM.kw.push, t.Name); StackValue opFunctionPointer = StackValue.BuildFunctionPointer(fptr); EmitPush(opFunctionPointer, runtimeIndex, t.line, t.col); return; } } } if (!isAllocated || !isAccessible) { if (isAllocated) { if (!isAccessible) { string message = String.Format(ProtoCore.Properties.Resources.kPropertyIsInaccessible, t.Value); buildStatus.LogWarning(WarningID.AccessViolation, message, core.CurrentDSFileName, t.line, t.col, graphNode); } } else { string message = String.Format(ProtoCore.Properties.Resources.kUnboundIdentifierMsg, t.Value); var unboundSymbol = new SymbolNode { name = t.Value }; buildStatus.LogUnboundVariableWarning(unboundSymbol, message, core.CurrentDSFileName, t.line, t.col, graphNode); } inferedType.UID = (int)ProtoCore.PrimitiveType.Null; // Jun Comment: Specification excerpt // If resolution fails at this point a com.Design-Script.Imperative.Core.UnboundIdentifier // warning is emitted during pre-execute phase, and at the ID is bound to null. (R1 - Feb) EmitPushNull(); ProtoCore.Type varType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.Var, 0); symbolnode = Allocate(t.Value, globalProcIndex, varType); EmitInstrConsole(kw.pop, t.Value); EmitPopForSymbol(symbolnode, runtimeIndex); } else { type = symbolnode.datatype; runtimeIndex = symbolnode.runtimeTableIndex; if (core.Options.AssociativeToImperativePropagation) { // Comment Jun: If this symbol belongs to an outer block, then append it to this language blocks dependent if (symbolnode.codeBlockId != codeBlock.codeBlockId) { // A parent codeblock owns this symbol if (null != graphNode) { ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode(); dependentNode.PushSymbolReference(symbolnode); graphNode.PushDependent(dependentNode); } } } } EmitInstrConsole(kw.push, t.Value); EmitPushForSymbol(symbolnode, runtimeIndex, t); if (null != t.ArrayDimensions) { dimensions = DfsEmitArrayIndexHeap(t.ArrayDimensions); } //fix type's rank //fix type's rank if (type.rank >= 0) { type.rank -= dimensions; if (type.rank < 0) { //throw new Exception("Exceed maximum rank!"); type.rank = 0; } } if (dimensions > 0) { EmitPushDimensions(dimensions); EmitLoadElement(symbolnode, runtimeIndex); } if (core.TypeSystem.IsHigherRank(type.UID, inferedType.UID)) { inferedType = type; } // We need to get inferedType for boolean variable so that we can perform type check inferedType.UID = (isBooleanOp || (type.UID == (int)PrimitiveType.Bool)) ? (int)PrimitiveType.Bool : type.UID; }