2018-11-10 12:11:36 +00:00
|
|
|
using System;
|
2018-11-11 19:31:55 +00:00
|
|
|
using System.Collections.Generic;
|
2018-11-11 17:12:42 +00:00
|
|
|
using Upsilon.BaseTypes.Number;
|
|
|
|
using Upsilon.Binder;
|
2018-11-10 12:11:36 +00:00
|
|
|
|
|
|
|
namespace Upsilon.Evaluator
|
|
|
|
{
|
2018-11-10 16:00:39 +00:00
|
|
|
public class Evaluator
|
2018-11-10 12:11:36 +00:00
|
|
|
{
|
2018-11-11 09:26:52 +00:00
|
|
|
private readonly Diagnostics _diagnostics;
|
2018-11-12 15:21:59 +00:00
|
|
|
private object _value;
|
2018-11-12 16:45:50 +00:00
|
|
|
private Script Script { get; }
|
2018-11-11 20:03:50 +00:00
|
|
|
private readonly Dictionary<VariableSymbol, object> _variables = new Dictionary<VariableSymbol, object>();
|
2018-11-10 16:00:39 +00:00
|
|
|
|
2018-11-11 17:12:42 +00:00
|
|
|
public Evaluator(Script script, Diagnostics diagnostics)
|
2018-11-10 16:00:39 +00:00
|
|
|
{
|
2018-11-11 09:26:52 +00:00
|
|
|
_diagnostics = diagnostics;
|
2018-11-11 20:03:50 +00:00
|
|
|
Script = script;
|
|
|
|
}
|
|
|
|
public Evaluator(Script script, Diagnostics diagnostics, Dictionary<VariableSymbol, object> vars)
|
|
|
|
{
|
|
|
|
_diagnostics = diagnostics;
|
|
|
|
Script = script;
|
|
|
|
_variables = vars;
|
2018-11-10 16:00:39 +00:00
|
|
|
}
|
|
|
|
|
2018-11-11 17:12:42 +00:00
|
|
|
public object Evaluate(BoundScript e)
|
2018-11-10 12:11:36 +00:00
|
|
|
{
|
2018-11-12 15:21:59 +00:00
|
|
|
EvaluateStatement(e.Statement);
|
|
|
|
return _value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void EvaluateStatement(BoundStatement e)
|
|
|
|
{
|
|
|
|
switch (e.Kind)
|
|
|
|
{
|
|
|
|
case BoundKind.BoundAssignmentStatement:
|
|
|
|
EvaluateAssignmentStatement((BoundVariableAssignment) e);
|
|
|
|
break;
|
2018-11-12 16:45:50 +00:00
|
|
|
case BoundKind.BoundBlockStatement:
|
|
|
|
EvaluateBoundBlockStatement((BoundBlockStatement) e);
|
|
|
|
break;
|
2018-11-12 15:21:59 +00:00
|
|
|
default:
|
|
|
|
EvaluateExpressionStatement((BoundExpressionStatement) e);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-12 16:45:50 +00:00
|
|
|
|
2018-11-12 15:21:59 +00:00
|
|
|
private void EvaluateExpressionStatement(BoundExpressionStatement e)
|
|
|
|
{
|
|
|
|
_value = EvaluateExpression(e.Expression);
|
2018-11-10 12:11:36 +00:00
|
|
|
}
|
|
|
|
|
2018-11-11 17:12:42 +00:00
|
|
|
private object EvaluateExpression(BoundExpression e)
|
2018-11-10 12:11:36 +00:00
|
|
|
{
|
|
|
|
switch (e.Kind)
|
|
|
|
{
|
2018-11-11 17:12:42 +00:00
|
|
|
case BoundKind.BoundLiteralExpression:
|
|
|
|
return ((BoundLiteralExpression) e).Value;
|
|
|
|
case BoundKind.BoundBinaryExpression:
|
|
|
|
return EvaluateBinaryExpression((BoundBinaryExpression) e);
|
2018-11-11 18:56:53 +00:00
|
|
|
case BoundKind.BoundUnaryExpression:
|
|
|
|
return EvaluateUnaryExpression((BoundUnaryExpression) e);
|
2018-11-11 20:03:50 +00:00
|
|
|
case BoundKind.VariableExpression:
|
|
|
|
return EvaluateVariableExpression((BoundVariableExpression) e);
|
2018-11-10 12:11:36 +00:00
|
|
|
default:
|
2018-11-11 18:56:53 +00:00
|
|
|
throw new NotImplementedException();
|
2018-11-10 12:11:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-11 18:56:53 +00:00
|
|
|
private object EvaluateUnaryExpression(BoundUnaryExpression e)
|
2018-11-10 12:11:36 +00:00
|
|
|
{
|
2018-11-11 18:56:53 +00:00
|
|
|
var operand = EvaluateExpression(e.InExpression);
|
2018-11-10 12:11:36 +00:00
|
|
|
switch (e.Operator.Kind)
|
|
|
|
{
|
2018-11-11 18:56:53 +00:00
|
|
|
case BoundUnaryOperator.OperatorKind.Identity:
|
2018-11-10 12:11:36 +00:00
|
|
|
return operand;
|
2018-11-11 18:56:53 +00:00
|
|
|
case BoundUnaryOperator.OperatorKind.Negation:
|
|
|
|
return -((Number)operand);
|
|
|
|
case BoundUnaryOperator.OperatorKind.LogicalNegation:
|
|
|
|
return !(bool) operand;
|
2018-11-10 12:11:36 +00:00
|
|
|
default:
|
|
|
|
throw new Exception("Invalid Unary Operator: " + e.Operator.Kind);
|
|
|
|
}
|
2018-11-11 18:56:53 +00:00
|
|
|
}
|
2018-11-10 12:11:36 +00:00
|
|
|
|
2018-11-11 17:12:42 +00:00
|
|
|
private object EvaluateBinaryExpression(BoundBinaryExpression e)
|
2018-11-10 12:11:36 +00:00
|
|
|
{
|
2018-11-11 17:12:42 +00:00
|
|
|
var left = EvaluateExpression(e.LeftExpression);
|
|
|
|
var right = EvaluateExpression(e.RightExpression);
|
|
|
|
switch (e.Operator.Kind)
|
2018-11-11 09:26:52 +00:00
|
|
|
{
|
2018-11-11 17:12:42 +00:00
|
|
|
case BoundBinaryOperator.OperatorKind.Addition:
|
|
|
|
return ((Number)left) + ((Number)right);
|
|
|
|
case BoundBinaryOperator.OperatorKind.Subtraction:
|
|
|
|
return ((Number)left) - ((Number)right);
|
|
|
|
case BoundBinaryOperator.OperatorKind.Multiplication:
|
|
|
|
return ((Number)left) * ((Number)right);
|
|
|
|
case BoundBinaryOperator.OperatorKind.Division:
|
|
|
|
return ((Number)left) / ((Number)right);
|
|
|
|
case BoundBinaryOperator.OperatorKind.Equality:
|
|
|
|
return Equals(left, right);
|
|
|
|
case BoundBinaryOperator.OperatorKind.Inequality:
|
|
|
|
return !Equals(left, right);
|
|
|
|
default:
|
|
|
|
throw new Exception("Invalid Binary Operator: " + e.Operator);
|
2018-11-10 12:11:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-12 16:45:50 +00:00
|
|
|
private void EvaluateAssignmentStatement(BoundVariableAssignment e)
|
2018-11-10 16:00:39 +00:00
|
|
|
{
|
2018-11-12 15:21:59 +00:00
|
|
|
var val = EvaluateExpression(e.BoundExpression);
|
2018-11-11 20:03:50 +00:00
|
|
|
_variables[e.Variable] = val;
|
2018-11-12 15:21:59 +00:00
|
|
|
_value = val;
|
2018-11-11 19:31:55 +00:00
|
|
|
}
|
2018-11-10 16:00:39 +00:00
|
|
|
|
2018-11-11 20:03:50 +00:00
|
|
|
private object EvaluateVariableExpression(BoundVariableExpression e)
|
2018-11-10 16:00:39 +00:00
|
|
|
{
|
2018-11-11 20:03:50 +00:00
|
|
|
return _variables[e.Variable];
|
2018-11-10 16:00:39 +00:00
|
|
|
}
|
|
|
|
|
2018-11-12 16:45:50 +00:00
|
|
|
private void EvaluateBoundBlockStatement(BoundBlockStatement boundBlockStatement)
|
|
|
|
{
|
|
|
|
foreach (var boundStatement in boundBlockStatement.Statements)
|
|
|
|
{
|
|
|
|
EvaluateStatement(boundStatement);
|
|
|
|
}
|
|
|
|
}
|
2018-11-10 12:11:36 +00:00
|
|
|
}
|
|
|
|
}
|