129 lines
4.4 KiB
C#
129 lines
4.4 KiB
C#
using System;
|
|
using Upsilon.Parser;
|
|
|
|
namespace Upsilon.Evaluator
|
|
{
|
|
public class Evaluator
|
|
{
|
|
private readonly Diagnostics _diagnostics;
|
|
public Script Script { get; }
|
|
public VariableScope Scope { get; }
|
|
|
|
public Evaluator(Script script, VariableScope scope, Diagnostics diagnostics)
|
|
{
|
|
_diagnostics = diagnostics;
|
|
Script = script;
|
|
Scope = scope;
|
|
}
|
|
|
|
public object Evaluate(ScriptSyntax e)
|
|
{
|
|
return EvaluateExpression(e.Statement);
|
|
}
|
|
|
|
public object Evaluate(ExpressionSyntax e)
|
|
{
|
|
return EvaluateExpression(e);
|
|
}
|
|
|
|
private object EvaluateExpression(ExpressionSyntax e)
|
|
{
|
|
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:
|
|
return Evaluate(((ParenthesizedExpressionSyntax)e).Expression);
|
|
case SyntaxKind.AssignmentExpression:
|
|
return EvaluateAssignmentExpression((AssignmentExpressionSyntax)e);
|
|
case SyntaxKind.VariableExpression:
|
|
return EvaluateVariableExpression((VariableExpressionSyntax) e);
|
|
default:
|
|
throw new Exception("Invalid expression: " + e.Kind);
|
|
}
|
|
}
|
|
|
|
private object EvaluateUnaryExpression(UnaryExpressionSyntax e)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
private object EvaluateBinaryExpression(BinaryExpressionSyntax e)
|
|
{
|
|
var left = EvaluateExpression(e.Left);
|
|
var right = EvaluateExpression(e.Right);
|
|
try
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
_diagnostics.LogUnknownVariable(e.Span, varName);
|
|
return null;
|
|
}
|
|
|
|
}
|
|
} |