Code/Core/Contexts/ExecutionContext/ExecutionContext.Evaluate.cs
namespace Nodebox;
public partial class ExecutionContext {
public virtual EvaluateResult Evaluate() {
InvalidOperationException.ThrowIf(Graph == null, $"{nameof(Graph)} is not set");
var result = new EvaluateResult();
var subgraphs = Graph.ConnectedSubGraphs();
foreach (var graph in subgraphs) {
result.Register(EvaluateImpl(graph));
}
return result;
}
protected virtual EvaluateResult EvaluateImpl(Graph graph) {
var result = new EvaluateResult();
result.Register(Check(graph));
if (result.HasExceptions) {
return result;
}
try {
var toEvaluate = EvaluationTopologicalSort(graph);
foreach (var node in toEvaluate) {
Evaluate(node);
}
}
catch (Exception e) {
result.Register(e);
}
return result;
}
public virtual void Evaluate(Node node) {
var nodeType = node.GetType();
if (!Implementations.TryGetValue(nodeType, out var implentation)) {
throw new MissingImplementationException(node);
}
implentation.Evaluate(this, node);
foreach (var wireSet in node.OutputWires) {
foreach (var wire in wireSet) {
if (!Graph.Contains<Wire>(wire)) {
continue;
}
Store[wire.Destination].SetInput(wire.DestinationIndex, Store[wire.Source].GetOutput<object>(wire.SourceIndex));
}
}
}
[AttributeUsage(AttributeTargets.Class)]
public class ReaderAttribute : Attribute { }
public virtual bool IsReader(Node node) => TypeLibrary.GetType(node.GetType()).HasAttribute<ReaderAttribute>();
[AttributeUsage(AttributeTargets.Class)]
public class WriterAttribute : Attribute { }
public virtual bool IsWriter(Node node) => TypeLibrary.GetType(node.GetType()).HasAttribute<WriterAttribute>();
public virtual List<Node> EvaluationTopologicalSort(Graph graph) {
var list = new List<Node>();
var evaluatedNodes = new HashSet<Node>();
var queue = new Queue<Node>(graph.GetAll<Node>().Where(IsWriter));
while (queue.TryDequeue(out var node)) {
list.Add(node);
foreach (var wireSet in node.InputWires) {
foreach (var wire in wireSet) {
if (evaluatedNodes.Contains(wire.Source)) {
continue;
}
queue.Enqueue(wire.Source);
evaluatedNodes.Add(wire.Source);
}
}
}
list.Reverse();
return list;
}
public class EvaluateResult {
public bool HasExceptions => Exceptions.Count > 0;
public List<Exception> Exceptions { get; set; } = [];
public static EvaluateResult Error(IEnumerable<Exception> exceptions) => new() {
Exceptions = [.. exceptions]
};
public EvaluateResult Register(EvaluateResult other) {
Exceptions.AddRange(other.Exceptions);
return this;
}
public EvaluateResult Register(Exception exception) {
Exceptions.Add(exception);
return this;
}
public EvaluateResult Register(IEnumerable<Exception> exceptions) {
Exceptions.AddRange(exceptions);
return this;
}
}
}