|
@@ -16,7 +16,9 @@ namespace NTERA.Engine.Runtime
|
|
|
|
|
|
public Stack<StackFrame> ExecutionStack { get; } = new Stack<StackFrame>();
|
|
|
|
|
|
- protected List<FunctionDefinition> TotalProcedureDefinitions = new List<FunctionDefinition>(BaseDefinitions.DefaultGlobalFunctions);
|
|
|
+ public List<FunctionDefinition> TotalProcedureDefinitions { get; set; } = new List<FunctionDefinition>(BaseDefinitions.DefaultGlobalFunctions);
|
|
|
+ public Dictionary<string, Variable> GlobalVariables { get; set; } = new Dictionary<string, Variable>();
|
|
|
+ public Dictionary<string, Variable> SemiGlobalVariables { get; set; } = new Dictionary<string, Variable>();
|
|
|
|
|
|
public EraRuntime(IExecutionProvider executionProvider)
|
|
|
{
|
|
@@ -24,6 +26,14 @@ namespace NTERA.Engine.Runtime
|
|
|
|
|
|
TotalProcedureDefinitions.AddRange(ExecutionProvider.DefinedProcedures);
|
|
|
TotalProcedureDefinitions.AddRange(BaseDefinitions.DefaultGlobalFunctions);
|
|
|
+
|
|
|
+ foreach (var variable in BaseDefinitions.DefaultGlobalVariables)
|
|
|
+ {
|
|
|
+ var globalVariable = new Variable(variable.Name, variable.ValueType);
|
|
|
+ globalVariable[0] = variable.CalculatedValue;
|
|
|
+
|
|
|
+ GlobalVariables.Add(variable.Name, globalVariable);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public bool Initialize(IConsole console)
|
|
@@ -55,10 +65,9 @@ namespace NTERA.Engine.Runtime
|
|
|
System.Threading.Thread.Sleep(-1);
|
|
|
}
|
|
|
|
|
|
- public ExecutionResult Call(FunctionDefinition function, IList<Value> parameters = null)
|
|
|
+ public ExecutionResult Call(FunctionDefinition function, IList<Parameter> parameters = null)
|
|
|
{
|
|
|
var localVariables = new Dictionary<string, Variable>();
|
|
|
- var globalVariables = new Dictionary<string, Variable>();
|
|
|
|
|
|
foreach (var variable in function.Variables)
|
|
|
{
|
|
@@ -68,28 +77,24 @@ namespace NTERA.Engine.Runtime
|
|
|
localVariables.Add(variable.Name, localVariable);
|
|
|
}
|
|
|
|
|
|
- foreach (var variable in BaseDefinitions.DefaultGlobalVariables)
|
|
|
+ foreach (var variable in GlobalVariables)
|
|
|
{
|
|
|
- var globalVariable = new Variable(variable.Name, variable.ValueType);
|
|
|
- globalVariable[0] = variable.CalculatedValue;
|
|
|
-
|
|
|
- globalVariables.Add(variable.Name, globalVariable);
|
|
|
+ localVariables.Add(variable.Key, variable.Value);
|
|
|
}
|
|
|
|
|
|
- var context = new StackFrame
|
|
|
+ var newContext = new StackFrame
|
|
|
{
|
|
|
SelfDefinition = function,
|
|
|
- GlobalVariables = globalVariables,
|
|
|
- LocalVariables = localVariables
|
|
|
+ Variables = localVariables
|
|
|
};
|
|
|
|
|
|
ExecutionResult result;
|
|
|
|
|
|
- ExecutionStack.Push(context);
|
|
|
+ ExecutionStack.Push(newContext);
|
|
|
|
|
|
if (function.Filename == "__GLOBAL")
|
|
|
{
|
|
|
- var resultValue = Base.Functions.StaticFunctions[function.Name].Invoke(this, context, parameters);
|
|
|
+ var resultValue = Base.Functions.StaticFunctions[function.Name].Invoke(this, newContext, parameters);
|
|
|
|
|
|
result = new ExecutionResult(ExecutionResultType.FunctionReturn, resultValue);
|
|
|
}
|
|
@@ -108,15 +113,27 @@ namespace NTERA.Engine.Runtime
|
|
|
else
|
|
|
throw new EraRuntimeException($"Unable to assign parameter #{index + 1}");
|
|
|
|
|
|
- var paramVariable = ComputeVariable(context, parameter.Name);
|
|
|
-
|
|
|
- paramVariable[parameter.Index] = parameters[index];
|
|
|
+
|
|
|
+ var localVariable = function.Variables.FirstOrDefault(x => x.Name == parameter.Name);
|
|
|
+
|
|
|
+ if (localVariable != null && localVariable.VariableType.HasFlag(VariableType.Reference))
|
|
|
+ {
|
|
|
+ if (parameters[index].BackingVariable == null)
|
|
|
+ throw new EraRuntimeException("Expected a variable to pass through as REF");
|
|
|
+
|
|
|
+ newContext.Variables[localVariable.Name] = parameters[index].BackingVariable;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var paramVariable = ComputeVariable(newContext, parameter.Name);
|
|
|
+ paramVariable[parameter.Index] = parameters[index];
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var executionContents = ExecutionProvider.GetExecutionNodes(function);
|
|
|
|
|
|
- result = ExecuteSet(context, executionContents.ToList());
|
|
|
+ result = ExecuteSet(newContext, executionContents.ToList());
|
|
|
}
|
|
|
|
|
|
ExecutionStack.Pop();
|
|
@@ -129,47 +146,23 @@ namespace NTERA.Engine.Runtime
|
|
|
for (int index = 0; index < nodes.Count; index++)
|
|
|
{
|
|
|
ExecutionNode node = nodes[index];
|
|
|
-
|
|
|
- if (node.Type == "statement")
|
|
|
+
|
|
|
+ if (node.Type == "for")
|
|
|
{
|
|
|
- if (node["name"].Equals("FOR", StringComparison.OrdinalIgnoreCase))
|
|
|
- {
|
|
|
- int endIndex = -1;
|
|
|
- int forLevel = 0;
|
|
|
-
|
|
|
- for (int subIndex = index + 1; subIndex < nodes.Count; subIndex++)
|
|
|
- {
|
|
|
- ExecutionNode subNode = nodes[subIndex];
|
|
|
-
|
|
|
- if (subNode.Type != "statement")
|
|
|
- continue;
|
|
|
-
|
|
|
- if (subNode["name"].Equals("FOR", StringComparison.OrdinalIgnoreCase))
|
|
|
- forLevel++;
|
|
|
+ ExecutionNode forContext = node[0];
|
|
|
|
|
|
- if (subNode["name"].Equals("NEXT", StringComparison.OrdinalIgnoreCase))
|
|
|
- {
|
|
|
- if (forLevel == 0)
|
|
|
- {
|
|
|
- endIndex = subIndex;
|
|
|
- break;
|
|
|
- }
|
|
|
+ var iterationVariable = ComputeVariable(context, forContext[0], out var iterationIndex);
|
|
|
|
|
|
- forLevel--;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (endIndex == -1)
|
|
|
- throw new EraRuntimeException("Could not find matching NEXT for FOR statement");
|
|
|
-
|
|
|
- //string variableName =
|
|
|
+ var beginNumber = ComputeExpression(context, forContext[1]);
|
|
|
+ var endNumber = ComputeExpression(context, forContext[2]);
|
|
|
|
|
|
- //for (context.LocalVariables[])
|
|
|
- ExecuteSet(context, nodes.Skip(index).Take(endIndex - index).ToArray());
|
|
|
-
|
|
|
- index = endIndex;
|
|
|
- continue;
|
|
|
+ for (iterationVariable[iterationIndex] = beginNumber.Real; iterationVariable[iterationIndex].Real < endNumber.Real; iterationVariable[iterationIndex]++)
|
|
|
+ {
|
|
|
+ var subset = node.Skip(1).ToList();
|
|
|
+ ExecuteSet(context, subset);
|
|
|
}
|
|
|
+
|
|
|
+ continue;
|
|
|
}
|
|
|
|
|
|
if (node.Type == "result")
|
|
@@ -211,7 +204,7 @@ namespace NTERA.Engine.Runtime
|
|
|
if (procedure == null)
|
|
|
throw new EraRuntimeException($"Unknown procedure: '{procedureName}'");
|
|
|
|
|
|
- var executionResult = Call(procedure, node.GetSubtype("parameters").Select(x => ComputeExpression(context, x)).ToArray());
|
|
|
+ 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}");
|
|
@@ -242,13 +235,25 @@ namespace NTERA.Engine.Runtime
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
public Variable ComputeVariable(StackFrame context, string variableName)
|
|
|
{
|
|
|
- if (context.LocalVariables.TryGetValue(variableName, out var variable)
|
|
|
- || context.GlobalVariables.TryGetValue(variableName, out variable))
|
|
|
+ if (context.Variables.TryGetValue(variableName, out var variable))
|
|
|
return variable;
|
|
|
|
|
|
throw new EraRuntimeException($"Unable to retrieve variable '{variableName}'");
|
|
|
}
|
|
|
|
|
|
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
+ public Parameter ComputeParameter(StackFrame context, ExecutionNode variableNode)
|
|
|
+ {
|
|
|
+ if (variableNode.Type == "variable")
|
|
|
+ {
|
|
|
+ var variable = ComputeVariable(context, variableNode, out int[] index);
|
|
|
+
|
|
|
+ return new Parameter(variable[index], variable, index);
|
|
|
+ }
|
|
|
+
|
|
|
+ return new Parameter(ComputeExpression(context, variableNode));
|
|
|
+ }
|
|
|
+
|
|
|
public Value ComputeExpression(StackFrame context, ExecutionNode expressionNode)
|
|
|
{
|
|
|
switch (expressionNode.Type)
|
|
@@ -272,7 +277,7 @@ namespace NTERA.Engine.Runtime
|
|
|
if (function == null)
|
|
|
throw new EraRuntimeException($"Unknown function: '{functionName}'");
|
|
|
|
|
|
- var executionResult = Call(function, expressionNode.GetSubtype("parameters").Select(x => ComputeExpression(context, x)).ToArray());
|
|
|
+ var executionResult = Call(function, expressionNode.GetSubtype("parameters").Select(x => ComputeParameter(context, x)).ToArray());
|
|
|
|
|
|
if (executionResult.Type != ExecutionResultType.FunctionReturn || !executionResult.Result.HasValue)
|
|
|
throw new EraRuntimeException($"Unexpected result from function '{functionName}': {executionResult.Type}");
|
|
@@ -293,6 +298,9 @@ namespace NTERA.Engine.Runtime
|
|
|
case "subtract":
|
|
|
operatorToken = Token.Minus;
|
|
|
break;
|
|
|
+ case "multiply":
|
|
|
+ operatorToken = Token.Asterisk;
|
|
|
+ break;
|
|
|
default: throw new EraRuntimeException($"Unknown operation type: '{operationType}'");
|
|
|
}
|
|
|
|