static StackBaseModel FindConnectedStacksCommonDescendant(INodeModel statement, HashSet <IStackModel> visited) { var firstStack = GetConnectedStack((NodeModel)statement, 0); StackBaseModel desc = statement.OutputsByDisplayOrder.Aggregate(firstStack, (stack, nextPort) => { if (stack == null) { return(null); } if (nextPort.PortType != PortType.Execution) { return(firstStack); } var nextStack = GetConnectedStack(nextPort); if (nextStack == null) { return(null); } if (!visited.Add(nextStack)) { return(stack); } return(FindCommonDescendant(visited, stack, nextStack)); }); return(desc); }
// check if thisStack's descendants have been already visited and put in otherBranchSet // otherwise add them static bool Test(ref StackBaseModel thisStack, HashSet <StackBaseModel> thisBranchSet, HashSet <StackBaseModel> otherBranchSet, Queue <StackBaseModel> thisBranchQueue) { if (thisStack == null) { return(false); } StackBaseModel connectedStack = FindConnectedStacksCommonDescendant(thisStack); if (!connectedStack) { return(false); } Assert.IsTrue(connectedStack.InputPorts.Count > 0, "a connected stack must have inputs"); // small optimization: no common descendant can have less than 2 input connections if (connectedStack.InputPorts.Sum(c => c.ConnectionPortModels.Count()) >= 2 && otherBranchSet.Contains(connectedStack)) { thisStack = connectedStack; return(true); } if (thisBranchSet.Add(connectedStack)) { thisBranchQueue.Enqueue(connectedStack); } return(false); }
void CreateStackAndLogs(out StackBaseModel stack, out FunctionCallNodeModel[] log, int logCount = 1) { stack = GraphModel.CreateFunction("F", Vector2.zero); log = new FunctionCallNodeModel[logCount]; for (int i = 0; i < logCount; i++) { log[i] = stack.CreateFunctionCallNode(k_LogMethodInfo); } }
// This will find a common descendant stack for both inputs // ie. FindCommonDescendant(A, B) => E // Note: if c wasn't connected to E, A and B would not have a common descendant, // as no descendant of B would be reachable from C // Root // / \ // A B // / \ | // C D | // \__\ / // E // we need to keep two sets/queues, one per initial branch // another solution would be to keep an Ancestor hashset associated to each stack model // and find a non empty union public static StackBaseModel FindCommonDescendant(IStackModel root, StackBaseModel a, StackBaseModel b) { var stackModels = new HashSet <IStackModel>(); if (root != a && root != b) { stackModels.Add(root); } return(FindCommonDescendant(stackModels, a, b)); }
void CreateIfThenElseStacks(StackBaseModel ifStack, string thenName, string elseName, out StackBaseModel thenStack, out StackBaseModel elseStack) { var ifNode = ifStack.CreateStackedNode <IfConditionNodeModel>("if"); thenStack = GraphModel.CreateStack(thenName, Vector2.left); GraphModel.CreateEdge(thenStack.InputPorts[0], ifNode.ThenPort); elseStack = GraphModel.CreateStack(elseName, Vector2.right); GraphModel.CreateEdge(elseStack.InputPorts[0], ifNode.ElsePort); }
IfConditionNodeModel CreateIfThenElseStacks(StackBaseModel ifStack, out StackBaseModel thenStack, out StackBaseModel elseStack) { var ifNode = ifStack.CreateStackedNode <IfConditionNodeModel>("if"); thenStack = GraphModel.CreateStack("then", Vector2.left); GraphModel.CreateEdge(thenStack.InputPorts[0], ifNode.ThenPort); elseStack = GraphModel.CreateStack("else", Vector2.right); GraphModel.CreateEdge(elseStack.InputPorts[0], ifNode.ElsePort); return(ifNode); }
public static StackBaseModel FindConnectedStacksCommonDescendant(INodeModel statement) { var firstStack = GetConnectedStack((NodeModel)statement, 0); StackBaseModel desc = statement.OutputsByDisplayOrder.Aggregate(firstStack, (stack, nextPort) => { if (nextPort.PortType != PortType.Execution) { return(firstStack); } return(FindCommonDescendant(stack, GetConnectedStack(nextPort))); }); return(desc); }
// This will find a common descendant stack for both inputs // ie. FindCommonDescendant(A, B) => E // Note: if c wasn't connected to E, A and B would not have a common descendant, // as no descendant of B would be reachable from C // Root // / \ // A B // / \ | // C D | // \__\ / // E // we need to keep two sets/queues, one per initial branch // another solution would be to keep an Ancestor hashset associated to each stack model // and find a non empty union public static StackBaseModel FindCommonDescendant(StackBaseModel a, StackBaseModel b) { if (a == b) // FCD(a, a) = a { return(a); } if (a == null || b == null) // FCD(x, null) = null { return(null); } HashSet <StackBaseModel> aSet = new HashSet <StackBaseModel>(); aSet.Add(a); Queue <StackBaseModel> aQueue = new Queue <StackBaseModel>(); aQueue.Enqueue(a); HashSet <StackBaseModel> bSet = new HashSet <StackBaseModel>(); bSet.Add(b); Queue <StackBaseModel> bQueue = new Queue <StackBaseModel>(); bQueue.Enqueue(b); while (aQueue.Count > 0 || bQueue.Count > 0) { if (aQueue.Count > 0) { a = aQueue.Dequeue(); } if (bQueue.Count > 0) { b = bQueue.Dequeue(); } if (Test(ref a, aSet, bSet, aQueue)) { return(a); } if (Test(ref b, bSet, aSet, bQueue)) { return(b); } } return(null); }
public static FunctionCallNodeModel CreateFunctionCallNode(this StackBaseModel stackModel, MethodInfo methodInfo, int index = -1, SpawnFlags spawnFlags = SpawnFlags.Default) { return(CreateStackedNode <FunctionCallNodeModel>(stackModel, methodInfo.Name, index, spawnFlags, n => n.MethodInfo = methodInfo)); }
public abstract LoopNodeModel CreateLoopNode(StackBaseModel hostStack, int index, SpawnFlags spawnFlags = SpawnFlags.Default);
public static IGraphElement CreateStack(this ElementBuilder elementBuilder, IStore store, StackBaseModel model) { var ui = new StackNode(); ui.Setup(model, store, elementBuilder.GraphView); return(ui); }
public InsideStackConstraint(IStackModel expected) : base(expected) { m_ExpectedStack = (StackBaseModel)expected; }
public static UnaryOperatorNodeModel CreateUnaryStatementNode(this StackBaseModel stackModel, UnaryOperatorKind kind, int index, SpawnFlags spawnFlags = SpawnFlags.Default) { return(CreateStackedNode <UnaryOperatorNodeModel>(stackModel, kind.ToString(), index, spawnFlags, n => n.kind = kind)); }
public static GraphElement CreateStack(this INodeBuilder builder, Store store, StackBaseModel model) { return(new StackNode(store, model, builder)); }
public void DuplicateStackedNodes(INodeModel copiedNode, Dictionary <INodeModel, NodeModel> mapping, Vector2 delta, int stackInsertionIndex, List <StackedNodesStruct> implicitStackedNodes, StackBaseModel pastedStackModel) { pastedStackModel.ClearNodes(); if (implicitStackedNodes?.Count > 0) { foreach (var stackedNodeStruct in implicitStackedNodes) { DuplicateNode(stackedNodeStruct.stackedNodeModel, mapping, pastedStackModel, delta, stackInsertionIndex != -1 ? stackInsertionIndex++ : -1); } } }
public override LoopNodeModel CreateLoopNode(StackBaseModel hostStack, int index, SpawnFlags spawnFlags = SpawnFlags.Default) { return(hostStack.CreateStackedNode <WhileNodeModel>(Title, index, spawnFlags)); }
public static FunctionRefCallNodeModel CreateFunctionRefCallNode(this StackBaseModel stackModel, FunctionModel methodInfo, int index = -1, SpawnFlags spawnFlags = SpawnFlags.Default) { return(stackModel.CreateStackedNode <FunctionRefCallNodeModel>(methodInfo.Title, index, spawnFlags, n => n.Function = methodInfo)); }
static T CreateStackedNode <T>(this StackBaseModel stackModel, string nodeName, int index, SpawnFlags spawnFlags = SpawnFlags.Default, Action <T> setup = null) where T : NodeModel { return(stackModel.CreateStackedNode(nodeName, index, spawnFlags, setup)); }
static INodeModel CreateStackedNode(this StackBaseModel stackModel, Type type, string nodeName, int index, SpawnFlags spawnFlags = SpawnFlags.Default, Action <NodeModel> setup = null) { return(stackModel.CreateStackedNode(type, nodeName, index, spawnFlags, setup)); }
public static SetPropertyGroupNodeModel CreateSetPropertyGroupNode(this StackBaseModel stackModel, int index) { var nodeModel = stackModel.CreateStackedNode <SetPropertyGroupNodeModel>("Set Property", index); return(nodeModel); }
public NodeModel DuplicateNode(INodeModel copiedNode, Dictionary <INodeModel, NodeModel> mapping, StackBaseModel pastedNodeParentStack, Vector2 delta, int stackInsertionIndex, List <StackedNodesStruct> implicitStackedNodes = null) { var pastedNodeModel = (NodeModel)copiedNode.Clone(); // Set graphmodel BEFORE define node as it is commonly use during Define pastedNodeModel.AssetModel = AssetModel; pastedNodeModel.Title = copiedNode.Title; pastedNodeModel.AssignNewGuid(); pastedNodeModel.DefineNode(); pastedNodeModel.ReinstantiateInputConstants(); mapping.Add(copiedNode, pastedNodeModel); if (pastedNodeParentStack != null) { pastedNodeParentStack.AddStackedNode(pastedNodeModel, stackInsertionIndex); } else { AddNode(pastedNodeModel); pastedNodeModel.Position += delta; if (pastedNodeModel is StackBaseModel pastedStackModel) { DuplicateStackedNodes(copiedNode, mapping, delta, stackInsertionIndex, implicitStackedNodes, pastedStackModel); } } return(pastedNodeModel); }
protected void JoinStacks(StackBaseModel a, StackBaseModel b, string newStackName, out StackBaseModel newJoinStack) { newJoinStack = GraphModel.CreateStack(newStackName, Vector2.zero); GraphModel.CreateEdge(newJoinStack.InputPorts[0], a.OutputPorts[0]); GraphModel.CreateEdge(newJoinStack.InputPorts[0], b.OutputPorts[0]); }
public virtual void BuildStack(IStackModel stack, ref BlockSyntax blockNode, StackExitStrategy exitStrategy = StackExitStrategy.Return) { if (stack == null || stack.State == ModelState.Disabled) { return; } RegisterBuiltStack(stack); // JUST in case... until we validate the previous failsafe if (m_BuiltStackCounter++ > 10000) { throw new InvalidOperationException("Infinite loop while building the script, aborting"); } StackExitStrategy origStackExitStrategy = m_StackExitStrategy; if (exitStrategy != StackExitStrategy.Inherit) { m_StackExitStrategy = exitStrategy; } // Debug.Log($"Build stack {stack}"); // m_EndStack might get changed by recursive BuildNode() calls StackBaseModel origEndStack = EndStack; var statements = new List <StatementSyntax>(); foreach (var statement in stack.NodeModels) { if (statement.State == ModelState.Disabled) { continue; } var syntaxNodes = BuildNode(statement); foreach (var syntaxNode in syntaxNodes) { switch (syntaxNode) { case StatementSyntax statementNode: statements.Add(statementNode); break; case ExpressionSyntax expressionNode: statements.Add(ExpressionStatement(expressionNode) .WithAdditionalAnnotations(new SyntaxAnnotation(Annotations.AnnotationKind, statement.Guid.ToString())) ); break; default: throw new InvalidOperationException($"Expected a statement or expression node, found a {syntaxNode.GetType()} when building {statement}"); } } } blockNode = blockNode.AddStatements(statements.ToArray()); if (stack.DelegatesOutputsToNode(out _)) { var nextStack = EndStack; m_StackExitStrategy = origStackExitStrategy; // Debug.Log($"Stack {stack} delegates ports. nextStack {nextStack} origEndStack {origEndStack}"); // if a nested node changed the end stack, but found the same common descendant, // let the parent call handle it if (EndStack == origEndStack) { return; } EndStack = origEndStack; BuildStack(nextStack, ref blockNode, exitStrategy); return; } bool anyConnection = false; foreach (var outputPort in stack.OutputPorts) { foreach (var connectedStack in outputPort.ConnectionPortModels) { if (connectedStack.NodeModel is IStackModel nextStack) { anyConnection = true; if (!ReferenceEquals(nextStack, EndStack)) { BuildStack(nextStack, ref blockNode, StackExitStrategy.Inherit); } } } } // TODO use function default return value StatementSyntax lastStatementSyntax = blockNode.Statements.LastOrDefault(); if (!anyConnection && !(lastStatementSyntax is ReturnStatementSyntax) && !(lastStatementSyntax is ContinueStatementSyntax)) { //TODO we had that for a reason // lastStatementSyntax = StatementFromExitStrategy(m_StackExitStrategy, null); // if(lastStatementSyntax != null) // blockNode = blockNode.AddStatements(lastStatementSyntax); } m_StackExitStrategy = origStackExitStrategy; }
public ConnectedToStackConstraint(IStackModel expected) : base(expected) { m_ExpectedStack = (StackBaseModel)expected; }
public LoopNodeModel CreateLoopNode(StackBaseModel hostStack, int index, SpawnFlags spawnFlags = SpawnFlags.Default, Action <NodeModel> setup = null, GUID?guid = null) { return((LoopNodeModel)hostStack.CreateStackedNode( MatchingStackedNodeType, Title, index, spawnFlags, setup, guid)); }
public IndexInStackConstraint(int expectedIndex, IStackModel expectedStack) : base(expectedIndex, expectedStack) { m_ExpectedIndex = expectedIndex; m_ExpectedStack = (StackBaseModel)expectedStack; }
public virtual void BuildStack(IStackModel stack, ref BlockSyntax blockNode, StackExitStrategy exitStrategy = StackExitStrategy.Return) { if (stack == null || stack.State == ModelState.Disabled) { return; } RegisterBuiltStack(stack); // JUST in case... until we validate the previous failsafe if (m_BuiltStackCounter++ > 10000) { throw new InvalidOperationException("Infinite loop while building the script, aborting"); } StackExitStrategy origStackExitStrategy = m_StackExitStrategy; if (exitStrategy != StackExitStrategy.Inherit) { m_StackExitStrategy = exitStrategy; } // Debug.Log($"Build stack {stack}"); // m_EndStack might get changed by recursive BuildNode() calls StackBaseModel origEndStack = EndStack; var statements = new List <StatementSyntax>(); foreach (var statement in stack.NodeModels) { if (statement.State == ModelState.Disabled) { continue; } var syntaxNodes = BuildNode(statement); foreach (var syntaxNode in syntaxNodes) { StatementSyntax resultingStatement; switch (syntaxNode) { case StatementSyntax statementNode: resultingStatement = statementNode; break; case ExpressionSyntax expressionNode: resultingStatement = ExpressionStatement(expressionNode); break; default: throw new InvalidOperationException($"Expected a statement or expression node, found a {syntaxNode.GetType()} when building {statement}"); } // TODO: RecordValue codegen counter instead of counting them after the fact if ((Options & UnityEngine.Modifier.VisualScripting.CompilationOptions.Tracing) != 0) { var recordValueCount = syntaxNode.GetAnnotations(Annotations.RecordValueCountKind).FirstOrDefault(); int recordedValuesCount = recordValueCount == null ? syntaxNode.GetAnnotatedNodes(Annotations.RecordValueKind).Count() : int.Parse(recordValueCount.Data); statements.Add(InstrumentForInEditorDebugging.BuildLastCallFrameExpression(recordedValuesCount, statement.Guid, this.GetRecorderName())); } statements.Add(resultingStatement); } } blockNode = blockNode.AddStatements(statements.ToArray()); if (stack.DelegatesOutputsToNode(out _)) { var nextStack = EndStack; m_StackExitStrategy = origStackExitStrategy; // Debug.Log($"Stack {stack} delegates ports. nextStack {nextStack} origEndStack {origEndStack}"); // if a nested node changed the end stack, but found the same common descendant, // let the parent call handle it if (EndStack == origEndStack) { return; } EndStack = origEndStack; BuildStack(nextStack, ref blockNode, exitStrategy); return; } bool anyConnection = false; foreach (var outputPort in stack.OutputPorts) { foreach (var connectedStack in outputPort.ConnectionPortModels) { if (connectedStack.NodeModel is IStackModel nextStack) { anyConnection = true; if (!ReferenceEquals(nextStack, EndStack)) { BuildStack(nextStack, ref blockNode, StackExitStrategy.Inherit); } } } } // TODO use function default return value StatementSyntax lastStatementSyntax = blockNode.Statements.LastOrDefault(); if (!anyConnection && !(lastStatementSyntax is ReturnStatementSyntax) && !(lastStatementSyntax is ContinueStatementSyntax)) { //TODO we had that for a reason // lastStatementSyntax = StatementFromExitStrategy(m_StackExitStrategy, null); // if(lastStatementSyntax != null) // blockNode = blockNode.AddStatements(lastStatementSyntax); } m_StackExitStrategy = origStackExitStrategy; }
public void DuplicateStackedNodes(INodeModel copiedNode, Dictionary <INodeModel, NodeModel> mapping, Vector2 delta, int stackInsertionIndex, List <StackedNodesStruct> implicitStackedNodes, StackBaseModel pastedStackModel) { pastedStackModel.ClearNodes(); if (implicitStackedNodes?.Count > 0) { foreach (var stackedNodeStruct in implicitStackedNodes) { DuplicateNode(stackedNodeStruct.stackedNodeModel, mapping, pastedStackModel, delta, stackInsertionIndex != -1 ? stackInsertionIndex++ : -1); } } if (copiedNode is FunctionModel copiedFunctionModel && pastedStackModel is FunctionModel pastedFunctionModel) { pastedFunctionModel.ClearVariableDeclarations(); foreach (IVariableDeclarationModel functionVariableModel in copiedFunctionModel.FunctionVariableModels) { VariableDeclarationModel variableDeclaration = ((VariableDeclarationModel)functionVariableModel).Clone(); // Reset name to be the exact same as the original since they are in different scopes variableDeclaration.Name = functionVariableModel.Name; variableDeclaration.Owner = pastedFunctionModel; pastedFunctionModel.VariableDeclarations.Add(variableDeclaration); } pastedFunctionModel.ClearParameterDeclarations(); foreach (IVariableDeclarationModel functionParameterModel in copiedFunctionModel.FunctionParameterModels) { VariableDeclarationModel parameterDeclaration = ((VariableDeclarationModel)functionParameterModel).Clone(); // Reset name to be the exact same as the original since they are in different scopes parameterDeclaration.Name = functionParameterModel.Name; parameterDeclaration.Owner = pastedFunctionModel; pastedFunctionModel.FunctionParameters.Add(parameterDeclaration); } } }