2018-11-10 12:11:36 +00:00
|
|
|
using System;
|
2018-11-15 19:13:53 +00:00
|
|
|
using System.Collections.Generic;
|
2018-11-16 13:58:15 +00:00
|
|
|
using System.Collections.Immutable;
|
2018-11-14 12:09:01 +00:00
|
|
|
using Upsilon.BaseTypes;
|
2018-11-11 17:12:42 +00:00
|
|
|
using Upsilon.BaseTypes.Number;
|
2018-11-21 12:47:16 +00:00
|
|
|
using Upsilon.BaseTypes.UserData;
|
2018-11-11 17:12:42 +00:00
|
|
|
using Upsilon.Binder;
|
2018-11-16 13:46:12 +00:00
|
|
|
using Type = Upsilon.BaseTypes.Type;
|
2018-11-10 12:11:36 +00:00
|
|
|
|
|
|
|
namespace Upsilon.Evaluator
|
|
|
|
{
|
2018-11-17 11:40:28 +00:00
|
|
|
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;
|
2018-11-17 11:40:28 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-11-20 11:55:41 +00:00
|
|
|
internal Evaluator(Diagnostics diagnostics, EvaluationScope parentScope)
|
2018-11-16 12:45:03 +00:00
|
|
|
{
|
|
|
|
_diagnostics = diagnostics;
|
|
|
|
Scope = new EvaluationScope(parentScope);
|
|
|
|
}
|
|
|
|
|
2018-11-14 12:09:01 +00:00
|
|
|
public LuaType Evaluate(BoundScript e)
|
2018-11-10 12:11:36 +00:00
|
|
|
{
|
2018-11-20 11:55:41 +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
|
|
|
}
|
|
|
|
|
2018-11-16 13:58:15 +00:00
|
|
|
public LuaType Evaluate(BoundScript e, string functionName, ImmutableArray<LuaType> parameters)
|
2018-11-16 13:46:12 +00:00
|
|
|
{
|
2018-11-20 11:55:41 +00:00
|
|
|
EvaluateNode(e.Statement);
|
2018-11-16 13:46:12 +00:00
|
|
|
if (!Scope.TryGet(functionName, out var statement) || statement.Type != Type.Function)
|
|
|
|
{
|
|
|
|
throw new ArgumentException(($"Function '{functionName}' could not be found"));
|
|
|
|
}
|
2018-11-20 11:55:41 +00:00
|
|
|
var function = (LuaInternalFunction) statement;
|
2018-11-16 13:46:12 +00:00
|
|
|
var innerEvaluator = new Evaluator(_diagnostics, Scope);
|
2018-11-16 13:58:15 +00:00
|
|
|
for (var index = 0; index < parameters.Length; index++)
|
|
|
|
{
|
|
|
|
var parameter = parameters[index];
|
|
|
|
var parameterName = function.Parameters[index];
|
|
|
|
innerEvaluator.Scope.Set(parameterName, parameter);
|
|
|
|
}
|
|
|
|
|
2018-11-20 11:55:41 +00:00
|
|
|
var result = innerEvaluator.EvaluateNode(function.Block);
|
2018-11-16 13:46:12 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-11-20 11:55:41 +00:00
|
|
|
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:
|
2018-11-18 21:22:30 +00:00
|
|
|
case BoundKind.BoundFunctionExpression:
|
2018-11-17 18:13:05 +00:00
|
|
|
case BoundKind.BoundTableExpression:
|
2018-11-18 21:22:30 +00:00
|
|
|
case BoundKind.BoundIndexExpression:
|
2018-11-20 13:05:34 +00:00
|
|
|
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:
|
2018-11-18 21:22:30 +00:00
|
|
|
case BoundKind.BoundFunctionAssignmentStatement:
|
2018-11-16 12:45:03 +00:00
|
|
|
case BoundKind.BoundPromise:
|
2018-11-18 21:22:30 +00:00
|
|
|
case BoundKind.BoundReturnStatement:
|
2018-11-19 15:22:13 +00:00
|
|
|
case BoundKind.BoundTableAssigmentStatement:
|
2018-11-21 16:18:35 +00:00
|
|
|
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;
|
2018-11-12 15:21:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void EvaluateStatement(BoundStatement e)
|
|
|
|
{
|
2018-11-16 12:45:03 +00:00
|
|
|
if (HasReturned)
|
|
|
|
return;
|
2018-11-12 15:21:59 +00:00
|
|
|
switch (e.Kind)
|
|
|
|
{
|
|
|
|
case BoundKind.BoundAssignmentStatement:
|
|
|
|
EvaluateAssignmentStatement((BoundVariableAssignment) e);
|
|
|
|
break;
|
2018-11-12 16:45:50 +00:00
|
|
|
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;
|
2018-11-18 21:22:30 +00:00
|
|
|
case BoundKind.BoundFunctionAssignmentStatement:
|
|
|
|
EvaluateBoundFunctionAssigmentStatement((BoundFunctionAssignmentStatement) e);
|
|
|
|
break;
|
2018-11-19 15:22:13 +00:00
|
|
|
case BoundKind.BoundTableAssigmentStatement:
|
|
|
|
EvaluateTableAssignmentStatement((BoundTableAssigmentStatement) e);
|
|
|
|
break;
|
2018-11-21 16:18:35 +00:00
|
|
|
case BoundKind.BoundMultiAssignmentStatement:
|
|
|
|
EvaluateMultiAssignmentStatement((BoundMultiAssignmentStatement) e);
|
|
|
|
break;
|
2018-11-12 15:21:59 +00:00
|
|
|
default:
|
|
|
|
EvaluateExpressionStatement((BoundExpressionStatement) e);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-12 16:45:50 +00:00
|
|
|
|
2018-11-12 15:21:59 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-11-20 11:55:41 +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);
|
2018-11-18 21:22:30 +00:00
|
|
|
case BoundKind.BoundFunctionExpression:
|
|
|
|
return EvaluateBoundFunctionStatement((BoundFunctionExpression) e);
|
|
|
|
case BoundKind.BoundPromise:
|
|
|
|
return EvaluateUnboundFunctionStatement((UnboundFunctionExpression) e);
|
2018-11-20 13:05:34 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-14 12:09:01 +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:
|
2018-11-21 12:54:41 +00:00
|
|
|
if (operand.Type == Type.Number)
|
|
|
|
return -((Number)operand);
|
|
|
|
else if (operand.Type == Type.UserData)
|
|
|
|
{
|
2018-11-21 13:49:59 +00:00
|
|
|
var ud = (GenericUserData) operand;
|
2018-11-21 12:54:41 +00:00
|
|
|
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:
|
2018-11-21 12:54:41 +00:00
|
|
|
if (operand.Type == Type.Boolean)
|
|
|
|
return !(LuaBoolean) operand;
|
|
|
|
else if (operand.Type == Type.UserData)
|
|
|
|
{
|
2018-11-21 13:49:59 +00:00
|
|
|
var ud = (GenericUserData) operand;
|
2018-11-21 12:54:41 +00:00
|
|
|
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
|
|
|
|
2018-11-14 12:09:01 +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;
|
|
|
|
}
|
2018-11-21 12:47:16 +00:00
|
|
|
else if (left.Type == Type.UserData)
|
|
|
|
{
|
2018-11-21 13:49:59 +00:00
|
|
|
var ud = (GenericUserData) left;
|
2018-11-21 12:47:16 +00:00
|
|
|
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:
|
2018-11-21 12:47:16 +00:00
|
|
|
if (left.Type == Type.Number)
|
|
|
|
{
|
|
|
|
return ((Number)left) - ((Number)right);
|
|
|
|
}
|
|
|
|
else if (left.Type == Type.UserData)
|
|
|
|
{
|
2018-11-21 13:49:59 +00:00
|
|
|
var ud = (GenericUserData) left;
|
2018-11-21 12:47:16 +00:00
|
|
|
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:
|
2018-11-21 12:47:16 +00:00
|
|
|
if (left.Type == Type.Number)
|
|
|
|
{
|
|
|
|
return ((Number)left) * ((Number)right);
|
|
|
|
}
|
|
|
|
else if (left.Type == Type.UserData)
|
|
|
|
{
|
2018-11-21 13:49:59 +00:00
|
|
|
var ud = (GenericUserData) left;
|
2018-11-21 12:47:16 +00:00
|
|
|
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:
|
2018-11-21 12:47:16 +00:00
|
|
|
if (left.Type == Type.Number)
|
|
|
|
{
|
|
|
|
return ((Number)left) / ((Number)right);
|
|
|
|
}
|
|
|
|
else if (left.Type == Type.UserData)
|
|
|
|
{
|
2018-11-21 13:49:59 +00:00
|
|
|
var ud = (GenericUserData) left;
|
2018-11-21 12:47:16 +00:00
|
|
|
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:
|
2018-11-14 12:10:24 +00:00
|
|
|
return new LuaBoolean(Equals(left, right));
|
2018-11-11 17:12:42 +00:00
|
|
|
case BoundBinaryOperator.OperatorKind.Inequality:
|
2018-11-14 12:10:24 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-12 16:45:50 +00:00
|
|
|
private void EvaluateAssignmentStatement(BoundVariableAssignment e)
|
2018-11-10 16:00:39 +00:00
|
|
|
{
|
2018-11-12 15:21:59 +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
|
|
|
|
2018-11-21 16:18:35 +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;
|
2018-11-21 16:25:12 +00:00
|
|
|
if (variableSymbol.Name == "_")
|
|
|
|
continue;
|
2018-11-21 16:18:35 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-11-14 12:09:01 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-11-12 16:45:50 +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-12 16:45:50 +00:00
|
|
|
}
|
|
|
|
}
|
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);
|
2018-11-14 12:10:24 +00:00
|
|
|
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
|
|
|
|
2018-11-18 21:22:30 +00:00
|
|
|
private void EvaluateBoundFunctionAssigmentStatement(BoundFunctionAssignmentStatement e)
|
2018-11-15 14:51:05 +00:00
|
|
|
{
|
2018-11-18 21:22:30 +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
|
2018-11-18 21:22:30 +00:00
|
|
|
Scope.SetGlobal(e.Variable, func);
|
2018-11-15 19:13:53 +00:00
|
|
|
}
|
|
|
|
|
2018-11-18 21:22:30 +00:00
|
|
|
private LuaType EvaluateBoundFunctionStatement(BoundFunctionExpression boundFunctionExpression)
|
2018-11-15 19:48:52 +00:00
|
|
|
{
|
2018-11-20 11:55:41 +00:00
|
|
|
var func = new LuaInternalFunction(boundFunctionExpression.Parameters, boundFunctionExpression.Block, Scope);
|
2018-11-18 21:22:30 +00:00
|
|
|
return func;
|
|
|
|
}
|
2018-11-15 19:48:52 +00:00
|
|
|
|
2018-11-18 21:22:30 +00:00
|
|
|
private LuaType EvaluateUnboundFunctionStatement(UnboundFunctionExpression unboundFunctionExpression)
|
|
|
|
{
|
2018-11-20 11:55:41 +00:00
|
|
|
var func = new LuaInternalFunction(unboundFunctionExpression.Parameters, unboundFunctionExpression.Block, Scope);
|
2018-11-18 21:22:30 +00:00
|
|
|
return func;
|
2018-11-15 19:48:52 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2018-11-18 21:22:30 +00:00
|
|
|
throw new Exception($"Variable is not a function.");
|
2018-11-15 19:13:53 +00:00
|
|
|
}
|
2018-11-20 11:55:41 +00:00
|
|
|
var ls = new List<LuaType>();
|
|
|
|
foreach (var t in boundFunctionCallExpression.Parameters)
|
2018-11-15 19:13:53 +00:00
|
|
|
{
|
2018-11-20 11:55:41 +00:00
|
|
|
var evaluate = EvaluateExpression(t);
|
|
|
|
ls.Add(evaluate);
|
2018-11-15 19:13:53 +00:00
|
|
|
}
|
2018-11-20 11:55:41 +00:00
|
|
|
|
|
|
|
var val = function.Run(_diagnostics, ls.ToArray());
|
|
|
|
return val;
|
2018-11-15 14:51:05 +00:00
|
|
|
}
|
2018-11-15 19:48:52 +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-15 19:48:52 +00:00
|
|
|
|
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);
|
2018-11-17 18:45:24 +00:00
|
|
|
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-18 21:22:30 +00:00
|
|
|
{
|
2018-11-19 11:17:21 +00:00
|
|
|
case BoundKind.BoundAssignmentStatement:
|
|
|
|
case BoundKind.BoundFunctionExpression:
|
|
|
|
case BoundKind.BoundFunctionAssignmentStatement:
|
2018-11-20 11:55:41 +00:00
|
|
|
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-17 18:45:24 +00:00
|
|
|
}
|
2018-11-19 11:17:21 +00:00
|
|
|
|
2018-11-17 18:45:24 +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;
|
|
|
|
}
|
2018-11-20 13:05:34 +00:00
|
|
|
var indexer = EvaluateExpression(e.Index);
|
2018-11-21 13:49:59 +00:00
|
|
|
return indexable.Get(_diagnostics, e.Span, indexer, scope);
|
2018-11-17 18:13:05 +00:00
|
|
|
}
|
2018-11-20 13:05:34 +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;
|
|
|
|
}
|
|
|
|
|
2018-11-21 13:49:59 +00:00
|
|
|
return indexable.Get(_diagnostics, e.Span, e.Index.ToLuaType(), scope);
|
2018-11-20 13:05:34 +00:00
|
|
|
}
|
2018-11-19 15:22:13 +00:00
|
|
|
|
|
|
|
private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e)
|
|
|
|
{
|
2018-11-20 13:05:34 +00:00
|
|
|
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
|
|
|
}
|
2018-11-21 13:49:59 +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
|
|
|
}
|
|
|
|
}
|