Upsilon/Upsilon/Evaluator/Evaluator.cs

482 lines
20 KiB
C#
Raw Normal View History

2018-11-10 12:11:36 +00:00
using System;
2018-11-15 19:13:53 +00:00
using System.Collections.Generic;
using System.Collections.Immutable;
using Upsilon.BaseTypes;
2018-11-11 17:12:42 +00:00
using Upsilon.BaseTypes.Number;
using Upsilon.BaseTypes.UserData;
2018-11-11 17:12:42 +00:00
using Upsilon.Binder;
using Type = Upsilon.BaseTypes.Type;
2018-11-10 12:11:36 +00:00
namespace Upsilon.Evaluator
{
internal class Evaluator
2018-11-10 12:11:36 +00:00
{
2018-11-11 09:26:52 +00:00
private readonly Diagnostics _diagnostics;
2018-11-16 13:11:27 +00:00
private LuaType _lastValue;
private LuaType _returnValue;
internal EvaluationScope Scope { get; }
2018-11-16 12:45:03 +00:00
private bool HasReturned { get; set; }
2018-11-10 16:00:39 +00:00
2018-11-19 11:49:48 +00:00
internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables)
2018-11-11 20:03:50 +00:00
{
_diagnostics = diagnostics;
2018-11-15 19:13:53 +00:00
Scope = new EvaluationScope(variables);
2018-11-10 16:00:39 +00:00
}
internal Evaluator(Diagnostics diagnostics, EvaluationScope parentScope)
2018-11-16 12:45:03 +00:00
{
_diagnostics = diagnostics;
Scope = new EvaluationScope(parentScope);
}
public LuaType Evaluate(BoundScript e)
2018-11-10 12:11:36 +00:00
{
EvaluateNode(e.Statement);
2018-11-16 13:11:27 +00:00
if (_returnValue == null)
return _lastValue;
return _returnValue;
2018-11-16 12:45:03 +00:00
}
public LuaType Evaluate(BoundScript e, string functionName, ImmutableArray<LuaType> parameters)
{
EvaluateNode(e.Statement);
if (!Scope.TryGet(functionName, out var statement) || statement.Type != Type.Function)
{
throw new ArgumentException(($"Function '{functionName}' could not be found"));
}
var function = (LuaInternalFunction) statement;
var innerEvaluator = new Evaluator(_diagnostics, Scope);
for (var index = 0; index < parameters.Length; index++)
{
var parameter = parameters[index];
var parameterName = function.Parameters[index];
innerEvaluator.Scope.Set(parameterName, parameter);
}
var result = innerEvaluator.EvaluateNode(function.Block);
return result;
}
internal LuaType EvaluateNode(BoundNode b)
2018-11-16 12:45:03 +00:00
{
switch (b.Kind)
{
case BoundKind.BoundScript:
EvaluateStatement(((BoundScript)b).Statement);
break;
case BoundKind.BoundLiteralExpression:
case BoundKind.BoundBinaryExpression:
case BoundKind.BoundUnaryExpression:
case BoundKind.VariableExpression:
case BoundKind.BoundFunctionCallExpression:
case BoundKind.BoundFunctionExpression:
2018-11-17 18:13:05 +00:00
case BoundKind.BoundTableExpression:
case BoundKind.BoundIndexExpression:
case BoundKind.BoundFullstopIndexExpression:
2018-11-16 13:11:27 +00:00
_lastValue = EvaluateExpression((BoundExpression) b);
2018-11-16 12:45:03 +00:00
break;
case BoundKind.BoundAssignmentStatement:
case BoundKind.BoundExpressionStatement:
case BoundKind.BoundBlockStatement:
case BoundKind.BoundIfStatement:
case BoundKind.BoundElseStatement:
case BoundKind.BoundFunctionAssignmentStatement:
2018-11-16 12:45:03 +00:00
case BoundKind.BoundPromise:
case BoundKind.BoundReturnStatement:
2018-11-19 15:22:13 +00:00
case BoundKind.BoundTableAssigmentStatement:
case BoundKind.BoundMultiAssignmentStatement:
2018-11-16 12:45:03 +00:00
EvaluateStatement((BoundStatement) b);
break;
default:
throw new ArgumentOutOfRangeException();
}
2018-11-16 13:11:27 +00:00
return _returnValue;
}
private void EvaluateStatement(BoundStatement e)
{
2018-11-16 12:45:03 +00:00
if (HasReturned)
return;
switch (e.Kind)
{
case BoundKind.BoundAssignmentStatement:
EvaluateAssignmentStatement((BoundVariableAssignment) e);
break;
case BoundKind.BoundBlockStatement:
EvaluateBoundBlockStatement((BoundBlockStatement) e);
break;
2018-11-13 11:48:50 +00:00
case BoundKind.BoundIfStatement:
EvaluateBoundIfStatement((BoundIfStatement) e);
break;
2018-11-16 12:45:03 +00:00
case BoundKind.BoundReturnStatement:
EvaluateReturnStatement((BoundReturnStatement) e);
break;
case BoundKind.BoundFunctionAssignmentStatement:
EvaluateBoundFunctionAssigmentStatement((BoundFunctionAssignmentStatement) e);
break;
2018-11-19 15:22:13 +00:00
case BoundKind.BoundTableAssigmentStatement:
EvaluateTableAssignmentStatement((BoundTableAssigmentStatement) e);
break;
case BoundKind.BoundMultiAssignmentStatement:
EvaluateMultiAssignmentStatement((BoundMultiAssignmentStatement) e);
break;
default:
EvaluateExpressionStatement((BoundExpressionStatement) e);
break;
}
}
private void EvaluateExpressionStatement(BoundExpressionStatement e)
{
2018-11-16 13:11:27 +00:00
_lastValue = EvaluateExpression(e.Expression);
2018-11-10 12:11:36 +00:00
}
internal LuaType EvaluateExpression(BoundExpression e)
2018-11-10 12:11:36 +00:00
{
switch (e.Kind)
{
2018-11-11 17:12:42 +00:00
case BoundKind.BoundLiteralExpression:
return ((BoundLiteralExpression) e).Value;
case BoundKind.BoundBinaryExpression:
return EvaluateBinaryExpression((BoundBinaryExpression) e);
2018-11-11 18:56:53 +00:00
case BoundKind.BoundUnaryExpression:
return EvaluateUnaryExpression((BoundUnaryExpression) e);
2018-11-11 20:03:50 +00:00
case BoundKind.VariableExpression:
return EvaluateVariableExpression((BoundVariableExpression) e);
2018-11-15 19:13:53 +00:00
case BoundKind.BoundFunctionCallExpression:
return EvaluateBoundFunctionCallExpression((BoundFunctionCallExpression) e);
2018-11-17 18:13:05 +00:00
case BoundKind.BoundTableExpression:
return EvaluateTableExpression((BoundTableExpression) e);
2018-11-18 13:18:24 +00:00
case BoundKind.BoundIndexExpression:
return EvaluateIndexExpression((BoundIndexExpression) e);
case BoundKind.BoundFunctionExpression:
return EvaluateBoundFunctionStatement((BoundFunctionExpression) e);
case BoundKind.BoundPromise:
return EvaluateUnboundFunctionStatement((UnboundFunctionExpression) e);
case BoundKind.BoundFullstopIndexExpression:
return EvaluateFullStopIndexExpression((BoundFullStopIndexExpression) e);
2018-11-10 12:11:36 +00:00
default:
2018-11-11 18:56:53 +00:00
throw new NotImplementedException();
2018-11-10 12:11:36 +00:00
}
}
private LuaType EvaluateUnaryExpression(BoundUnaryExpression e)
2018-11-10 12:11:36 +00:00
{
2018-11-11 18:56:53 +00:00
var operand = EvaluateExpression(e.InExpression);
2018-11-10 12:11:36 +00:00
switch (e.Operator.Kind)
{
2018-11-11 18:56:53 +00:00
case BoundUnaryOperator.OperatorKind.Identity:
2018-11-10 12:11:36 +00:00
return operand;
2018-11-11 18:56:53 +00:00
case BoundUnaryOperator.OperatorKind.Negation:
if (operand.Type == Type.Number)
return -((Number)operand);
else if (operand.Type == Type.UserData)
{
var ud = (GenericUserData) operand;
var (type, failed) = ud.UnaryOperator(operand, OperatorType.UnaryNegation);
if (failed) goto default;
return type;
}
goto default;
2018-11-11 18:56:53 +00:00
case BoundUnaryOperator.OperatorKind.LogicalNegation:
if (operand.Type == Type.Boolean)
return !(LuaBoolean) operand;
else if (operand.Type == Type.UserData)
{
var ud = (GenericUserData) operand;
var (type, failed) = ud.UnaryOperator(operand, OperatorType.LogicalNot);
if (failed) goto default;
return type;
}
goto default;
2018-11-10 12:11:36 +00:00
default:
throw new Exception("Invalid Unary Operator: " + e.Operator.Kind);
}
2018-11-11 18:56:53 +00:00
}
2018-11-10 12:11:36 +00:00
private LuaType EvaluateBinaryExpression(BoundBinaryExpression e)
2018-11-10 12:11:36 +00:00
{
2018-11-11 17:12:42 +00:00
var left = EvaluateExpression(e.LeftExpression);
var right = EvaluateExpression(e.RightExpression);
switch (e.Operator.Kind)
2018-11-11 09:26:52 +00:00
{
2018-11-11 17:12:42 +00:00
case BoundBinaryOperator.OperatorKind.Addition:
2018-11-17 14:57:26 +00:00
if (left.Type == Type.Number)
return ((Number)left) + ((Number)right);
else if (left.Type == Type.String)
{
return ((LuaString) left) + right;
}
else if (left.Type == Type.UserData)
{
var ud = (GenericUserData) left;
var (type, failed) = ud.BinaryOperator(left, OperatorType.Addition, right);
if (failed) goto default;
return type;
}
2018-11-17 14:57:26 +00:00
goto default;
2018-11-11 17:12:42 +00:00
case BoundBinaryOperator.OperatorKind.Subtraction:
if (left.Type == Type.Number)
{
return ((Number)left) - ((Number)right);
}
else if (left.Type == Type.UserData)
{
var ud = (GenericUserData) left;
var (type, failed) = ud.BinaryOperator(left, OperatorType.Subtraction, right);
if (failed) goto default;
return type;
}
goto default;
2018-11-11 17:12:42 +00:00
case BoundBinaryOperator.OperatorKind.Multiplication:
if (left.Type == Type.Number)
{
return ((Number)left) * ((Number)right);
}
else if (left.Type == Type.UserData)
{
var ud = (GenericUserData) left;
var (type, failed) = ud.BinaryOperator(left, OperatorType.Multiplication, right);
if (failed) goto default;
return type;
}
goto default;
2018-11-11 17:12:42 +00:00
case BoundBinaryOperator.OperatorKind.Division:
if (left.Type == Type.Number)
{
return ((Number)left) / ((Number)right);
}
else if (left.Type == Type.UserData)
{
var ud = (GenericUserData) left;
var (type, failed) = ud.BinaryOperator(left, OperatorType.Division, right);
if (failed) goto default;
return type;
}
goto default;
2018-11-11 17:12:42 +00:00
case BoundBinaryOperator.OperatorKind.Equality:
return new LuaBoolean(Equals(left, right));
2018-11-11 17:12:42 +00:00
case BoundBinaryOperator.OperatorKind.Inequality:
return new LuaBoolean(!Equals(left, right));
2018-11-11 17:12:42 +00:00
default:
throw new Exception("Invalid Binary Operator: " + e.Operator);
2018-11-10 12:11:36 +00:00
}
}
private void EvaluateAssignmentStatement(BoundVariableAssignment e)
2018-11-10 16:00:39 +00:00
{
var val = EvaluateExpression(e.BoundExpression);
2018-11-14 15:39:52 +00:00
if (e.Variable.Local)
{
2018-11-15 19:13:53 +00:00
Scope.Set(e.Variable, val);
2018-11-14 15:39:52 +00:00
}
else
{
2018-11-15 19:13:53 +00:00
Scope.SetGlobal(e.Variable, val);
2018-11-14 15:39:52 +00:00
}
2018-11-16 13:11:27 +00:00
_lastValue = val;
2018-11-11 19:31:55 +00:00
}
2018-11-10 16:00:39 +00:00
private void EvaluateMultiAssignmentStatement(BoundMultiAssignmentStatement e)
{
var val = EvaluateExpression(e.Assignment);
if (val.Type == Type.Table)
{
var table = (LuaTable) val;
for (var i = 0; i < e.Variables.Length; i++)
{
var variableSymbol = e.Variables[i];
if (variableSymbol == null)
continue;
if (variableSymbol.Name == "_")
continue;
var value = table.Get(_diagnostics, e.Span, new NumberLong(i + 1), Scope);
if (variableSymbol.Local)
Scope.Set(variableSymbol, value);
else
Scope.SetGlobal(variableSymbol, value);
}
}
else
{
_diagnostics.LogError($"Can't assign type '{val.Type}' to multiple variables.", e.Span);
}
_lastValue = val;
}
private LuaType EvaluateVariableExpression(BoundVariableExpression e)
2018-11-10 16:00:39 +00:00
{
2018-11-15 19:13:53 +00:00
if (Scope.TryGet(e.Variable, out var val))
2018-11-14 15:39:52 +00:00
{
return val;
}
throw new Exception($"Cannot find variable: '{e.Variable.Name}'");
2018-11-10 16:00:39 +00:00
}
private void EvaluateBoundBlockStatement(BoundBlockStatement boundBlockStatement)
{
foreach (var boundStatement in boundBlockStatement.Statements)
{
2018-11-16 12:45:03 +00:00
if (HasReturned)
return;
2018-11-15 19:13:53 +00:00
EvaluateStatement(boundStatement);
}
}
2018-11-13 11:48:50 +00:00
private void EvaluateBoundIfStatement(BoundIfStatement boundBlockStatement)
{
2018-11-16 12:45:03 +00:00
var innerEvaluator = new Evaluator(_diagnostics, Scope);
var condition = innerEvaluator.EvaluateExpression(boundBlockStatement.Condition.Expression);
if ((LuaBoolean) condition)
2018-11-13 11:48:50 +00:00
{
2018-11-16 12:45:03 +00:00
innerEvaluator.EvaluateStatement(boundBlockStatement.Block);
2018-11-13 11:48:50 +00:00
}
2018-11-13 14:15:44 +00:00
else if (boundBlockStatement.NextElseIf != null)
{
2018-11-16 12:45:03 +00:00
innerEvaluator.EvaluateStatement(boundBlockStatement.NextElseIf);
2018-11-13 14:15:44 +00:00
}
2018-11-13 12:54:51 +00:00
else if (boundBlockStatement.ElseStatement != null)
{
2018-11-16 12:45:03 +00:00
innerEvaluator.EvaluateStatement(boundBlockStatement.ElseStatement.Block);
2018-11-13 12:54:51 +00:00
}
2018-11-16 12:45:03 +00:00
HasReturned = innerEvaluator.HasReturned;
2018-11-16 13:47:03 +00:00
if (HasReturned)
_returnValue = innerEvaluator._returnValue;
2018-11-16 13:11:27 +00:00
_lastValue = innerEvaluator._lastValue;
2018-11-13 11:48:50 +00:00
}
2018-11-15 14:51:05 +00:00
private void EvaluateBoundFunctionAssigmentStatement(BoundFunctionAssignmentStatement e)
2018-11-15 14:51:05 +00:00
{
var func = EvaluateBoundFunctionStatement(e.Func);
if (e.Variable.Local)
Scope.Set(e.Variable, func);
2018-11-15 14:51:05 +00:00
else
Scope.SetGlobal(e.Variable, func);
2018-11-15 19:13:53 +00:00
}
private LuaType EvaluateBoundFunctionStatement(BoundFunctionExpression boundFunctionExpression)
{
var func = new LuaInternalFunction(boundFunctionExpression.Parameters, boundFunctionExpression.Block, Scope);
return func;
}
private LuaType EvaluateUnboundFunctionStatement(UnboundFunctionExpression unboundFunctionExpression)
{
var func = new LuaInternalFunction(unboundFunctionExpression.Parameters, unboundFunctionExpression.Block, Scope);
return func;
}
2018-11-15 19:13:53 +00:00
private LuaType EvaluateBoundFunctionCallExpression(BoundFunctionCallExpression boundFunctionCallExpression)
{
2018-11-18 19:20:03 +00:00
var variable = EvaluateExpression(boundFunctionCallExpression.Identifier);
if (!(variable is LuaFunction function))
2018-11-15 19:13:53 +00:00
{
throw new Exception($"Variable is not a function.");
2018-11-15 19:13:53 +00:00
}
var ls = new List<LuaType>();
foreach (var t in boundFunctionCallExpression.Parameters)
2018-11-15 19:13:53 +00:00
{
var evaluate = EvaluateExpression(t);
ls.Add(evaluate);
2018-11-15 19:13:53 +00:00
}
var val = function.Run(_diagnostics, ls.ToArray());
return val;
2018-11-15 14:51:05 +00:00
}
2018-11-16 12:45:03 +00:00
private void EvaluateReturnStatement(BoundReturnStatement b)
{
2018-11-16 13:11:27 +00:00
_returnValue = EvaluateExpression(b.Expression);
_lastValue = _returnValue;
2018-11-16 12:45:03 +00:00
HasReturned = true;
}
2018-11-17 18:13:05 +00:00
private LuaType EvaluateTableExpression(BoundTableExpression e)
{
2018-11-19 11:17:21 +00:00
var tableScope = EvaluationScope.CreateWithGetOnlyParent(Scope);
var innerEvaluator = new Evaluator(_diagnostics, tableScope);
var currentPos = 1;
foreach (var boundStatement in e.Statements)
2018-11-17 18:13:05 +00:00
{
2018-11-19 11:17:21 +00:00
switch (boundStatement.Kind)
{
2018-11-19 11:17:21 +00:00
case BoundKind.BoundAssignmentStatement:
case BoundKind.BoundFunctionExpression:
case BoundKind.BoundFunctionAssignmentStatement:
innerEvaluator.EvaluateNode(boundStatement);
2018-11-19 11:17:21 +00:00
break;
default:
{
innerEvaluator.EvaluateStatement(boundStatement);
if (innerEvaluator._lastValue != null)
tableScope.Set(new VariableSymbol(currentPos.ToString(), innerEvaluator._lastValue.Type, false),
innerEvaluator._lastValue);
innerEvaluator._lastValue = null;
break;
}
}
2018-11-19 11:17:21 +00:00
currentPos++;
2018-11-17 18:13:05 +00:00
}
2018-11-19 11:17:21 +00:00
return new LuaTable(tableScope);
2018-11-18 13:18:24 +00:00
}
private LuaType EvaluateIndexExpression(BoundIndexExpression e)
{
2018-11-18 19:20:03 +00:00
var variable = EvaluateExpression(e.Identifier);
if (!(variable is IIndexable indexable))
2018-11-18 13:18:24 +00:00
{
2018-11-18 19:20:03 +00:00
throw new Exception("Variable is not indexable.");
2018-11-18 13:18:24 +00:00
}
2018-11-19 11:17:21 +00:00
var scope = Scope;
if (variable is IScopeOwner scopeOwner)
{
scope = scopeOwner.EvaluationScope;
}
var indexer = EvaluateExpression(e.Index);
return indexable.Get(_diagnostics, e.Span, indexer, scope);
2018-11-17 18:13:05 +00:00
}
private LuaType EvaluateFullStopIndexExpression(BoundFullStopIndexExpression e)
{
var variable = EvaluateExpression(e.Expression);
if (!(variable is IIndexable indexable))
{
throw new Exception("Variable is not indexable.");
}
var scope = Scope;
if (variable is IScopeOwner scopeOwner)
{
scope = scopeOwner.EvaluationScope;
}
return indexable.Get(_diagnostics, e.Span, e.Index.ToLuaType(), scope);
}
2018-11-19 15:22:13 +00:00
private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e)
{
LuaType table;
LuaType index;
if (e.TableIndexExpression.Kind == BoundKind.BoundIndexExpression)
{
table = EvaluateExpression(((BoundIndexExpression)e.TableIndexExpression).Identifier);
index = EvaluateExpression(((BoundIndexExpression)e.TableIndexExpression).Index);
}
else
{
table = EvaluateExpression(((BoundFullStopIndexExpression)e.TableIndexExpression).Expression);
index = ((BoundFullStopIndexExpression) e.TableIndexExpression).Index.ToLuaType();
}
2018-11-19 15:22:13 +00:00
var value = EvaluateExpression(e.Value);
2018-11-19 16:22:25 +00:00
if (!(table is IIndexable indexable))
2018-11-19 15:22:13 +00:00
{
2018-11-19 16:22:25 +00:00
throw new Exception("Cant assign to that");
2018-11-19 15:22:13 +00:00
}
indexable.Set(_diagnostics, e.Span, index.ToString().ToLuaType(), value);
2018-11-19 15:22:13 +00:00
}
2018-11-10 12:11:36 +00:00
}
}