|
@@ -17,11 +17,13 @@ namespace NTERA.Engine.Runtime
|
|
|
public IConsole Console { get; protected set; }
|
|
|
|
|
|
public Stack<StackFrame> ExecutionStack { get; } = new Stack<StackFrame>();
|
|
|
+ public Stack<ExecutionResult> ExecutionResultStack { get; } = new Stack<ExecutionResult>();
|
|
|
|
|
|
- public List<FunctionDefinition> TotalProcedureDefinitions { get; set; } = new List<FunctionDefinition>(BaseDefinitions.DefaultGlobalFunctions);
|
|
|
- public Dictionary<string, Variable> GlobalVariables { get; set; } = new Dictionary<string, Variable>();
|
|
|
+ public List<FunctionDefinition> TotalProcedureDefinitions { get; } = new List<FunctionDefinition>(BaseDefinitions.DefaultGlobalFunctions);
|
|
|
+ public Dictionary<string, Variable> GlobalVariables { get; } = new Dictionary<string, Variable>();
|
|
|
|
|
|
- public Value LastInputValue { get; set; }
|
|
|
+
|
|
|
+ public Value LastInputValue { get; protected set; }
|
|
|
public AutoResetEvent InputResetEvent { get; } = new AutoResetEvent(false);
|
|
|
|
|
|
public EraRuntime(IExecutionProvider executionProvider)
|
|
@@ -33,8 +35,10 @@ namespace NTERA.Engine.Runtime
|
|
|
|
|
|
foreach (var variable in BaseDefinitions.DefaultGlobalVariables)
|
|
|
{
|
|
|
- var globalVariable = new Variable(variable.Name, variable.ValueType);
|
|
|
- globalVariable[0] = variable.CalculatedValue;
|
|
|
+ var globalVariable = new Variable(variable.Name, variable.ValueType)
|
|
|
+ {
|
|
|
+ [0] = variable.CalculatedValue
|
|
|
+ };
|
|
|
|
|
|
GlobalVariables.Add(variable.Name, globalVariable);
|
|
|
}
|
|
@@ -54,6 +58,11 @@ namespace NTERA.Engine.Runtime
|
|
|
try
|
|
|
{
|
|
|
Call(ExecutionProvider.DefinedProcedures.First(x => x.Name == "SYSTEM_TITLE"));
|
|
|
+
|
|
|
+ while (ExecutionStack.Count > 0)
|
|
|
+ {
|
|
|
+ ExecuteSet();
|
|
|
+ }
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
@@ -69,7 +78,7 @@ namespace NTERA.Engine.Runtime
|
|
|
Thread.Sleep(-1);
|
|
|
}
|
|
|
|
|
|
- public ExecutionResult Call(FunctionDefinition function, IList<Parameter> parameters = null)
|
|
|
+ public void Call(FunctionDefinition function, IList<Parameter> parameters = null)
|
|
|
{
|
|
|
var localVariables = new Dictionary<string, Variable>();
|
|
|
|
|
@@ -94,15 +103,11 @@ namespace NTERA.Engine.Runtime
|
|
|
Variables = localVariables
|
|
|
};
|
|
|
|
|
|
- ExecutionResult result;
|
|
|
-
|
|
|
- ExecutionStack.Push(newContext);
|
|
|
-
|
|
|
if (function.Filename == "__GLOBAL")
|
|
|
{
|
|
|
var resultValue = Functions.StaticFunctions[function.Name].Invoke(this, newContext, parameters);
|
|
|
|
|
|
- result = new ExecutionResult(ExecutionResultType.FunctionReturn, resultValue);
|
|
|
+ ExecutionResultStack.Push(new ExecutionResult(ExecutionResultType.FunctionReturn, resultValue));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -137,49 +142,56 @@ namespace NTERA.Engine.Runtime
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- var executionContents = ExecutionProvider.GetExecutionNodes(function);
|
|
|
-
|
|
|
- result = ExecuteSet(newContext, executionContents.ToList());
|
|
|
- }
|
|
|
|
|
|
- ExecutionStack.Pop();
|
|
|
+ newContext.ExecutionNodes = ExecutionProvider.GetExecutionNodes(function).ToList();
|
|
|
|
|
|
- return result;
|
|
|
+ ExecutionStack.Push(newContext);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- public ExecutionResult ExecuteSet(StackFrame context, IList<ExecutionNode> nodes)
|
|
|
+ public void ExecuteSet()
|
|
|
{
|
|
|
- for (int index = 0; index < nodes.Count; index++)
|
|
|
+ var context = ExecutionStack.Peek();
|
|
|
+
|
|
|
+ if (context.ExecutionIndex >= context.ExecutionNodes.Count)
|
|
|
{
|
|
|
- ExecutionNode node = nodes[index];
|
|
|
-
|
|
|
- if (node.Type == "for")
|
|
|
- {
|
|
|
- ExecutionNode forContext = node[0];
|
|
|
+ ExecutionStack.Pop();
|
|
|
|
|
|
- var iterationVariable = ComputeVariable(context, forContext[0], out var iterationIndex);
|
|
|
+ if (!context.IsAnonymous && context.SelfDefinition.IsReturnFunction)
|
|
|
+ throw new EraRuntimeException("Function did not return a value");
|
|
|
|
|
|
- var beginNumber = ComputeExpression(context, forContext[1]);
|
|
|
- var endNumber = ComputeExpression(context, forContext[2]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- for (iterationVariable[iterationIndex] = beginNumber.Real; iterationVariable[iterationIndex].Real < endNumber.Real; iterationVariable[iterationIndex]++)
|
|
|
- {
|
|
|
- var subset = node.Skip(1).ToList();
|
|
|
- ExecuteSet(context, subset);
|
|
|
- }
|
|
|
+ ExecutionNode node = context.ExecutionNodes[context.ExecutionIndex++];
|
|
|
+
|
|
|
+ if (node.Type == "for")
|
|
|
+ {
|
|
|
+ ExecutionNode forContext = node[0];
|
|
|
|
|
|
- continue;
|
|
|
- }
|
|
|
+ var iterationVariable = ComputeVariable(context, forContext[0], out var iterationIndex);
|
|
|
|
|
|
- if (node.Type == "result")
|
|
|
+ var beginNumber = ComputeExpression(context, forContext[1]);
|
|
|
+ var endNumber = ComputeExpression(context, forContext[2]);
|
|
|
+
|
|
|
+ for (iterationVariable[iterationIndex] = beginNumber.Real; iterationVariable[iterationIndex].Real < endNumber.Real; iterationVariable[iterationIndex]++)
|
|
|
{
|
|
|
- return new ExecutionResult(ExecutionResultType.FunctionReturn, ComputeExpression(context, node.Single()));
|
|
|
+ var subset = node.Skip(1).ToList();
|
|
|
+
|
|
|
+ ExecutionStack.Push(context.Clone(subset));
|
|
|
}
|
|
|
|
|
|
- ExecuteNode(context, node);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node.Type == "result")
|
|
|
+ {
|
|
|
+ ExecutionResultStack.Push(new ExecutionResult(ExecutionResultType.FunctionReturn, ComputeExpression(context, node.Single())));
|
|
|
+
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- return ExecutionResult.None;
|
|
|
+ ExecuteNode(context, node);
|
|
|
}
|
|
|
|
|
|
public void ExecuteNode(StackFrame context, ExecutionNode node)
|
|
@@ -210,10 +222,7 @@ namespace NTERA.Engine.Runtime
|
|
|
if (procedure == null)
|
|
|
throw new EraRuntimeException($"Unknown procedure: '{procedureName}'");
|
|
|
|
|
|
- var executionResult = Call(procedure, node.GetSubtype("parameters").Select(x => ComputeParameter(context, x)).ToArray());
|
|
|
-
|
|
|
- if (executionResult.Type != ExecutionResultType.None || executionResult.Result.HasValue)
|
|
|
- throw new EraRuntimeException($"Unexpected result from procedure '{procedureName}': {executionResult.Type}");
|
|
|
+ Call(procedure, node.GetSubtype("parameters").Select(x => ComputeParameter(context, x)).ToArray());
|
|
|
|
|
|
return;
|
|
|
|
|
@@ -283,7 +292,14 @@ namespace NTERA.Engine.Runtime
|
|
|
if (function == null)
|
|
|
throw new EraRuntimeException($"Unknown function: '{functionName}'");
|
|
|
|
|
|
- var executionResult = Call(function, expressionNode.GetSubtype("parameters").Select(x => ComputeParameter(context, x)).ToArray());
|
|
|
+ int currentStackLevel = ExecutionStack.Count;
|
|
|
+
|
|
|
+ Call(function, expressionNode.GetSubtype("parameters").Select(x => ComputeParameter(context, x)).ToArray());
|
|
|
+
|
|
|
+ while (ExecutionStack.Count > currentStackLevel)
|
|
|
+ ExecuteSet();
|
|
|
+
|
|
|
+ var executionResult = ExecutionResultStack.Pop();
|
|
|
|
|
|
if (executionResult.Type != ExecutionResultType.FunctionReturn || !executionResult.Result.HasValue)
|
|
|
throw new EraRuntimeException($"Unexpected result from function '{functionName}': {executionResult.Type}");
|