Upsilon/Upsilon/Evaluator/Evaluator.cs

129 lines
4.4 KiB
C#
Raw Normal View History

2018-11-10 12:11:36 +00:00
using System;
using Upsilon.Parser;
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-10 16:00:39 +00:00
public Script Script { get; }
public VariableScope Scope { get; }
2018-11-11 09:26:52 +00:00
public Evaluator(Script script, VariableScope scope, Diagnostics diagnostics)
2018-11-10 16:00:39 +00:00
{
2018-11-11 09:26:52 +00:00
_diagnostics = diagnostics;
2018-11-10 16:00:39 +00:00
Script = script;
Scope = scope;
}
public object Evaluate(ScriptSyntax e)
2018-11-10 12:11:36 +00:00
{
return EvaluateExpression(e.Statement);
}
2018-11-10 16:00:39 +00:00
public object Evaluate(ExpressionSyntax e)
2018-11-10 12:11:36 +00:00
{
return EvaluateExpression(e);
}
2018-11-10 16:00:39 +00:00
private object EvaluateExpression(ExpressionSyntax e)
2018-11-10 12:11:36 +00:00
{
switch (e.Kind)
{
case SyntaxKind.UnaryExpression:
return EvaluateUnaryExpression((UnaryExpressionSyntax) e);
case SyntaxKind.BinaryExpression:
return EvaluateBinaryExpression((BinaryExpressionSyntax) e);
case SyntaxKind.LiteralExpression:
return ((LiteralExpressionSyntax) e).Value;
case SyntaxKind.ParenthesizedExpression:
2018-11-10 16:00:39 +00:00
return Evaluate(((ParenthesizedExpressionSyntax)e).Expression);
case SyntaxKind.AssignmentExpression:
return EvaluateAssignmentExpression((AssignmentExpressionSyntax)e);
case SyntaxKind.VariableExpression:
return EvaluateVariableExpression((VariableExpressionSyntax) e);
2018-11-10 12:11:36 +00:00
default:
throw new Exception("Invalid expression: " + e.Kind);
}
}
2018-11-10 16:00:39 +00:00
private object EvaluateUnaryExpression(UnaryExpressionSyntax e)
2018-11-10 12:11:36 +00:00
{
var operand = EvaluateExpression(e.Expression);
switch (e.Operator.Kind)
{
case SyntaxKind.Plus:
return operand;
case SyntaxKind.Minus:
return -(double) operand;
case SyntaxKind.NotKeyword:
return !(bool)operand;
default:
throw new Exception("Invalid Unary Operator: " + e.Operator.Kind);
}
}
2018-11-10 16:00:39 +00:00
private object EvaluateBinaryExpression(BinaryExpressionSyntax e)
2018-11-10 12:11:36 +00:00
{
var left = EvaluateExpression(e.Left);
var right = EvaluateExpression(e.Right);
2018-11-11 09:26:52 +00:00
try
2018-11-10 12:11:36 +00:00
{
2018-11-11 09:26:52 +00:00
switch (e.Operator.Kind)
{
case SyntaxKind.Plus:
return (double) left + (double) right;
case SyntaxKind.Minus:
return (double) left - (double) right;
case SyntaxKind.Star:
return (double) left * (double) right;
case SyntaxKind.Slash:
return (double) left / (double) right;
case SyntaxKind.AndKeyword:
return (bool) left && (bool) right;
case SyntaxKind.OrKeyword:
return (bool) left || (bool) right;
case SyntaxKind.EqualsEquals:
return Equals(left, right);
case SyntaxKind.TildeEquals:
return !Equals(left, right);
default:
throw new Exception("Invalid Binary Operator: " + e.Operator.Kind);
}
}
catch (NullReferenceException)
{
_diagnostics.LogNullReferenceError(e.Span);
return null;
2018-11-10 12:11:36 +00:00
}
}
2018-11-10 16:00:39 +00:00
private object EvaluateAssignmentExpression(AssignmentExpressionSyntax e)
{
var variableName = e.Identifier.Name;
var val = EvaluateExpression(e.Expression);
if (e.LocalToken == null)
{
Scope.SetGlobalVariable(variableName, val);
}
else
{
Scope.SetVariable(variableName, val);
}
return val;
}
private object EvaluateVariableExpression(VariableExpressionSyntax e)
{
var varName = e.Identifier.Name;
if (Scope.TryGetVariable(varName, out var value))
{
return value;
}
2018-11-11 09:26:52 +00:00
_diagnostics.LogUnknownVariable(e.Span, varName);
return null;
2018-11-10 16:00:39 +00:00
}
2018-11-10 12:11:36 +00:00
}
}