diff --git a/src/Engine/ProtoAssociative/CodeGen.cs b/src/Engine/ProtoAssociative/CodeGen.cs index 051db64648a..527f9270469 100644 --- a/src/Engine/ProtoAssociative/CodeGen.cs +++ b/src/Engine/ProtoAssociative/CodeGen.cs @@ -2156,7 +2156,8 @@ public override int Emit(ProtoCore.AST.Node codeBlockNode, ProtoCore.Associative hasReturnStatement = EmitCodeBlock(codeblock.Body, ref inferedType, ProtoCore.CompilerDefinitions.SubCompilePass.UnboundIdentifier, false); if (compilePass == ProtoCore.CompilerDefinitions.CompilePass.GlobalScope && !hasReturnStatement) { - EmitReturnNull(); + var guidList = codeblock.Body.Select(x=> (x as BinaryExpressionNode)?.guid).Where(x=>x!=null).ToList(); + EmitReturnNull(guidList.Any() ? guidList.Last() : null); } compilePass++; @@ -5909,7 +5910,7 @@ private void EmitGroupExpressionNode(AssociativeNode node, ref ProtoCore.Type in } } - protected override void EmitReturnNull() + protected override void EmitReturnNull(Guid? guid) { int startpc = pc; @@ -5928,9 +5929,17 @@ protected override void EmitReturnNull() retNode.updateBlock.startpc = startpc; retNode.updateBlock.endpc = pc - 1; retNode.isReturn = true; + if (guid != null) + { + retNode.guid = (Guid)guid; + } PushGraphNode(retNode); } + protected override void EmitReturnNull() + { + EmitReturnNull(null); + } private ProtoCore.Type BuildArgumentTypeFromVarDeclNode(VarDeclNode argNode, GraphNode graphNode = null) { @@ -6130,4 +6139,4 @@ protected override void DfsTraverse(ProtoCore.AST.Node pNode, ref ProtoCore.Type int blockId = codeBlock.codeBlockId; } } -} \ No newline at end of file +} diff --git a/src/Engine/ProtoCore/AssociativeGraph.cs b/src/Engine/ProtoCore/AssociativeGraph.cs index f18433e6565..201ec7698ca 100644 --- a/src/Engine/ProtoCore/AssociativeGraph.cs +++ b/src/Engine/ProtoCore/AssociativeGraph.cs @@ -57,7 +57,12 @@ public static void BuildGraphNodeDependencies(List g { return; } - + for (int i = 0; i < graphNodesInScope.Count; ++i) + { + AssociativeGraph.GraphNode currentNode = graphNodesInScope[i]; + currentNode.ParentNodes.Clear(); + currentNode.ChildrenNodes.Clear(); + } // Get the current graphnode to check against the list // [a = 10] -> this one // c = 1 @@ -967,33 +972,31 @@ internal IEnumerable ClearCycles(IEnumerable graphNodes) Stack stack = new Stack(); stack.Push(this); - var visited = graphNodes.ToDictionary(node => node, node => false); + var visited = new HashSet(); - var guids = new List(); + var guids = new HashSet(); while(stack.Any()) { var node = stack.Pop(); - if (!visited[node]) + if (visited.Add(node.UID)) { guids.Add(node.guid); if (node.isCyclic) { node.isCyclic = false; node.isActive = true; - } - visited[node] = true; } foreach(var cNode in node.ChildrenNodes) { - if (!visited[cNode]) + if (!visited.Contains(cNode.UID)) { stack.Push(cNode); } } } - return guids; + return guids.ToList(); } public void PushDependent(GraphNode dependent) diff --git a/src/Engine/ProtoCore/CodeGen.cs b/src/Engine/ProtoCore/CodeGen.cs index 860633c92a3..cd23f495027 100644 --- a/src/Engine/ProtoCore/CodeGen.cs +++ b/src/Engine/ProtoCore/CodeGen.cs @@ -2363,6 +2363,7 @@ protected bool InsideFunction() // used to manully emit "return = null" instruction if a function or language block does not have a return statement // there is update code involved in associativen code gen, so it is not implemented here + protected abstract void EmitReturnNull(Guid? guid); protected abstract void EmitReturnNull(); protected abstract void DfsTraverse(Node node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, diff --git a/src/Engine/ProtoImperative/CodeGen.cs b/src/Engine/ProtoImperative/CodeGen.cs index 769e61cb03e..bed77a09d3a 100644 --- a/src/Engine/ProtoImperative/CodeGen.cs +++ b/src/Engine/ProtoImperative/CodeGen.cs @@ -2543,12 +2543,17 @@ private void EmitSetExpressionUID(int exprId) //AppendInstruction(instr); } - protected override void EmitReturnNull() + protected override void EmitReturnNull(Guid? guid = null) { EmitPushNull(); EmitReturnToRegister(); } + protected override void EmitReturnNull() + { + EmitReturnNull(null); + } + protected void EmitGropuExpressionNode(ImperativeNode node, ref ProtoCore.Type inferedType) { GroupExpressionNode group = node as GroupExpressionNode; diff --git a/src/Engine/ProtoScript/Runners/LiveRunner.cs b/src/Engine/ProtoScript/Runners/LiveRunner.cs index a4908a75044..c988b5553c1 100644 --- a/src/Engine/ProtoScript/Runners/LiveRunner.cs +++ b/src/Engine/ProtoScript/Runners/LiveRunner.cs @@ -1709,6 +1709,13 @@ private void SynchronizeInternal(GraphSyncData syncData) // Get AST list that need to be executed var finalDeltaAstList = changeSetComputer.GetDeltaASTList(syncData); + //nodes which will be defined or redefined after compilation and execution + var pendingUIDsForDeletion = changeSetComputer.csData.DeletedBinaryExprASTNodes + .Select(x => (x as BinaryExpressionNode)?.guid) + .Where(x => x != null) + .Select(x => x.Value) + .ToHashSet(); + // Prior to execution, apply state modifications to the VM given the delta AST's bool anyForcedExecutedNodes = changeSetComputer.csData.ForceExecuteASTList.Any(); changeSetApplier.Apply(runnerCore, runtimeCore, changeSetComputer.csData); @@ -1721,6 +1728,14 @@ private void SynchronizeInternal(GraphSyncData syncData) var guids = runtimeCore.ExecutedAstGuids.ToList(); executedAstGuids[syncData.SessionID] = guids; runtimeCore.RemoveExecutedAstGuids(); + + // There should be a CodeBlock in CodeBlockList by now + if (runnerCore.CodeBlockList.Any()) + { + var nodes = runnerCore.CodeBlockList[(int)Language.Associative].instrStream.dependencyGraph.GetGraphNodesAtScope(Constants.kInvalidPC, Constants.kInvalidPC); + //delete all nodes which were redefined. For those nodes that were defined for the first time, this will be a no-op + nodes.RemoveAll(x=>!x.isActive || pendingUIDsForDeletion.Contains(x.guid)); + } } }