Refactor evaluation to not be handled in a single large class
This commit is contained in:
parent
4790cc74d2
commit
237f2fefd9
|
@ -107,9 +107,9 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
var callingVariable = variables[index];
|
var callingVariable = variables[index];
|
||||||
var optionVariable = option.Parameters[index];
|
var optionVariable = option.Parameters[index];
|
||||||
if (callingVariable.Type == BaseTypes.Type.Unknown || callingVariable.Type == BaseTypes.Type.Nil ||
|
if (callingVariable.Type == BaseTypes.Type.Unknown || callingVariable.Type == BaseTypes.Type.Nil ||
|
||||||
optionVariable.Type == BaseTypes.Type.Unknown)
|
optionVariable.ValueType == BaseTypes.Type.Unknown)
|
||||||
continue;
|
continue;
|
||||||
if (callingVariable.Type != optionVariable.Type)
|
if (callingVariable.Type != optionVariable.ValueType)
|
||||||
{
|
{
|
||||||
isCompatible = false;
|
isCompatible = false;
|
||||||
break;
|
break;
|
||||||
|
@ -135,10 +135,10 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
{
|
{
|
||||||
var callingVariable = variables[index];
|
var callingVariable = variables[index];
|
||||||
var optionVariable = option.Parameters[index];
|
var optionVariable = option.Parameters[index];
|
||||||
if (callingVariable.Type == BaseTypes.Type.Unknown || callingVariable.Type == BaseTypes.Type.Nil ||
|
if (callingVariable.ValueType == BaseTypes.Type.Unknown || callingVariable.ValueType == BaseTypes.Type.Nil ||
|
||||||
optionVariable.Type == BaseTypes.Type.Unknown)
|
optionVariable.ValueType == BaseTypes.Type.Unknown)
|
||||||
continue;
|
continue;
|
||||||
if (callingVariable.Type != optionVariable.Type)
|
if (callingVariable.ValueType != optionVariable.ValueType)
|
||||||
{
|
{
|
||||||
isCompatible = false;
|
isCompatible = false;
|
||||||
break;
|
break;
|
||||||
|
@ -163,24 +163,30 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
EvaluationScope = scope;
|
EvaluationScope = scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EvaluationScope EvaluationScope { get; }
|
public EvaluationScope EvaluationScope { get; set; }
|
||||||
|
|
||||||
public BoundBlockStatement Block { get; }
|
public BoundBlockStatement Block { get; }
|
||||||
public ImmutableArray<BoundVariableSymbol> Parameters { get; }
|
public ImmutableArray<BoundVariableSymbol> Parameters { get; }
|
||||||
|
|
||||||
public ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span)
|
public ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope outerScope, TextSpan span)
|
||||||
{
|
{
|
||||||
var innerEvaluator = new Evaluator.Evaluator(diagnostics, EvaluationScope, script);
|
var innerScope = new EvaluationScope(EvaluationScope);
|
||||||
|
var state = new EvaluationState()
|
||||||
|
{
|
||||||
|
Script = script,
|
||||||
|
};
|
||||||
if (Parameters != null)
|
if (Parameters != null)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < Parameters.Length; i++)
|
for (var i = 0; i < Parameters.Length; i++)
|
||||||
{
|
{
|
||||||
var parameterVariable = Parameters[i];
|
var parameterVariable = Parameters[i];
|
||||||
var parameterValue = variables[i];
|
var parameterValue = variables[i];
|
||||||
innerEvaluator.Scope.CreateLocal(parameterVariable.VariableSymbol, parameterValue);
|
innerScope.CreateLocal(parameterVariable.VariableSymbol, parameterValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return innerEvaluator.EvaluateNode(Block);
|
|
||||||
|
Block.Evaluate(innerScope, diagnostics, ref state);
|
||||||
|
return state.ReturnValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,10 +139,10 @@ namespace Upsilon.Binder
|
||||||
var inExp = BindExpression(e.Expression);
|
var inExp = BindExpression(e.Expression);
|
||||||
if (inExp.Kind == BoundKind.BoundBadExpression)
|
if (inExp.Kind == BoundKind.BoundBadExpression)
|
||||||
return new BoundBadExpression(e.Span);
|
return new BoundBadExpression(e.Span);
|
||||||
var op = BoundUnaryOperator.Bind(e.Operator.Kind, inExp.Type);
|
var op = BoundUnaryOperator.Bind(e.Operator.Kind, inExp.ValueType);
|
||||||
if (op == null)
|
if (op == null)
|
||||||
{
|
{
|
||||||
_diagnostics.LogUnknownUnaryOperator(e.Span, e.Operator.Kind, inExp.Type);
|
_diagnostics.LogUnknownUnaryOperator(e.Span, e.Operator.Kind, inExp.ValueType);
|
||||||
return inExp;
|
return inExp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,10 +155,10 @@ namespace Upsilon.Binder
|
||||||
var right = BindExpression(e.Right);
|
var right = BindExpression(e.Right);
|
||||||
if (left.Kind == BoundKind.BoundBadExpression || right.Kind == BoundKind.BoundBadExpression)
|
if (left.Kind == BoundKind.BoundBadExpression || right.Kind == BoundKind.BoundBadExpression)
|
||||||
return new BoundBadExpression(e.Span);
|
return new BoundBadExpression(e.Span);
|
||||||
var op = BoundBinaryOperator.Bind(e.Operator.Kind, left.Type, right.Type);
|
var op = BoundBinaryOperator.Bind(e.Operator.Kind, left.ValueType, right.ValueType);
|
||||||
if (op == null)
|
if (op == null)
|
||||||
{
|
{
|
||||||
_diagnostics.LogUnknownBinaryOperator(e.Span, e.Operator.Kind, left.Type, right.Type);
|
_diagnostics.LogUnknownBinaryOperator(e.Span, e.Operator.Kind, left.ValueType, right.ValueType);
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
return new BoundBinaryExpression(op, left, right, op.OutType, e.Span);
|
return new BoundBinaryExpression(op, left, right, op.OutType, e.Span);
|
||||||
|
@ -201,7 +201,7 @@ namespace Upsilon.Binder
|
||||||
private BoundExpression BindFunctionCallExpression(FunctionCallExpressionSyntax e)
|
private BoundExpression BindFunctionCallExpression(FunctionCallExpressionSyntax e)
|
||||||
{
|
{
|
||||||
var expression = BindExpression(e.Identifier);
|
var expression = BindExpression(e.Identifier);
|
||||||
if (expression.Type != Type.Function && expression.Type != Type.Unknown)
|
if (expression.ValueType != Type.Function && expression.ValueType != Type.Unknown)
|
||||||
{
|
{
|
||||||
_diagnostics.LogError($"Unknown function called.", e.Span);
|
_diagnostics.LogError($"Unknown function called.", e.Span);
|
||||||
return new BoundBadExpression(e.Span);
|
return new BoundBadExpression(e.Span);
|
||||||
|
@ -225,7 +225,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
if (function is ScriptFunctionVariableSymbol scriptFunction)
|
if (function is ScriptFunctionVariableSymbol scriptFunction)
|
||||||
{
|
{
|
||||||
if ((scriptFunction.GetFirstValid(parameters.Select(x => x.Type).ToArray()) is ScriptFunctionVariableOption functionOption))
|
if ((scriptFunction.GetFirstValid(parameters.Select(x => x.ValueType).ToArray()) is ScriptFunctionVariableOption functionOption))
|
||||||
{
|
{
|
||||||
if (!functionOption.IsBound)
|
if (!functionOption.IsBound)
|
||||||
{
|
{
|
||||||
|
@ -234,7 +234,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
var functionVariable = functionOption.Parameters[index];
|
var functionVariable = functionOption.Parameters[index];
|
||||||
var callingVariable = parameters[index];
|
var callingVariable = parameters[index];
|
||||||
functionVariable.TypeContainer = callingVariable.Type;
|
functionVariable.TypeContainer = callingVariable.ValueType;
|
||||||
Scope.DefineLocalVariable(functionVariable);
|
Scope.DefineLocalVariable(functionVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ namespace Upsilon.Binder
|
||||||
if (!isValid)
|
if (!isValid)
|
||||||
{
|
{
|
||||||
_diagnostics.LogError(
|
_diagnostics.LogError(
|
||||||
$"No valid function with name '{function.Name}' and parameter types {string.Join(", ", parameters.Select(x => $"'{x.Type}'"))} found",
|
$"No valid function with name '{function.Name}' and parameter types {string.Join(", ", parameters.Select(x => $"'{x.ValueType}'"))} found",
|
||||||
expression.Span);
|
expression.Span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +320,7 @@ namespace Upsilon.Binder
|
||||||
if (option == null)
|
if (option == null)
|
||||||
{
|
{
|
||||||
_diagnostics.LogError(
|
_diagnostics.LogError(
|
||||||
$"No valid function with name '{ubMethod.Name}' and parameter types {string.Join(", ", parameters.Select(x => $"'{x.Type}'"))} found",
|
$"No valid function with name '{ubMethod.Name}' and parameter types {string.Join(", ", parameters.Select(x => $"'{x.ValueType}'"))} found",
|
||||||
expression.Span);
|
expression.Span);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -421,7 +421,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
return new VariableSymbol("", compositeTypeContainer.Types[1], true);
|
return new VariableSymbol("", compositeTypeContainer.Types[1], true);
|
||||||
}
|
}
|
||||||
return new VariableSymbol("", expression.Type, true);
|
return new VariableSymbol("", expression.ValueType, true);
|
||||||
}
|
}
|
||||||
else if (indexerVariable.TypeContainer == Type.Unknown)
|
else if (indexerVariable.TypeContainer == Type.Unknown)
|
||||||
{
|
{
|
||||||
|
@ -430,18 +430,18 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
else if (expression.Kind == BoundKind.BoundFunctionCallExpression)
|
else if (expression.Kind == BoundKind.BoundFunctionCallExpression)
|
||||||
{
|
{
|
||||||
if (expression.Type == Type.UserData)
|
if (expression.ValueType == Type.UserData)
|
||||||
{
|
{
|
||||||
var ud = expression.Type.UserData;
|
var ud = expression.ValueType.UserData;
|
||||||
if (!string.IsNullOrEmpty(ud))
|
if (!string.IsNullOrEmpty(ud))
|
||||||
{
|
{
|
||||||
var boundDef = BoundTypeHandler.GetTypeDefinition(ud);
|
var boundDef = BoundTypeHandler.GetTypeDefinition(ud);
|
||||||
return new UserDataVariableSymbol("", boundDef, true);
|
return new UserDataVariableSymbol("", boundDef, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new VariableSymbol("", expression.Type, true);
|
return new VariableSymbol("", expression.ValueType, true);
|
||||||
}
|
}
|
||||||
else if (expression.Type == Type.Unknown)
|
else if (expression.ValueType == Type.Unknown)
|
||||||
{
|
{
|
||||||
return new VariableSymbol("", Type.Unknown, true);
|
return new VariableSymbol("", Type.Unknown, true);
|
||||||
}
|
}
|
||||||
|
@ -473,27 +473,27 @@ namespace Upsilon.Binder
|
||||||
var isCreation = false;
|
var isCreation = false;
|
||||||
if (!Scope.TryGetVariable(name, !isLocal, out var variable))
|
if (!Scope.TryGetVariable(name, !isLocal, out var variable))
|
||||||
{
|
{
|
||||||
if (assignment.Type == Type.Table)
|
if (assignment.ValueType == Type.Table)
|
||||||
{
|
{
|
||||||
if (assignment.Kind == BoundKind.BoundTableExpression)
|
if (assignment.Kind == BoundKind.BoundTableExpression)
|
||||||
{
|
{
|
||||||
variable = new TableVariableSymbol(name, isLocal,
|
variable = new TableVariableSymbol(name, isLocal,
|
||||||
((BoundTableExpression) assignment).Expressions, assignment.Type);
|
((BoundTableExpression) assignment).Expressions, assignment.ValueType);
|
||||||
}
|
}
|
||||||
else if (assignment.Kind == BoundKind.VariableExpression)
|
else if (assignment.Kind == BoundKind.VariableExpression)
|
||||||
{
|
{
|
||||||
variable = new TableVariableSymbol(name, isLocal,
|
variable = new TableVariableSymbol(name, isLocal,
|
||||||
((TableVariableSymbol) ((BoundVariableExpression) assignment).Variable.VariableSymbol)
|
((TableVariableSymbol) ((BoundVariableExpression) assignment).Variable.VariableSymbol)
|
||||||
.Variables, assignment.Type);
|
.Variables, assignment.ValueType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
variable = new TableVariableSymbol(name, isLocal, assignment.Type);
|
variable = new TableVariableSymbol(name, isLocal, assignment.ValueType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (assignment.Type == Type.UserData)
|
else if (assignment.ValueType == Type.UserData)
|
||||||
{
|
{
|
||||||
var ud = assignment.Type.UserData;
|
var ud = assignment.ValueType.UserData;
|
||||||
if (string.IsNullOrEmpty(ud))
|
if (string.IsNullOrEmpty(ud))
|
||||||
{
|
{
|
||||||
variable = new VariableSymbol(name, Type.Unknown, isLocal);
|
variable = new VariableSymbol(name, Type.Unknown, isLocal);
|
||||||
|
@ -508,13 +508,13 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
variable = new VariableSymbol(name, assignment.Type, isLocal);
|
variable = new VariableSymbol(name, assignment.ValueType, isLocal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
variable = new VariableSymbol(name, assignment.Type, isLocal);
|
variable = new VariableSymbol(name, assignment.ValueType, isLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
variable.CommentValue = commentData;
|
variable.CommentValue = commentData;
|
||||||
|
@ -529,26 +529,26 @@ namespace Upsilon.Binder
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// don't allow assigning different typed variables to a variable, unless either of them is nil, allow assigning nil to all variables
|
// don't allow assigning different typed variables to a variable, unless either of them is nil, allow assigning nil to all variables
|
||||||
if (assignment.Type != variable.TypeContainer)
|
if (assignment.ValueType != variable.TypeContainer)
|
||||||
{
|
{
|
||||||
if (variable.TypeContainer == Type.Nil || assignment.Type == Type.Nil)
|
if (variable.TypeContainer == Type.Nil || assignment.ValueType == Type.Nil)
|
||||||
{
|
{
|
||||||
variable.TypeContainer = assignment.Type;
|
variable.TypeContainer = assignment.ValueType;
|
||||||
}
|
}
|
||||||
else if (variable.TypeContainer == Type.Unknown)
|
else if (variable.TypeContainer == Type.Unknown)
|
||||||
{
|
{
|
||||||
variable.TypeContainer = assignment.Type;
|
variable.TypeContainer = assignment.ValueType;
|
||||||
}
|
}
|
||||||
else if (assignment.Type == Type.Unknown && assignment is BoundVariableExpression v)
|
else if (assignment.ValueType == Type.Unknown && assignment is BoundVariableExpression v)
|
||||||
{
|
{
|
||||||
v.Variable.VariableSymbol.TypeContainer = variable.TypeContainer;
|
v.Variable.VariableSymbol.TypeContainer = variable.TypeContainer;
|
||||||
}
|
}
|
||||||
else if (assignment.Type == Type.Unknown)
|
else if (assignment.ValueType == Type.Unknown)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_diagnostics.LogCannotConvert(assignment.Type, variable.TypeContainer, assignment.Span);
|
_diagnostics.LogCannotConvert(assignment.ValueType, variable.TypeContainer, assignment.Span);
|
||||||
return (null, false);
|
return (null, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -615,7 +615,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
Scope = new BoundScope(Scope);
|
Scope = new BoundScope(Scope);
|
||||||
var condition = BindExpressionStatement(e.Condition);
|
var condition = BindExpressionStatement(e.Condition);
|
||||||
if (condition.Expression.Type != Type.Boolean && condition.Expression.Type != Type.Unknown)
|
if (condition.Expression.ValueType != Type.Boolean && condition.Expression.ValueType != Type.Unknown)
|
||||||
{
|
{
|
||||||
_diagnostics.LogError("Condition for if statement should be a boolean.", condition.Span);
|
_diagnostics.LogError("Condition for if statement should be a boolean.", condition.Span);
|
||||||
}
|
}
|
||||||
|
@ -678,7 +678,7 @@ namespace Upsilon.Binder
|
||||||
innerScope.DefineLocalVariable(variableSymbol);
|
innerScope.DefineLocalVariable(variableSymbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameters.All(x => x.Type != Type.Unknown))
|
if (parameters.All(x => x.ValueType != Type.Unknown))
|
||||||
{
|
{
|
||||||
Scope = innerScope;
|
Scope = innerScope;
|
||||||
var block = BindBlockStatement(e.Block);
|
var block = BindBlockStatement(e.Block);
|
||||||
|
@ -770,17 +770,17 @@ namespace Upsilon.Binder
|
||||||
return new BoundReturnStatement(null, e.Span);
|
return new BoundReturnStatement(null, e.Span);
|
||||||
|
|
||||||
var expression = BindExpression(e.Expression);
|
var expression = BindExpression(e.Expression);
|
||||||
if (expression.Type != Type.Unknown && expression.Type != Type.Unknown &&
|
if (expression.ValueType != Type.Unknown && expression.ValueType != Type.Unknown &&
|
||||||
Scope.ReturnType != Type.Unknown && Scope.ReturnType != Type.Nil)
|
Scope.ReturnType != Type.Unknown && Scope.ReturnType != Type.Nil)
|
||||||
{
|
{
|
||||||
if (expression.Type != Scope.ReturnType)
|
if (expression.ValueType != Scope.ReturnType)
|
||||||
{
|
{
|
||||||
_diagnostics.LogError($"Can't return type '{expression.Type}' from this scope, earlier in the" +
|
_diagnostics.LogError($"Can't return type '{expression.ValueType}' from this scope, earlier in the" +
|
||||||
$" scope a return type of '{Scope.ReturnType}' is defined.", e.Span);
|
$" scope a return type of '{Scope.ReturnType}' is defined.", e.Span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (expression.Type != Type.Unknown && expression.Type != Type.Nil)
|
if (expression.ValueType != Type.Unknown && expression.ValueType != Type.Nil)
|
||||||
Scope.ReturnType = expression.Type;
|
Scope.ReturnType = expression.ValueType;
|
||||||
return new BoundReturnStatement(expression, e.Span);
|
return new BoundReturnStatement(expression, e.Span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -800,7 +800,7 @@ namespace Upsilon.Binder
|
||||||
var boundExpression = (BoundExpressionStatement)bound;
|
var boundExpression = (BoundExpressionStatement)bound;
|
||||||
current++;
|
current++;
|
||||||
innerVariables.Add(current.ToString(),
|
innerVariables.Add(current.ToString(),
|
||||||
new VariableSymbol(current.ToString(), boundExpression.Expression.Type, false));
|
new VariableSymbol(current.ToString(), boundExpression.Expression.ValueType, false));
|
||||||
}
|
}
|
||||||
statements.Add(bound);
|
statements.Add(bound);
|
||||||
}
|
}
|
||||||
|
@ -816,7 +816,7 @@ namespace Upsilon.Binder
|
||||||
var expression = BindExpression(e.Expression);
|
var expression = BindExpression(e.Expression);
|
||||||
|
|
||||||
var index = BindExpression(e.Index);
|
var index = BindExpression(e.Index);
|
||||||
switch (expression.Type.Type)
|
switch (expression.ValueType.Type)
|
||||||
{
|
{
|
||||||
case Type.Table:
|
case Type.Table:
|
||||||
if (isAssignment)
|
if (isAssignment)
|
||||||
|
@ -856,7 +856,7 @@ namespace Upsilon.Binder
|
||||||
_diagnostics.LogError($"No variable '{realIndex.Value}' found in table '{realTable.VariableSymbol.Name}'.",
|
_diagnostics.LogError($"No variable '{realIndex.Value}' found in table '{realTable.VariableSymbol.Name}'.",
|
||||||
e.Span);
|
e.Span);
|
||||||
}
|
}
|
||||||
else if (expression.Type is CompositeTypeContainer compositeTypeContainer)
|
else if (expression.ValueType is CompositeTypeContainer compositeTypeContainer)
|
||||||
{
|
{
|
||||||
return new BoundIndexExpression(expression, index, compositeTypeContainer.Types[1], e.Span);
|
return new BoundIndexExpression(expression, index, compositeTypeContainer.Types[1], e.Span);
|
||||||
}
|
}
|
||||||
|
@ -864,10 +864,10 @@ namespace Upsilon.Binder
|
||||||
case Type.UserData:
|
case Type.UserData:
|
||||||
case Type.Unknown:
|
case Type.Unknown:
|
||||||
return new BoundIndexExpression(expression, index, Type.Unknown, e.Span);
|
return new BoundIndexExpression(expression, index, Type.Unknown, e.Span);
|
||||||
case Type.String when index.Type == Type.Number:
|
case Type.String when index.ValueType == Type.Number:
|
||||||
return new BoundIndexExpression(expression, index, Type.String, e.Span);
|
return new BoundIndexExpression(expression, index, Type.String, e.Span);
|
||||||
default:
|
default:
|
||||||
_diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span);
|
_diagnostics.LogInvalidIndexExpression(expression.ValueType, index.ValueType, e.Span);
|
||||||
return new BoundBadExpression(e.Span);
|
return new BoundBadExpression(e.Span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -876,7 +876,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
var expression = BindExpression(e.Expression);
|
var expression = BindExpression(e.Expression);
|
||||||
var index = e.Index.Name;
|
var index = e.Index.Name;
|
||||||
switch (expression.Type.Type)
|
switch (expression.ValueType.Type)
|
||||||
{
|
{
|
||||||
case Type.Table:
|
case Type.Table:
|
||||||
if (isAssignment)
|
if (isAssignment)
|
||||||
|
@ -936,7 +936,7 @@ namespace Upsilon.Binder
|
||||||
case Type.String:
|
case Type.String:
|
||||||
return new BoundFullStopIndexExpression(expression, index, Type.String, e.Span);
|
return new BoundFullStopIndexExpression(expression, index, Type.String, e.Span);
|
||||||
default:
|
default:
|
||||||
_diagnostics.LogInvalidIndexExpression(expression.Type, Type.String, e.Span);
|
_diagnostics.LogInvalidIndexExpression(expression.ValueType, Type.String, e.Span);
|
||||||
return new BoundBadExpression(e.Span);
|
return new BoundBadExpression(e.Span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -964,7 +964,7 @@ namespace Upsilon.Binder
|
||||||
if (variableSymbol is TableVariableSymbol tableVariableSymbol)
|
if (variableSymbol is TableVariableSymbol tableVariableSymbol)
|
||||||
{
|
{
|
||||||
tableVariableSymbol.Variables.Add(index.Value.ToString(),
|
tableVariableSymbol.Variables.Add(index.Value.ToString(),
|
||||||
new VariableSymbol(index.Value.ToString(), value.Type, false));
|
new VariableSymbol(index.Value.ToString(), value.ValueType, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
indexableExpression = indexable;
|
indexableExpression = indexable;
|
||||||
|
@ -979,10 +979,10 @@ namespace Upsilon.Binder
|
||||||
if (indexable.Expression.Kind == BoundKind.VariableExpression)
|
if (indexable.Expression.Kind == BoundKind.VariableExpression)
|
||||||
{
|
{
|
||||||
var variable = (BoundVariableExpression)indexable.Expression;
|
var variable = (BoundVariableExpression)indexable.Expression;
|
||||||
if (variable.Type == Type.Table)
|
if (variable.ValueType == Type.Table)
|
||||||
{
|
{
|
||||||
((TableVariableSymbol)variable.Variable.VariableSymbol).Variables.Add(indexable.Index,
|
((TableVariableSymbol)variable.Variable.VariableSymbol).Variables.Add(indexable.Index,
|
||||||
new VariableSymbol(indexable.Index, value.Type, false));
|
new VariableSymbol(indexable.Index, value.ValueType, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
indexableExpression = indexable;
|
indexableExpression = indexable;
|
||||||
|
@ -1022,7 +1022,7 @@ namespace Upsilon.Binder
|
||||||
|
|
||||||
var valueVar = e.Variables[1];
|
var valueVar = e.Variables[1];
|
||||||
VariableSymbol valueVariable;
|
VariableSymbol valueVariable;
|
||||||
if (boundEnumerableExpression.Type is CompositeTypeContainer composite && composite.Types.Length == 2)
|
if (boundEnumerableExpression.ValueType is CompositeTypeContainer composite && composite.Types.Length == 2)
|
||||||
{
|
{
|
||||||
var keyType = composite.Types[0];
|
var keyType = composite.Types[0];
|
||||||
keyVariable.TypeContainer = keyType;
|
keyVariable.TypeContainer = keyType;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -17,6 +19,10 @@ namespace Upsilon.Binder
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type => BaseTypes.Type.Nil;
|
public override TypeContainer ValueType => BaseTypes.Type.Nil;
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
throw new Exception("Can't evaluate bad syntax.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,19 +1,24 @@
|
||||||
using System.Collections;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.BaseTypes.Number;
|
||||||
|
using Upsilon.BaseTypes.UserData;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
|
using Upsilon.Exceptions;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
public class BoundBinaryExpression : BoundExpression
|
public class BoundBinaryExpression : BoundExpression
|
||||||
{
|
{
|
||||||
public BoundBinaryExpression(BoundBinaryOperator op, BoundExpression leftExpression,
|
public BoundBinaryExpression(BoundBinaryOperator op, BoundExpression leftExpression,
|
||||||
BoundExpression rightExpression, Type type, TextSpan span) : base(span)
|
BoundExpression rightExpression, Type valueType, TextSpan span) : base(span)
|
||||||
{
|
{
|
||||||
Operator = op;
|
Operator = op;
|
||||||
LeftExpression = leftExpression;
|
LeftExpression = leftExpression;
|
||||||
RightExpression = rightExpression;
|
RightExpression = rightExpression;
|
||||||
Type = type;
|
ValueType = valueType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override BoundKind Kind => BoundKind.BoundBinaryExpression;
|
public override BoundKind Kind => BoundKind.BoundBinaryExpression;
|
||||||
|
@ -23,7 +28,161 @@ namespace Upsilon.Binder
|
||||||
yield return RightExpression;
|
yield return RightExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type { get; }
|
public override TypeContainer ValueType { get; }
|
||||||
|
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
if (Operator.Kind == BoundBinaryOperator.OperatorKind.Or)
|
||||||
|
{
|
||||||
|
var l = LeftExpression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (l.Type == Type.Boolean && ((ScriptBoolean)l).Value)
|
||||||
|
return new ScriptBoolean(true);
|
||||||
|
var r = RightExpression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (r.Type == Type.Boolean && ((ScriptBoolean)r).Value)
|
||||||
|
return new ScriptBoolean(true);
|
||||||
|
return new ScriptBoolean(false);
|
||||||
|
}
|
||||||
|
if (Operator.Kind == BoundBinaryOperator.OperatorKind.And)
|
||||||
|
{
|
||||||
|
var l = LeftExpression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (l.Type != Type.Boolean || !((ScriptBoolean)l).Value)
|
||||||
|
return new ScriptBoolean(false);
|
||||||
|
var r = RightExpression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (r.Type != Type.Boolean || !((ScriptBoolean)r).Value)
|
||||||
|
return new ScriptBoolean(false);
|
||||||
|
return new ScriptBoolean(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var left = LeftExpression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
var right = RightExpression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
switch (Operator.Kind)
|
||||||
|
{
|
||||||
|
case BoundBinaryOperator.OperatorKind.Addition:
|
||||||
|
if (left.Type == Type.Number)
|
||||||
|
{
|
||||||
|
if (right.Type == Type.Number)
|
||||||
|
{
|
||||||
|
return ((ScriptNumber)left) + ((ScriptNumber)right);
|
||||||
|
}
|
||||||
|
if (right.Type == Type.String)
|
||||||
|
{
|
||||||
|
return new ScriptString(left + right.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (left.Type == Type.String)
|
||||||
|
{
|
||||||
|
return ((ScriptString) 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;
|
||||||
|
}
|
||||||
|
goto default;
|
||||||
|
case BoundBinaryOperator.OperatorKind.Subtraction:
|
||||||
|
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||||
|
{
|
||||||
|
return ((ScriptNumber)left) - ((ScriptNumber)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;
|
||||||
|
case BoundBinaryOperator.OperatorKind.Multiplication:
|
||||||
|
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||||
|
{
|
||||||
|
return ((ScriptNumber)left) * ((ScriptNumber)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;
|
||||||
|
case BoundBinaryOperator.OperatorKind.Division:
|
||||||
|
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||||
|
{
|
||||||
|
return ((ScriptNumber)left) / ((ScriptNumber)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;
|
||||||
|
case BoundBinaryOperator.OperatorKind.Exponent:
|
||||||
|
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||||
|
{
|
||||||
|
return ScriptNumber.Exponent((ScriptNumber) left, (ScriptNumber) right);
|
||||||
|
}
|
||||||
|
goto default;
|
||||||
|
case BoundBinaryOperator.OperatorKind.Remainder:
|
||||||
|
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||||
|
{
|
||||||
|
return ((ScriptNumber)left) % ((ScriptNumber)right);
|
||||||
|
}
|
||||||
|
else if (left.Type == Type.UserData)
|
||||||
|
{
|
||||||
|
var ud = (GenericUserData) left;
|
||||||
|
var (type, failed) = ud.BinaryOperator(left, OperatorType.Modulo, right);
|
||||||
|
if (failed) goto default;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
goto default;
|
||||||
|
case BoundBinaryOperator.OperatorKind.Equality:
|
||||||
|
return new ScriptBoolean(left.Equals(right));
|
||||||
|
case BoundBinaryOperator.OperatorKind.Inequality:
|
||||||
|
return new ScriptBoolean(!left.Equals(right));
|
||||||
|
case BoundBinaryOperator.OperatorKind.Less:
|
||||||
|
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||||
|
{
|
||||||
|
return ((ScriptNumber) left) < ((ScriptNumber) right);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ScriptRuntimeException(state.Script.FileName,
|
||||||
|
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span,
|
||||||
|
diagnostics.ScriptString.GetSpan(Span));
|
||||||
|
case BoundBinaryOperator.OperatorKind.LessEquals:
|
||||||
|
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||||
|
{
|
||||||
|
return ((ScriptNumber) left) <= ((ScriptNumber) right);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ScriptRuntimeException(state.Script.FileName,
|
||||||
|
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span,
|
||||||
|
diagnostics.ScriptString.GetSpan(Span));
|
||||||
|
case BoundBinaryOperator.OperatorKind.Greater:
|
||||||
|
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||||
|
{
|
||||||
|
return ((ScriptNumber) left) > ((ScriptNumber) right);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ScriptRuntimeException(state.Script.FileName,
|
||||||
|
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span,
|
||||||
|
diagnostics.ScriptString.GetSpan(Span));
|
||||||
|
case BoundBinaryOperator.OperatorKind.GreaterEquals:
|
||||||
|
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||||
|
{
|
||||||
|
return ((ScriptNumber) left) >= ((ScriptNumber) right);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ScriptRuntimeException(state.Script.FileName,
|
||||||
|
$"Can't find operator '{Operator.Kind}' for types '{left.Type}' and '{right.Type}'", Span,
|
||||||
|
diagnostics.ScriptString.GetSpan(Span));
|
||||||
|
default:
|
||||||
|
throw new Exception("Invalid Binary Operator: " + Operator.Kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public BoundBinaryOperator Operator { get; }
|
public BoundBinaryOperator Operator { get; }
|
||||||
public BoundExpression LeftExpression { get; }
|
public BoundExpression LeftExpression { get; }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -9,6 +10,8 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract TypeContainer Type { get; }
|
public abstract TypeContainer ValueType { get; }
|
||||||
|
|
||||||
|
internal abstract ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,9 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.BaseTypes.ScriptFunction;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
|
using Upsilon.Exceptions;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -15,7 +18,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
Identifier = identifier;
|
Identifier = identifier;
|
||||||
Parameters = parameters;
|
Parameters = parameters;
|
||||||
Type = type;
|
ValueType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override BoundKind Kind => BoundKind.BoundFunctionCallExpression;
|
public override BoundKind Kind => BoundKind.BoundFunctionCallExpression;
|
||||||
|
@ -29,6 +32,24 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type { get; }
|
|
||||||
|
public override TypeContainer ValueType { get; }
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
var variable = Identifier.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (!(variable is ScriptFunction function))
|
||||||
|
{
|
||||||
|
throw new EvaluationException(state.Script.FileName, $"Variable is not a function.", Identifier.Span);
|
||||||
|
}
|
||||||
|
var ls = new List<ScriptType>();
|
||||||
|
foreach (var t in Parameters)
|
||||||
|
{
|
||||||
|
var evaluate = t.Evaluate(scope, diagnostics, ref state);
|
||||||
|
ls.Add(evaluate);
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = function.Run(diagnostics, ls.ToArray(), state.Script, scope, Span);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,8 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.BaseTypes.ScriptFunction;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
using Type = Upsilon.BaseTypes.Type;
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
|
@ -32,7 +34,15 @@ namespace Upsilon.Binder
|
||||||
yield return Block;
|
yield return Block;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type => BaseTypes.Type.Function;
|
public override TypeContainer ValueType => BaseTypes.Type.Function;
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
var option = new ScriptRuntimeFunction.ScriptRuntimeFunctionOption(Parameters, Block, scope);
|
||||||
|
var func = new ScriptRuntimeFunction(new List<ScriptRuntimeFunction.ScriptRuntimeFunctionOption>(){option});
|
||||||
|
return func;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public BoundScope Scope { get; set; }
|
public BoundScope Scope { get; set; }
|
||||||
public Type ReturnType { get; }
|
public Type ReturnType { get; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
|
using Upsilon.Exceptions;
|
||||||
using Upsilon.Parser;
|
using Upsilon.Parser;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
|
@ -11,7 +14,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
Identifier = identifier;
|
Identifier = identifier;
|
||||||
Index = index;
|
Index = index;
|
||||||
Type = type;
|
ValueType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoundExpression Identifier { get; }
|
public BoundExpression Identifier { get; }
|
||||||
|
@ -25,7 +28,30 @@ namespace Upsilon.Binder
|
||||||
yield return Index;
|
yield return Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type { get; }
|
public override TypeContainer ValueType { get; }
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
var variable = Identifier.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (variable.Type == Type.Nil)
|
||||||
|
{
|
||||||
|
throw new EvaluationException(state.Script.FileName, $"Nil variable can't be indexed", Span);
|
||||||
|
}
|
||||||
|
if (!(variable is IIndexable indexable))
|
||||||
|
{
|
||||||
|
throw new EvaluationException(state.Script.FileName,
|
||||||
|
$"Variable of type '{variable.Type}' is not indexable.", Span);
|
||||||
|
}
|
||||||
|
|
||||||
|
var innerScope = scope;
|
||||||
|
if (variable is IScopeOwner scopeOwner)
|
||||||
|
{
|
||||||
|
innerScope = scopeOwner.EvaluationScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
var indexer = Index.Evaluate(scope, diagnostics, ref state);
|
||||||
|
return indexable.Get(diagnostics, Span, indexer, innerScope);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundFullStopIndexExpression : BoundExpression
|
public class BoundFullStopIndexExpression : BoundExpression
|
||||||
|
@ -37,7 +63,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
Expression = expression;
|
Expression = expression;
|
||||||
Index = index;
|
Index = index;
|
||||||
Type = type;
|
ValueType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override BoundKind Kind => BoundKind.BoundFullstopIndexExpression;
|
public override BoundKind Kind => BoundKind.BoundFullstopIndexExpression;
|
||||||
|
@ -47,6 +73,28 @@ namespace Upsilon.Binder
|
||||||
yield return Expression;
|
yield return Expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type { get; }
|
public override TypeContainer ValueType { get; }
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
var variable = Expression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (variable.Type == Type.Nil)
|
||||||
|
{
|
||||||
|
throw new EvaluationException(state.Script.FileName, $"Nil variable can't be indexed", Span);
|
||||||
|
}
|
||||||
|
if (!(variable is IIndexable indexable))
|
||||||
|
{
|
||||||
|
throw new EvaluationException(state.Script.FileName,
|
||||||
|
$"Variable of type '{variable.Type}' is not indexable.", Span);
|
||||||
|
}
|
||||||
|
|
||||||
|
var innerScope = scope;
|
||||||
|
if (variable is IScopeOwner scopeOwner)
|
||||||
|
{
|
||||||
|
innerScope = scopeOwner.EvaluationScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
return indexable.Get(diagnostics, Span, Index.ToScriptType(), innerScope);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -18,7 +19,12 @@ namespace Upsilon.Binder
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type => Value.Type;
|
public override TypeContainer ValueType => Value.Type;
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
public ScriptType Value { get; }
|
public ScriptType Value { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.BaseTypes.ScriptTable;
|
||||||
using Upsilon.Binder.VariableSymbols;
|
using Upsilon.Binder.VariableSymbols;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
using Type = Upsilon.BaseTypes.Type;
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
|
@ -24,7 +26,7 @@ namespace Upsilon.Binder
|
||||||
return Statements;
|
return Statements;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type
|
public override TypeContainer ValueType
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@ -38,10 +40,10 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
if (valueType == null)
|
if (valueType == null)
|
||||||
{
|
{
|
||||||
valueType = exp.Expression.Type;
|
valueType = exp.Expression.ValueType;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (valueType == exp.Expression.Type) continue;
|
if (valueType == exp.Expression.ValueType) continue;
|
||||||
valueType = BaseTypes.Type.Unknown;
|
valueType = BaseTypes.Type.Unknown;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -55,6 +57,51 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope outerScope, Diagnostics diagnostics, ref EvaluationState outerState)
|
||||||
|
{
|
||||||
|
var tableScope = EvaluationScope.CreateWithGetOnlyParent(outerScope);
|
||||||
|
var innerState = new EvaluationState()
|
||||||
|
{
|
||||||
|
Script = outerState.Script
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var currentPos = 1;
|
||||||
|
var isNumerated = true;
|
||||||
|
foreach (var boundStatement in Statements)
|
||||||
|
{
|
||||||
|
switch (boundStatement.Kind)
|
||||||
|
{
|
||||||
|
case BoundKind.BoundAssignmentStatement:
|
||||||
|
case BoundKind.BoundFunctionExpression:
|
||||||
|
case BoundKind.BoundFunctionAssignmentStatement:
|
||||||
|
boundStatement.Evaluate(tableScope, diagnostics, ref innerState);
|
||||||
|
isNumerated = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
boundStatement.Evaluate(tableScope, diagnostics, ref innerState);
|
||||||
|
if (innerState.LastValue != null)
|
||||||
|
{
|
||||||
|
tableScope.CreateLocal(new VariableSymbol(currentPos.ToString(), innerState.LastValue.Type, false),
|
||||||
|
innerState.LastValue);
|
||||||
|
}
|
||||||
|
innerState.LastValue = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumerated)
|
||||||
|
{
|
||||||
|
return new NumeratedScriptTable(tableScope);
|
||||||
|
}
|
||||||
|
return new GenericKeyedScriptTable(tableScope);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Dictionary<string, VariableSymbol> Expressions { get; }
|
public Dictionary<string, VariableSymbol> Expressions { get; }
|
||||||
public ImmutableArray<BoundStatement> Statements { get; }
|
public ImmutableArray<BoundStatement> Statements { get; }
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.BaseTypes.Number;
|
||||||
|
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||||
|
using Upsilon.BaseTypes.UserData;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
|
using Upsilon.Exceptions;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -13,13 +18,53 @@ namespace Upsilon.Binder
|
||||||
yield return InExpression;
|
yield return InExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type { get; }
|
public override TypeContainer ValueType { get; }
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
var operand = InExpression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
switch (Operator.Kind)
|
||||||
|
{
|
||||||
|
case BoundUnaryOperator.OperatorKind.Identity:
|
||||||
|
return operand;
|
||||||
|
case BoundUnaryOperator.OperatorKind.Negation:
|
||||||
|
if (operand.Type == Type.Number)
|
||||||
|
return -((ScriptNumber)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;
|
||||||
|
case BoundUnaryOperator.OperatorKind.LogicalNegation:
|
||||||
|
if (operand.Type == Type.Boolean)
|
||||||
|
return !(ScriptBoolean) 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;
|
||||||
|
case BoundUnaryOperator.OperatorKind.Length:
|
||||||
|
if (operand is ILengthType length)
|
||||||
|
{
|
||||||
|
return length.Length();
|
||||||
|
}
|
||||||
|
goto default;
|
||||||
|
default:
|
||||||
|
throw new EvaluationException(state.Script.FileName, "Invalid Unary Operator: " + Operator.Kind, Span);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public BoundUnaryExpression(BoundUnaryOperator op, BoundExpression inExpression, Type type, TextSpan span) : base(span)
|
public BoundUnaryExpression(BoundUnaryOperator op, BoundExpression inExpression, Type type, TextSpan span) : base(span)
|
||||||
{
|
{
|
||||||
Operator = op;
|
Operator = op;
|
||||||
InExpression = inExpression;
|
InExpression = inExpression;
|
||||||
Type = type;
|
ValueType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoundExpression InExpression { get; }
|
public BoundExpression InExpression { get; }
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
|
using Upsilon.Exceptions;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
using Type = Upsilon.BaseTypes.Type;
|
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
|
@ -21,6 +22,10 @@ namespace Upsilon.Binder
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type => Variable.Type;
|
public override TypeContainer ValueType => Variable.ValueType;
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
return Variable.Evaluate(scope, diagnostics, ref state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -20,5 +20,17 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableArray<BoundStatement> Statements { get; }
|
public ImmutableArray<BoundStatement> Statements { get; }
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
foreach (var statement in Statements)
|
||||||
|
{
|
||||||
|
statement.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (state.Returned)
|
||||||
|
return;
|
||||||
|
if (state.HasBroken)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -15,5 +16,10 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
state.HasBroken = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -17,5 +18,11 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
Expression = expression;
|
Expression = expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
var value = Expression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
state.LastValue = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.BaseTypes.ScriptFunction;
|
||||||
using Upsilon.Binder.VariableSymbols;
|
using Upsilon.Binder.VariableSymbols;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -21,5 +23,33 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
yield return Func;
|
yield return Func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
var func = (ScriptRuntimeFunction)Func.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (Variable.Local)
|
||||||
|
{
|
||||||
|
if (scope.Variables.TryGetValue(Variable.Name, out var f) && f is ScriptRuntimeFunction scriptRuntimeFunction)
|
||||||
|
{
|
||||||
|
scriptRuntimeFunction.AddOption(func.Options[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scope.CreateLocal(Variable, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (scope.TryGet(Variable, out var f) && f is ScriptRuntimeFunction scriptRuntimeFunction)
|
||||||
|
{
|
||||||
|
scriptRuntimeFunction.AddOption(func.Options[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scope.AssignToNearest(Variable, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,11 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Upsilon.Binder.VariableSymbols;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
using Type = System.Type;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
|
@ -30,5 +34,52 @@ namespace Upsilon.Binder
|
||||||
yield return BoundEnumerableExpression;
|
yield return BoundEnumerableExpression;
|
||||||
yield return Block;
|
yield return Block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope outerScope, Diagnostics diagnostics, ref EvaluationState outerState)
|
||||||
|
{
|
||||||
|
var innerScope = new EvaluationScope(outerScope);
|
||||||
|
var innerState = new EvaluationState()
|
||||||
|
{
|
||||||
|
Script = outerState.Script,
|
||||||
|
};
|
||||||
|
|
||||||
|
var enumeratorObject = BoundEnumerableExpression.Evaluate(outerScope, diagnostics, ref innerState);
|
||||||
|
if (!(enumeratorObject is IIterable iterable))
|
||||||
|
{
|
||||||
|
throw new Exception($"Can't iterate over object with type '{enumeratorObject.Type}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var enumerator = iterable.GetScriptEnumerator())
|
||||||
|
{
|
||||||
|
while (enumerator.MoveNext())
|
||||||
|
{
|
||||||
|
var current = enumerator.Current;
|
||||||
|
if (current == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Can't assign result value of nothing to multiple values");
|
||||||
|
}
|
||||||
|
if (current.Type != BaseTypes.Type.Table)
|
||||||
|
{
|
||||||
|
throw new Exception($"Can't assign result value with type '{current.Type}' to multiple values");
|
||||||
|
}
|
||||||
|
|
||||||
|
var table = (SimpleScriptTable)current;
|
||||||
|
if (Variables[0].VariableSymbol.Name != "_")
|
||||||
|
innerScope.CreateLocal(Variables[0].VariableSymbol, table[0].ToScriptType());
|
||||||
|
if (Variables[1].VariableSymbol.Name != "_")
|
||||||
|
innerScope.CreateLocal(Variables[1].VariableSymbol, table[1]);
|
||||||
|
Block.Evaluate(innerScope, diagnostics, ref innerState);
|
||||||
|
if (innerState.HasBroken || innerState.Returned)
|
||||||
|
{
|
||||||
|
if (innerState.Returned)
|
||||||
|
{
|
||||||
|
outerState.Returned = true;
|
||||||
|
outerState.ReturnValue = innerState.ReturnValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -37,6 +39,24 @@ namespace Upsilon.Binder
|
||||||
public BoundBlockStatement Block { get; }
|
public BoundBlockStatement Block { get; }
|
||||||
public BoundIfStatement NextElseIf { get; }
|
public BoundIfStatement NextElseIf { get; }
|
||||||
public BoundElseStatement ElseStatement { get; }
|
public BoundElseStatement ElseStatement { get; }
|
||||||
|
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
var condition = Condition.Expression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if ((ScriptBoolean) condition)
|
||||||
|
{
|
||||||
|
Block.Evaluate(scope, diagnostics, ref state);
|
||||||
|
}
|
||||||
|
else if (NextElseIf != null)
|
||||||
|
{
|
||||||
|
NextElseIf.Evaluate(scope, diagnostics, ref state);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ElseStatement?.Evaluate(scope, diagnostics, ref state);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundElseStatement : BoundStatement
|
public class BoundElseStatement : BoundStatement
|
||||||
|
@ -54,5 +74,10 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
yield return Block;
|
yield return Block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
Block.Evaluate(scope, diagnostics, ref state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,9 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using Upsilon.BaseTypes.Number;
|
||||||
|
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||||
using Upsilon.Binder.VariableSymbols;
|
using Upsilon.Binder.VariableSymbols;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -23,5 +26,31 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
yield return Assignment;
|
yield return Assignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
var val = Assignment.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (val is IIndexable table)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < Variables.Length; i++)
|
||||||
|
{
|
||||||
|
var variableSymbol = Variables[i];
|
||||||
|
if (variableSymbol == null)
|
||||||
|
continue;
|
||||||
|
if (variableSymbol.Name == "_")
|
||||||
|
continue;
|
||||||
|
var value = table.Get(diagnostics, Span, new ScriptNumberLong(i + 1), scope);
|
||||||
|
if (variableSymbol.Local)
|
||||||
|
scope.CreateLocal(variableSymbol, value);
|
||||||
|
else
|
||||||
|
scope.AssignToNearest(variableSymbol, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
diagnostics.LogError($"Can't assign type '{val.Type}' to multiple variables.", Span);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.BaseTypes.Number;
|
||||||
using Upsilon.Binder.VariableSymbols;
|
using Upsilon.Binder.VariableSymbols;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -31,5 +33,56 @@ namespace Upsilon.Binder
|
||||||
yield return BoundStep;
|
yield return BoundStep;
|
||||||
yield return Block;
|
yield return Block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope outerScope, Diagnostics diagnostics, ref EvaluationState outerState)
|
||||||
|
{
|
||||||
|
var innerScope = new EvaluationScope(outerScope);
|
||||||
|
var innerState = new EvaluationState()
|
||||||
|
{
|
||||||
|
Script = outerState.Script,
|
||||||
|
};
|
||||||
|
|
||||||
|
var startVal = (ScriptNumberLong) BoundStart.Evaluate(innerScope, diagnostics, ref innerState);
|
||||||
|
innerScope.CreateLocal(Variable, startVal);
|
||||||
|
var stopVal = (ScriptNumberLong)BoundStop.Evaluate(innerScope, diagnostics, ref innerState);
|
||||||
|
long step = 1;
|
||||||
|
if (BoundStep != null)
|
||||||
|
{
|
||||||
|
var stepVal = (ScriptNumberLong) BoundStep.Evaluate(innerScope, diagnostics, ref innerState);
|
||||||
|
step = stepVal.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step > 0)
|
||||||
|
{
|
||||||
|
for (; startVal.Value <= stopVal.Value; startVal.Value = startVal.Value + step)
|
||||||
|
{
|
||||||
|
Block.Evaluate(innerScope, diagnostics, ref innerState);
|
||||||
|
if (innerState.HasBroken)
|
||||||
|
break;
|
||||||
|
if (innerState.Returned)
|
||||||
|
{
|
||||||
|
outerState.Returned = true;
|
||||||
|
outerState.ReturnValue = innerState.ReturnValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (step < 0)
|
||||||
|
{
|
||||||
|
for (; startVal.Value >= stopVal.Value; startVal.Value = startVal.Value + step)
|
||||||
|
{
|
||||||
|
Block.Evaluate(innerScope, diagnostics, ref innerState);
|
||||||
|
if (innerState.HasBroken)
|
||||||
|
break;
|
||||||
|
if (innerState.Returned)
|
||||||
|
{
|
||||||
|
outerState.Returned = true;
|
||||||
|
outerState.ReturnValue = innerState.ReturnValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
public class BoundReturnStatement : BoundStatement
|
public class BoundReturnStatement : BoundStatement
|
||||||
{
|
{
|
||||||
public BoundReturnStatement(BoundExpression expression, TextSpan span) : base(span)
|
public BoundReturnStatement(BoundExpression expression, TextSpan span) : base(span)
|
||||||
{
|
{
|
||||||
|
@ -17,5 +18,12 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
yield return Expression;
|
yield return Expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
state.ReturnValue = Expression?.Evaluate(scope, diagnostics, ref state);
|
||||||
|
state.Returned = true;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,5 +26,10 @@ namespace Upsilon.Binder
|
||||||
|
|
||||||
public BoundBlockStatement Statement { get; }
|
public BoundBlockStatement Statement { get; }
|
||||||
public BoundScope Scope { get; }
|
public BoundScope Scope { get; }
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
Statement.Evaluate(scope, diagnostics, ref state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -9,5 +10,7 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool HasBreakpoint { get; set; }
|
internal bool HasBreakpoint { get; set; }
|
||||||
|
|
||||||
|
internal abstract void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,8 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -22,5 +26,30 @@ namespace Upsilon.Binder
|
||||||
yield return TableIndexExpression;
|
yield return TableIndexExpression;
|
||||||
yield return Value;
|
yield return Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
ScriptType table;
|
||||||
|
ScriptType index;
|
||||||
|
if (TableIndexExpression.Kind == BoundKind.BoundIndexExpression)
|
||||||
|
{
|
||||||
|
var indexExpression = (BoundIndexExpression)TableIndexExpression;
|
||||||
|
table = indexExpression.Identifier.Evaluate(scope, diagnostics, ref state);
|
||||||
|
index = indexExpression.Index.Evaluate(scope, diagnostics, ref state);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var fullStopIndexExpression = (BoundFullStopIndexExpression) TableIndexExpression;
|
||||||
|
table = fullStopIndexExpression.Expression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
index = fullStopIndexExpression.Index.ToScriptType();
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = Value.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (!(table is IIndexable indexable))
|
||||||
|
{
|
||||||
|
throw new Exception("Cant assign to that");
|
||||||
|
}
|
||||||
|
indexable.Set(diagnostics, Span, index.ToString().ToScriptType(), value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -23,5 +24,19 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
yield return BoundExpression;
|
yield return BoundExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
var val = BoundExpression.Evaluate(scope, diagnostics, ref state);
|
||||||
|
if (IsLocalDefinition)
|
||||||
|
{
|
||||||
|
scope.CreateLocal(Variable.VariableSymbol, val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scope.AssignToNearest(Variable.VariableSymbol, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -23,5 +24,30 @@ namespace Upsilon.Binder
|
||||||
yield return Condition;
|
yield return Condition;
|
||||||
yield return Block;
|
yield return Block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Evaluate(EvaluationScope outerScope, Diagnostics diagnostics, ref EvaluationState outerState)
|
||||||
|
{
|
||||||
|
var innerScope = new EvaluationScope(outerScope);
|
||||||
|
var innerState = new EvaluationState()
|
||||||
|
{
|
||||||
|
Script = outerState.Script
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
while ((ScriptBoolean) Condition.Evaluate(innerScope, diagnostics, ref innerState))
|
||||||
|
{
|
||||||
|
Block.Evaluate(innerScope, diagnostics, ref innerState);
|
||||||
|
if (innerState.HasBroken || innerState.Returned)
|
||||||
|
{
|
||||||
|
if (innerState.Returned)
|
||||||
|
{
|
||||||
|
outerState.Returned = true;
|
||||||
|
outerState.ReturnValue = innerState.ReturnValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
using Upsilon.Binder.VariableSymbols;
|
using Upsilon.Binder.VariableSymbols;
|
||||||
|
using Upsilon.Evaluator;
|
||||||
|
using Upsilon.Exceptions;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
namespace Upsilon.Binder
|
||||||
|
@ -27,6 +29,18 @@ namespace Upsilon.Binder
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TypeContainer Type => VariableSymbol.TypeContainer;
|
public override TypeContainer ValueType => VariableSymbol.TypeContainer;
|
||||||
|
|
||||||
|
|
||||||
|
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
|
||||||
|
{
|
||||||
|
if (scope.TryGet(VariableSymbol, out var val))
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new EvaluationException(state.Script.FileName, $"Cannot find variable: '{VariableSymbol.Name}'",
|
||||||
|
Span);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,14 +36,14 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
{
|
{
|
||||||
var functionParameter = option.FunctionParameters[i];
|
var functionParameter = option.FunctionParameters[i];
|
||||||
var callingParameter = callingParameters[i];
|
var callingParameter = callingParameters[i];
|
||||||
if (callingParameter.Type == Type.Unknown || callingParameter.Type == Type.Nil)
|
if (callingParameter.ValueType == Type.Unknown || callingParameter.ValueType == Type.Nil)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (functionParameter.ValidTypes == Type.Unknown)
|
if (functionParameter.ValidTypes == Type.Unknown)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!functionParameter.ValidTypes.Type.HasFlag(callingParameter.Type))
|
if (!functionParameter.ValidTypes.Type.HasFlag(callingParameter.ValueType))
|
||||||
{
|
{
|
||||||
isValid = false;
|
isValid = false;
|
||||||
break;
|
break;
|
||||||
|
@ -85,7 +85,7 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
{
|
{
|
||||||
var functionParameter = option.FunctionParameters[i];
|
var functionParameter = option.FunctionParameters[i];
|
||||||
var callingParameter = parameters[i];
|
var callingParameter = parameters[i];
|
||||||
if (!functionParameter.ValidTypes.Type.HasFlag(callingParameter.Type))
|
if (!functionParameter.ValidTypes.Type.HasFlag(callingParameter.ValueType))
|
||||||
{
|
{
|
||||||
isValid = false;
|
isValid = false;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -27,11 +27,11 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
var functionParameter = option.Parameters[i];
|
var functionParameter = option.Parameters[i];
|
||||||
var callingParameter = callingParameters[i];
|
var callingParameter = callingParameters[i];
|
||||||
if (functionParameter.TypeContainer == Type.Unknown ||
|
if (functionParameter.TypeContainer == Type.Unknown ||
|
||||||
callingParameter.Type == Type.Unknown ||
|
callingParameter.ValueType == Type.Unknown ||
|
||||||
callingParameter.Type == Type.Nil)
|
callingParameter.ValueType == Type.Nil)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!functionParameter.TypeContainer.Type.HasFlag(callingParameter.Type))
|
if (!functionParameter.TypeContainer.Type.HasFlag(callingParameter.ValueType))
|
||||||
{
|
{
|
||||||
isValid = false;
|
isValid = false;
|
||||||
break;
|
break;
|
||||||
|
@ -46,7 +46,7 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
if (string.IsNullOrEmpty(userData))
|
if (string.IsNullOrEmpty(userData))
|
||||||
continue;
|
continue;
|
||||||
if (!string.Equals(userData,
|
if (!string.Equals(userData,
|
||||||
callingParameter.Type.UserData))
|
callingParameter.ValueType.UserData))
|
||||||
{
|
{
|
||||||
isValid = false;
|
isValid = false;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -242,11 +242,11 @@ namespace Upsilon.BoundTypes
|
||||||
{
|
{
|
||||||
var functionParameter = Parameters[i];
|
var functionParameter = Parameters[i];
|
||||||
var callingParameter = callingParameters[i];
|
var callingParameter = callingParameters[i];
|
||||||
if (callingParameter.Type == Type.Unknown || callingParameter.Type == Type.Nil ||
|
if (callingParameter.ValueType == Type.Unknown || callingParameter.ValueType == Type.Nil ||
|
||||||
functionParameter.Type == Type.Unknown)
|
functionParameter.Type == Type.Unknown)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!functionParameter.Type.Type.HasFlag(callingParameter.Type))
|
if (!functionParameter.Type.Type.HasFlag(callingParameter.ValueType))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
|
|
||||||
|
namespace Upsilon.Evaluator
|
||||||
|
{
|
||||||
|
internal struct EvaluationState
|
||||||
|
{
|
||||||
|
public Script Script;
|
||||||
|
public bool Returned;
|
||||||
|
public bool HasBroken;
|
||||||
|
public ScriptType ReturnValue;
|
||||||
|
public ScriptType LastValue;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
using Upsilon.BaseTypes.Number;
|
|
||||||
using Upsilon.BaseTypes.ScriptFunction;
|
using Upsilon.BaseTypes.ScriptFunction;
|
||||||
using Upsilon.BaseTypes.ScriptTable;
|
|
||||||
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
|
||||||
using Upsilon.BaseTypes.UserData;
|
|
||||||
using Upsilon.Binder;
|
using Upsilon.Binder;
|
||||||
using Upsilon.Binder.VariableSymbols;
|
|
||||||
using Upsilon.Evaluator.Debugging;
|
using Upsilon.Evaluator.Debugging;
|
||||||
using Upsilon.Exceptions;
|
using Upsilon.Exceptions;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
@ -18,22 +11,11 @@ using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
namespace Upsilon.Evaluator
|
namespace Upsilon.Evaluator
|
||||||
{
|
{
|
||||||
internal class Evaluator : IDisposable
|
internal class Evaluator
|
||||||
{
|
{
|
||||||
private readonly Script _script;
|
private readonly Script _script;
|
||||||
private Diagnostics _diagnostics;
|
private Diagnostics _diagnostics;
|
||||||
private ScriptType _lastValue;
|
|
||||||
private ScriptType _returnValue;
|
|
||||||
internal EvaluationScope Scope { get; private set; }
|
internal EvaluationScope Scope { get; private set; }
|
||||||
private bool HasReturned { get; set; }
|
|
||||||
private bool HasBroken { get; set; }
|
|
||||||
|
|
||||||
internal Evaluator(Diagnostics diagnostics, Dictionary<string, ScriptType> variables, Script script)
|
|
||||||
{
|
|
||||||
_diagnostics = diagnostics;
|
|
||||||
_script = script;
|
|
||||||
Scope = new EvaluationScope(variables);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Evaluator(Diagnostics diagnostics, EvaluationScope parentScope, Script script)
|
internal Evaluator(Diagnostics diagnostics, EvaluationScope parentScope, Script script)
|
||||||
{
|
{
|
||||||
|
@ -52,13 +34,6 @@ namespace Upsilon.Evaluator
|
||||||
return new Evaluator(script) {_diagnostics = diagnostics, Scope = scope};
|
return new Evaluator(script) {_diagnostics = diagnostics, Scope = scope};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Scope.Dispose();
|
|
||||||
_lastValue = null;
|
|
||||||
_returnValue = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScriptType Evaluate(BoundScript e)
|
public ScriptType Evaluate(BoundScript e)
|
||||||
{
|
{
|
||||||
if (DebugSession.DebuggerAttached && !string.IsNullOrWhiteSpace(e.FileName))
|
if (DebugSession.DebuggerAttached && !string.IsNullOrWhiteSpace(e.FileName))
|
||||||
|
@ -73,10 +48,15 @@ namespace Upsilon.Evaluator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EvaluateNode(e.Statement);
|
|
||||||
if (_returnValue == null)
|
var evaluationState = new EvaluationState()
|
||||||
return _lastValue;
|
{
|
||||||
return _returnValue;
|
Script = _script
|
||||||
|
};
|
||||||
|
e.Evaluate(Scope, _diagnostics, ref evaluationState);
|
||||||
|
if (evaluationState.ReturnValue != null)
|
||||||
|
return evaluationState.ReturnValue;
|
||||||
|
return evaluationState.LastValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptType Evaluate(BoundScript e, string functionName, object[] parameters)
|
public ScriptType Evaluate(BoundScript e, string functionName, object[] parameters)
|
||||||
|
@ -102,684 +82,5 @@ namespace Upsilon.Evaluator
|
||||||
var result = option.Run(_diagnostics, parameters?.Select(x => x.ToScriptType()).ToArray(), _script, Scope, new TextSpan());
|
var result = option.Run(_diagnostics, parameters?.Select(x => x.ToScriptType()).ToArray(), _script, Scope, new TextSpan());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ScriptType EvaluateNode(BoundNode b)
|
|
||||||
{
|
|
||||||
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:
|
|
||||||
case BoundKind.BoundTableExpression:
|
|
||||||
case BoundKind.BoundIndexExpression:
|
|
||||||
case BoundKind.BoundFullstopIndexExpression:
|
|
||||||
_lastValue = EvaluateExpression((BoundExpression) b);
|
|
||||||
break;
|
|
||||||
case BoundKind.BoundAssignmentStatement:
|
|
||||||
case BoundKind.BoundExpressionStatement:
|
|
||||||
case BoundKind.BoundBlockStatement:
|
|
||||||
case BoundKind.BoundIfStatement:
|
|
||||||
case BoundKind.BoundElseStatement:
|
|
||||||
case BoundKind.BoundFunctionAssignmentStatement:
|
|
||||||
case BoundKind.BoundPromise:
|
|
||||||
case BoundKind.BoundReturnStatement:
|
|
||||||
case BoundKind.BoundTableAssigmentStatement:
|
|
||||||
case BoundKind.BoundMultiAssignmentStatement:
|
|
||||||
case BoundKind.BoundNumericForStatement:
|
|
||||||
case BoundKind.BoundGenericForStatement:
|
|
||||||
case BoundKind.BoundBreakStatement:
|
|
||||||
case BoundKind.BoundWhileStatement:
|
|
||||||
EvaluateStatement((BoundStatement) b);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
return _returnValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateStatement(BoundStatement e)
|
|
||||||
{
|
|
||||||
if (HasReturned)
|
|
||||||
return;
|
|
||||||
switch (e.Kind)
|
|
||||||
{
|
|
||||||
case BoundKind.BoundAssignmentStatement:
|
|
||||||
EvaluateAssignmentStatement((BoundVariableAssignment) e);
|
|
||||||
break;
|
|
||||||
case BoundKind.BoundBlockStatement:
|
|
||||||
EvaluateBoundBlockStatement((BoundBlockStatement) e);
|
|
||||||
break;
|
|
||||||
case BoundKind.BoundIfStatement:
|
|
||||||
EvaluateBoundIfStatement((BoundIfStatement) e);
|
|
||||||
break;
|
|
||||||
case BoundKind.BoundReturnStatement:
|
|
||||||
EvaluateReturnStatement((BoundReturnStatement) e);
|
|
||||||
break;
|
|
||||||
case BoundKind.BoundFunctionAssignmentStatement:
|
|
||||||
EvaluateBoundFunctionAssigmentStatement((BoundFunctionAssignmentStatement) e);
|
|
||||||
break;
|
|
||||||
case BoundKind.BoundTableAssigmentStatement:
|
|
||||||
EvaluateTableAssignmentStatement((BoundTableAssigmentStatement) e);
|
|
||||||
break;
|
|
||||||
case BoundKind.BoundMultiAssignmentStatement:
|
|
||||||
EvaluateMultiAssignmentStatement((BoundMultiAssignmentStatement) e);
|
|
||||||
break;
|
|
||||||
case BoundKind.BoundNumericForStatement:
|
|
||||||
EvaluateNumericForStatement((BoundNumericForStatement) e);
|
|
||||||
break;
|
|
||||||
case BoundKind.BoundBreakStatement:
|
|
||||||
HasBroken = true;
|
|
||||||
return;
|
|
||||||
case BoundKind.BoundGenericForStatement:
|
|
||||||
EvaluateGenericForStatement((BoundGenericForStatement) e);
|
|
||||||
break;
|
|
||||||
case BoundKind.BoundWhileStatement:
|
|
||||||
EvaluateWhileStatement((BoundWhileStatement) e);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
EvaluateExpressionStatement((BoundExpressionStatement) e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void EvaluateExpressionStatement(BoundExpressionStatement e)
|
|
||||||
{
|
|
||||||
_lastValue = EvaluateExpression(e.Expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal ScriptType EvaluateExpression(BoundExpression e)
|
|
||||||
{
|
|
||||||
switch (e.Kind)
|
|
||||||
{
|
|
||||||
case BoundKind.BoundLiteralExpression:
|
|
||||||
return ((BoundLiteralExpression) e).Value;
|
|
||||||
case BoundKind.BoundBinaryExpression:
|
|
||||||
return EvaluateBinaryExpression((BoundBinaryExpression) e);
|
|
||||||
case BoundKind.BoundUnaryExpression:
|
|
||||||
return EvaluateUnaryExpression((BoundUnaryExpression) e);
|
|
||||||
case BoundKind.VariableExpression:
|
|
||||||
return EvaluateVariableExpression((BoundVariableExpression) e);
|
|
||||||
case BoundKind.BoundFunctionCallExpression:
|
|
||||||
return EvaluateBoundFunctionCallExpression((BoundFunctionCallExpression) e);
|
|
||||||
case BoundKind.BoundTableExpression:
|
|
||||||
return EvaluateTableExpression((BoundTableExpression) e);
|
|
||||||
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);
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException(e.Kind.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScriptType EvaluateUnaryExpression(BoundUnaryExpression e)
|
|
||||||
{
|
|
||||||
var operand = EvaluateExpression(e.InExpression);
|
|
||||||
switch (e.Operator.Kind)
|
|
||||||
{
|
|
||||||
case BoundUnaryOperator.OperatorKind.Identity:
|
|
||||||
return operand;
|
|
||||||
case BoundUnaryOperator.OperatorKind.Negation:
|
|
||||||
if (operand.Type == Type.Number)
|
|
||||||
return -((ScriptNumber)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;
|
|
||||||
case BoundUnaryOperator.OperatorKind.LogicalNegation:
|
|
||||||
if (operand.Type == Type.Boolean)
|
|
||||||
return !(ScriptBoolean) 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;
|
|
||||||
case BoundUnaryOperator.OperatorKind.Length:
|
|
||||||
if (operand is ILengthType length)
|
|
||||||
{
|
|
||||||
return length.Length();
|
|
||||||
}
|
|
||||||
goto default;
|
|
||||||
default:
|
|
||||||
throw new EvaluationException(_script.FileName, "Invalid Unary Operator: " + e.Operator.Kind, e.Span);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScriptType EvaluateBinaryExpression(BoundBinaryExpression e)
|
|
||||||
{
|
|
||||||
if (e.Operator.Kind == BoundBinaryOperator.OperatorKind.Or)
|
|
||||||
{
|
|
||||||
var l = EvaluateExpression(e.LeftExpression);
|
|
||||||
if (l.Type == Type.Boolean && ((ScriptBoolean)l).Value)
|
|
||||||
return new ScriptBoolean(true);
|
|
||||||
var r = EvaluateExpression(e.RightExpression);
|
|
||||||
if (r.Type == Type.Boolean && ((ScriptBoolean)r).Value)
|
|
||||||
return new ScriptBoolean(true);
|
|
||||||
return new ScriptBoolean(false);
|
|
||||||
}
|
|
||||||
if (e.Operator.Kind == BoundBinaryOperator.OperatorKind.And)
|
|
||||||
{
|
|
||||||
var l = EvaluateExpression(e.LeftExpression);
|
|
||||||
if (l.Type != Type.Boolean || !((ScriptBoolean)l).Value)
|
|
||||||
return new ScriptBoolean(false);
|
|
||||||
var r = EvaluateExpression(e.RightExpression);
|
|
||||||
if (r.Type != Type.Boolean || !((ScriptBoolean)r).Value)
|
|
||||||
return new ScriptBoolean(false);
|
|
||||||
return new ScriptBoolean(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
var left = EvaluateExpression(e.LeftExpression);
|
|
||||||
var right = EvaluateExpression(e.RightExpression);
|
|
||||||
switch (e.Operator.Kind)
|
|
||||||
{
|
|
||||||
case BoundBinaryOperator.OperatorKind.Addition:
|
|
||||||
if (left.Type == Type.Number)
|
|
||||||
{
|
|
||||||
if (right.Type == Type.Number)
|
|
||||||
{
|
|
||||||
return ((ScriptNumber)left) + ((ScriptNumber)right);
|
|
||||||
}
|
|
||||||
if (right.Type == Type.String)
|
|
||||||
{
|
|
||||||
return new ScriptString(left + right.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (left.Type == Type.String)
|
|
||||||
{
|
|
||||||
return ((ScriptString) 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;
|
|
||||||
}
|
|
||||||
goto default;
|
|
||||||
case BoundBinaryOperator.OperatorKind.Subtraction:
|
|
||||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
|
||||||
{
|
|
||||||
return ((ScriptNumber)left) - ((ScriptNumber)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;
|
|
||||||
case BoundBinaryOperator.OperatorKind.Multiplication:
|
|
||||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
|
||||||
{
|
|
||||||
return ((ScriptNumber)left) * ((ScriptNumber)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;
|
|
||||||
case BoundBinaryOperator.OperatorKind.Division:
|
|
||||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
|
||||||
{
|
|
||||||
return ((ScriptNumber)left) / ((ScriptNumber)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;
|
|
||||||
case BoundBinaryOperator.OperatorKind.Exponent:
|
|
||||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
|
||||||
{
|
|
||||||
return ScriptNumber.Exponent((ScriptNumber) left, (ScriptNumber) right);
|
|
||||||
}
|
|
||||||
goto default;
|
|
||||||
case BoundBinaryOperator.OperatorKind.Remainder:
|
|
||||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
|
||||||
{
|
|
||||||
return ((ScriptNumber)left) % ((ScriptNumber)right);
|
|
||||||
}
|
|
||||||
else if (left.Type == Type.UserData)
|
|
||||||
{
|
|
||||||
var ud = (GenericUserData) left;
|
|
||||||
var (type, failed) = ud.BinaryOperator(left, OperatorType.Modulo, right);
|
|
||||||
if (failed) goto default;
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
goto default;
|
|
||||||
case BoundBinaryOperator.OperatorKind.Equality:
|
|
||||||
return new ScriptBoolean(left.Equals(right));
|
|
||||||
case BoundBinaryOperator.OperatorKind.Inequality:
|
|
||||||
return new ScriptBoolean(!left.Equals(right));
|
|
||||||
case BoundBinaryOperator.OperatorKind.Less:
|
|
||||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
|
||||||
{
|
|
||||||
return ((ScriptNumber)left) < ((ScriptNumber)right);
|
|
||||||
}
|
|
||||||
ThrowException($"Can't find operator for types '{left.Type}' and '{right.Type}'", e.Span);
|
|
||||||
return new ScriptNull();
|
|
||||||
case BoundBinaryOperator.OperatorKind.LessEquals:
|
|
||||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
|
||||||
{
|
|
||||||
return ((ScriptNumber)left) <= ((ScriptNumber)right);
|
|
||||||
}
|
|
||||||
ThrowException($"Can't find operator for types '{left.Type}' and '{right.Type}'", e.Span);
|
|
||||||
return new ScriptNull();
|
|
||||||
case BoundBinaryOperator.OperatorKind.Greater:
|
|
||||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
|
||||||
{
|
|
||||||
return ((ScriptNumber)left) > ((ScriptNumber)right);
|
|
||||||
}
|
|
||||||
ThrowException($"Can't find operator for types '{left.Type}' and '{right.Type}'", e.Span);
|
|
||||||
return new ScriptNull();
|
|
||||||
case BoundBinaryOperator.OperatorKind.GreaterEquals:
|
|
||||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
|
||||||
{
|
|
||||||
return ((ScriptNumber)left) >= ((ScriptNumber)right);
|
|
||||||
}
|
|
||||||
ThrowException($"Can't find operator for types '{left.Type}' and '{right.Type}'", e.Span);
|
|
||||||
return new ScriptNull();
|
|
||||||
default:
|
|
||||||
throw new Exception("Invalid Binary Operator: " + e.Operator.Kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThrowException(string message, TextSpan location)
|
|
||||||
{
|
|
||||||
throw new ScriptRuntimeException(_script.FileName, message, location, _diagnostics.ScriptString.GetSpan(location));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateAssignmentStatement(BoundVariableAssignment e)
|
|
||||||
{
|
|
||||||
var val = EvaluateExpression(e.BoundExpression);
|
|
||||||
if (e.IsLocalDefinition)
|
|
||||||
{
|
|
||||||
Scope.CreateLocal(e.Variable.VariableSymbol, val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Scope.AssignToNearest(e.Variable.VariableSymbol, val);
|
|
||||||
}
|
|
||||||
_lastValue = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateMultiAssignmentStatement(BoundMultiAssignmentStatement e)
|
|
||||||
{
|
|
||||||
var val = EvaluateExpression(e.Assignment);
|
|
||||||
if (val is IIndexable table)
|
|
||||||
{
|
|
||||||
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 ScriptNumberLong(i + 1), Scope);
|
|
||||||
if (variableSymbol.Local)
|
|
||||||
Scope.CreateLocal(variableSymbol, value);
|
|
||||||
else
|
|
||||||
Scope.AssignToNearest(variableSymbol, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_diagnostics.LogError($"Can't assign type '{val.Type}' to multiple variables.", e.Span);
|
|
||||||
}
|
|
||||||
_lastValue = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScriptType EvaluateVariableExpression(BoundVariableExpression e)
|
|
||||||
{
|
|
||||||
if (Scope.TryGet(e.Variable.VariableSymbol, out var val))
|
|
||||||
{
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new EvaluationException(_script.FileName, $"Cannot find variable: '{e.Variable.VariableSymbol.Name}'",
|
|
||||||
e.Span);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Stack<BoundStatement> _todoStatements = new Stack<BoundStatement>();
|
|
||||||
|
|
||||||
private void EvaluateBoundBlockStatement(BoundBlockStatement boundBlockStatement)
|
|
||||||
{
|
|
||||||
for (var index = boundBlockStatement.Statements.Length - 1; index >= 0; index--)
|
|
||||||
{
|
|
||||||
var s = boundBlockStatement.Statements[index];
|
|
||||||
_todoStatements.Push(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (DebugSession.Debugging)
|
|
||||||
{
|
|
||||||
Thread.Sleep(10);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (HasReturned)
|
|
||||||
return;
|
|
||||||
if (HasBroken)
|
|
||||||
return;
|
|
||||||
if (_todoStatements.Count == 0)
|
|
||||||
return;
|
|
||||||
var boundStatement = _todoStatements.Pop();
|
|
||||||
if (DebugSession.DebuggerAttached && boundStatement.HasBreakpoint)
|
|
||||||
{
|
|
||||||
DebugSession.TriggerBreakpoint(Scope);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
EvaluateStatement(boundStatement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateBoundIfStatement(BoundIfStatement boundBlockStatement)
|
|
||||||
{
|
|
||||||
var condition = EvaluateExpression(boundBlockStatement.Condition.Expression);
|
|
||||||
if ((ScriptBoolean) condition)
|
|
||||||
{
|
|
||||||
EvaluateStatement(boundBlockStatement.Block);
|
|
||||||
}
|
|
||||||
else if (boundBlockStatement.NextElseIf != null)
|
|
||||||
{
|
|
||||||
EvaluateStatement(boundBlockStatement.NextElseIf);
|
|
||||||
}
|
|
||||||
else if (boundBlockStatement.ElseStatement != null)
|
|
||||||
{
|
|
||||||
EvaluateStatement(boundBlockStatement.ElseStatement.Block);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateBoundFunctionAssigmentStatement(BoundFunctionAssignmentStatement e)
|
|
||||||
{
|
|
||||||
var func = (ScriptRuntimeFunction)EvaluateBoundFunctionStatement(e.Func);
|
|
||||||
if (e.Variable.Local)
|
|
||||||
{
|
|
||||||
if (Scope.Variables.TryGetValue(e.Variable.Name, out var f) && f is ScriptRuntimeFunction scriptRuntimeFunction)
|
|
||||||
{
|
|
||||||
scriptRuntimeFunction.AddOption(func.Options[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Scope.CreateLocal(e.Variable, func);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Scope.TryGet(e.Variable, out var f) && f is ScriptRuntimeFunction scriptRuntimeFunction)
|
|
||||||
{
|
|
||||||
scriptRuntimeFunction.AddOption(func.Options[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Scope.AssignToNearest(e.Variable, func);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScriptType EvaluateBoundFunctionStatement(BoundFunctionExpression boundFunctionExpression)
|
|
||||||
{
|
|
||||||
var option = new ScriptRuntimeFunction.ScriptRuntimeFunctionOption(boundFunctionExpression.Parameters, boundFunctionExpression.Block, Scope);
|
|
||||||
var func = new ScriptRuntimeFunction(new List<ScriptRuntimeFunction.ScriptRuntimeFunctionOption>(){option});
|
|
||||||
return func;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScriptType EvaluateUnboundFunctionStatement(UnboundFunctionExpression unboundFunctionExpression)
|
|
||||||
{
|
|
||||||
var option = new ScriptRuntimeFunction.ScriptRuntimeFunctionOption(unboundFunctionExpression.Parameters, unboundFunctionExpression.Block, Scope);
|
|
||||||
var func = new ScriptRuntimeFunction(new List<ScriptRuntimeFunction.ScriptRuntimeFunctionOption>(){option});
|
|
||||||
return func;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScriptType EvaluateBoundFunctionCallExpression(BoundFunctionCallExpression boundFunctionCallExpression)
|
|
||||||
{
|
|
||||||
var variable = EvaluateExpression(boundFunctionCallExpression.Identifier);
|
|
||||||
if (!(variable is ScriptFunction function))
|
|
||||||
{
|
|
||||||
throw new EvaluationException(_script.FileName, $"Variable is not a function.",
|
|
||||||
boundFunctionCallExpression.Identifier.Span);
|
|
||||||
}
|
|
||||||
var ls = new List<ScriptType>();
|
|
||||||
foreach (var t in boundFunctionCallExpression.Parameters)
|
|
||||||
{
|
|
||||||
var evaluate = EvaluateExpression(t);
|
|
||||||
ls.Add(evaluate);
|
|
||||||
}
|
|
||||||
|
|
||||||
var val = function.Run(_diagnostics, ls.ToArray(), _script, Scope, boundFunctionCallExpression.Span);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateReturnStatement(BoundReturnStatement b)
|
|
||||||
{
|
|
||||||
_returnValue = b.Expression == null ? null : EvaluateExpression(b.Expression);
|
|
||||||
_lastValue = _returnValue;
|
|
||||||
HasReturned = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScriptType EvaluateTableExpression(BoundTableExpression e)
|
|
||||||
{
|
|
||||||
var tableScope = EvaluationScope.CreateWithGetOnlyParent(Scope);
|
|
||||||
var innerEvaluator = new Evaluator(_diagnostics, tableScope, _script);
|
|
||||||
var currentPos = 1;
|
|
||||||
var isNumerated = true;
|
|
||||||
foreach (var boundStatement in e.Statements)
|
|
||||||
{
|
|
||||||
switch (boundStatement.Kind)
|
|
||||||
{
|
|
||||||
case BoundKind.BoundAssignmentStatement:
|
|
||||||
case BoundKind.BoundFunctionExpression:
|
|
||||||
case BoundKind.BoundFunctionAssignmentStatement:
|
|
||||||
innerEvaluator.EvaluateNode(boundStatement);
|
|
||||||
isNumerated = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
innerEvaluator.EvaluateStatement(boundStatement);
|
|
||||||
if (innerEvaluator._lastValue != null)
|
|
||||||
{
|
|
||||||
tableScope.CreateLocal(new VariableSymbol(currentPos.ToString(), innerEvaluator._lastValue.Type, false),
|
|
||||||
innerEvaluator._lastValue);
|
|
||||||
}
|
|
||||||
innerEvaluator._lastValue = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNumerated)
|
|
||||||
{
|
|
||||||
return new NumeratedScriptTable(tableScope);
|
|
||||||
}
|
|
||||||
return new GenericKeyedScriptTable(tableScope);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScriptType EvaluateIndexExpression(BoundIndexExpression e)
|
|
||||||
{
|
|
||||||
var variable = EvaluateExpression(e.Identifier);
|
|
||||||
if (variable.Type == Type.Nil)
|
|
||||||
{
|
|
||||||
throw new EvaluationException(_script.FileName, $"Nil variable can't be indexed", e.Span);
|
|
||||||
}
|
|
||||||
if (!(variable is IIndexable indexable))
|
|
||||||
{
|
|
||||||
throw new EvaluationException(_script.FileName,
|
|
||||||
$"Variable of type '{variable.Type}' is not indexable.", e.Span);
|
|
||||||
}
|
|
||||||
|
|
||||||
var scope = Scope;
|
|
||||||
if (variable is IScopeOwner scopeOwner)
|
|
||||||
{
|
|
||||||
scope = scopeOwner.EvaluationScope;
|
|
||||||
}
|
|
||||||
var indexer = EvaluateExpression(e.Index);
|
|
||||||
return indexable.Get(_diagnostics, e.Span, indexer, scope);
|
|
||||||
}
|
|
||||||
private ScriptType EvaluateFullStopIndexExpression(BoundFullStopIndexExpression e)
|
|
||||||
{
|
|
||||||
var variable = EvaluateExpression(e.Expression);
|
|
||||||
if (variable.Type == Type.Nil)
|
|
||||||
{
|
|
||||||
throw new EvaluationException(_script.FileName, $"Nil variable can't be indexed", e.Span);
|
|
||||||
}
|
|
||||||
if (!(variable is IIndexable indexable))
|
|
||||||
{
|
|
||||||
throw new EvaluationException(_script.FileName,
|
|
||||||
$"Variable of type '{variable.Type}' is not indexable.", e.Span);
|
|
||||||
}
|
|
||||||
|
|
||||||
var scope = Scope;
|
|
||||||
if (variable is IScopeOwner scopeOwner)
|
|
||||||
{
|
|
||||||
scope = scopeOwner.EvaluationScope;
|
|
||||||
}
|
|
||||||
|
|
||||||
return indexable.Get(_diagnostics, e.Span, e.Index.ToScriptType(), scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e)
|
|
||||||
{
|
|
||||||
ScriptType table;
|
|
||||||
ScriptType 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.ToScriptType();
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = EvaluateExpression(e.Value);
|
|
||||||
if (!(table is IIndexable indexable))
|
|
||||||
{
|
|
||||||
throw new Exception("Cant assign to that");
|
|
||||||
}
|
|
||||||
indexable.Set(_diagnostics, e.Span, index.ToString().ToScriptType(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateNumericForStatement(BoundNumericForStatement e)
|
|
||||||
{
|
|
||||||
var innerEvaluator = new Evaluator(_diagnostics, Scope, _script);
|
|
||||||
var startVal = (ScriptNumberLong)innerEvaluator.EvaluateExpression(e.BoundStart);
|
|
||||||
innerEvaluator.Scope.CreateLocal(e.Variable, startVal);
|
|
||||||
var stopVal = (ScriptNumberLong)innerEvaluator.EvaluateExpression(e.BoundStop);
|
|
||||||
long step = 1;
|
|
||||||
if (e.BoundStep != null)
|
|
||||||
{
|
|
||||||
var stepVal = (ScriptNumberLong)innerEvaluator.EvaluateExpression(e.BoundStep);
|
|
||||||
step = stepVal.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (step > 0)
|
|
||||||
{
|
|
||||||
for (; startVal.Value <= stopVal.Value; startVal.Value = startVal.Value + step)
|
|
||||||
{
|
|
||||||
innerEvaluator.EvaluateBoundBlockStatement(e.Block);
|
|
||||||
if (innerEvaluator.HasBroken)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (step < 0)
|
|
||||||
{
|
|
||||||
for (; startVal.Value >= stopVal.Value; startVal.Value = startVal.Value + step)
|
|
||||||
{
|
|
||||||
innerEvaluator.EvaluateBoundBlockStatement(e.Block);
|
|
||||||
if (innerEvaluator.HasBroken)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateGenericForStatement(BoundGenericForStatement e)
|
|
||||||
{
|
|
||||||
var innerEvaluator = new Evaluator(_diagnostics, Scope, _script);
|
|
||||||
var enumeratorObject = EvaluateExpression(e.BoundEnumerableExpression);
|
|
||||||
if (!(enumeratorObject is IIterable iterable))
|
|
||||||
{
|
|
||||||
throw new Exception($"Can't iterate over object with type '{enumeratorObject.Type}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var enumerator = iterable.GetScriptEnumerator())
|
|
||||||
{
|
|
||||||
while (enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
var current = enumerator.Current;
|
|
||||||
if (current == null)
|
|
||||||
{
|
|
||||||
throw new Exception($"Can't assign result value of nothing to multiple values");
|
|
||||||
}
|
|
||||||
if (current.Type != Type.Table)
|
|
||||||
{
|
|
||||||
throw new Exception($"Can't assign result value with type '{current.Type}' to multiple values");
|
|
||||||
}
|
|
||||||
|
|
||||||
var table = (SimpleScriptTable)current;
|
|
||||||
if (e.Variables[0].VariableSymbol.Name != "_")
|
|
||||||
innerEvaluator.Scope.CreateLocal(e.Variables[0].VariableSymbol, table[0].ToScriptType());
|
|
||||||
if (e.Variables[1].VariableSymbol.Name != "_")
|
|
||||||
innerEvaluator.Scope.CreateLocal(e.Variables[1].VariableSymbol, table[1]);
|
|
||||||
innerEvaluator.EvaluateBoundBlockStatement((BoundBlockStatement) e.Block);
|
|
||||||
if (innerEvaluator.HasBroken || innerEvaluator.HasReturned)
|
|
||||||
{
|
|
||||||
if (innerEvaluator.HasReturned)
|
|
||||||
{
|
|
||||||
HasReturned = innerEvaluator.HasReturned;
|
|
||||||
_returnValue = innerEvaluator._returnValue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateWhileStatement(BoundWhileStatement e)
|
|
||||||
{
|
|
||||||
var innerEvaluator = new Evaluator(_diagnostics, Scope, _script);
|
|
||||||
|
|
||||||
var block = (BoundBlockStatement) e.Block;
|
|
||||||
while ((ScriptBoolean)innerEvaluator.EvaluateExpression(e.Condition))
|
|
||||||
{
|
|
||||||
innerEvaluator.EvaluateBoundBlockStatement(block);
|
|
||||||
if (innerEvaluator.HasBroken || innerEvaluator.HasReturned)
|
|
||||||
{
|
|
||||||
if (innerEvaluator.HasReturned)
|
|
||||||
{
|
|
||||||
HasReturned = innerEvaluator.HasReturned;
|
|
||||||
_returnValue = innerEvaluator._returnValue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -171,7 +171,6 @@ namespace Upsilon.Evaluator
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Binder?.Dispose();
|
Binder?.Dispose();
|
||||||
Evaluator?.Dispose();
|
|
||||||
Scope?.Dispose();
|
Scope?.Dispose();
|
||||||
_parsed = null;
|
_parsed = null;
|
||||||
_bound = null;
|
_bound = null;
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace Upsilon.StandardLibraries
|
||||||
if (variableSymbols.Length != 1)
|
if (variableSymbols.Length != 1)
|
||||||
return BaseTypes.Type.Unknown;
|
return BaseTypes.Type.Unknown;
|
||||||
var parameter = variableSymbols[0];
|
var parameter = variableSymbols[0];
|
||||||
return parameter.Type;
|
return parameter.ValueType;
|
||||||
}
|
}
|
||||||
|
|
||||||
[ScriptFunction("print", "Prints a message to the action given in the script options", passScriptReference: true,
|
[ScriptFunction("print", "Prints a message to the action given in the script options", passScriptReference: true,
|
||||||
|
@ -122,7 +122,7 @@ namespace Upsilon.StandardLibraries
|
||||||
if (expressions.Length != 2)
|
if (expressions.Length != 2)
|
||||||
return BaseTypes.Type.Unknown;
|
return BaseTypes.Type.Unknown;
|
||||||
var typeNameExpression = expressions[1];
|
var typeNameExpression = expressions[1];
|
||||||
if (!(typeNameExpression is BoundLiteralExpression literal) || literal.Type != BaseTypes.Type.String)
|
if (!(typeNameExpression is BoundLiteralExpression literal) || literal.ValueType != BaseTypes.Type.String)
|
||||||
return BaseTypes.Type.Unknown;
|
return BaseTypes.Type.Unknown;
|
||||||
|
|
||||||
var boundType = BoundTypeHandler.GetTypeDefinition(((ScriptString) literal.Value));
|
var boundType = BoundTypeHandler.GetTypeDefinition(((ScriptString) literal.Value));
|
||||||
|
|
|
@ -31,9 +31,9 @@ return false";
|
||||||
var input =
|
var input =
|
||||||
$@"
|
$@"
|
||||||
if {condition} then
|
if {condition} then
|
||||||
val = {in1}
|
return {in1}
|
||||||
else
|
else
|
||||||
val = {in2}
|
return {in2}
|
||||||
end";
|
end";
|
||||||
var actual = Executor.EvaluateScript<long>(input, Options);
|
var actual = Executor.EvaluateScript<long>(input, Options);
|
||||||
Assert.Equal(expected, actual);
|
Assert.Equal(expected, actual);
|
||||||
|
@ -47,11 +47,11 @@ end";
|
||||||
var input =
|
var input =
|
||||||
$@"
|
$@"
|
||||||
if {condition1} then
|
if {condition1} then
|
||||||
val = {in1}
|
return {in1}
|
||||||
elseif {condition2} then
|
elseif {condition2} then
|
||||||
val = {in2}
|
return {in2}
|
||||||
else
|
else
|
||||||
val = {in3}
|
return {in3}
|
||||||
end";
|
end";
|
||||||
var actual = Executor.EvaluateScript<long>(input, Options);
|
var actual = Executor.EvaluateScript<long>(input, Options);
|
||||||
Assert.Equal(expected, actual);
|
Assert.Equal(expected, actual);
|
||||||
|
|
Loading…
Reference in New Issue