Lots of work on type binding
This commit is contained in:
parent
699377cdfc
commit
3561979ded
|
@ -0,0 +1,78 @@
|
||||||
|
namespace Upsilon.BaseTypes.Number
|
||||||
|
{
|
||||||
|
public abstract class Number
|
||||||
|
{
|
||||||
|
protected abstract bool IsFloat { get; }
|
||||||
|
|
||||||
|
#region Binary Operators
|
||||||
|
|
||||||
|
public static Number operator + (Number a, Number b)
|
||||||
|
{
|
||||||
|
if (!a.IsFloat && !b.IsFloat)
|
||||||
|
return new NumberLong(((NumberLong) a).Value + ((NumberLong) b).Value);
|
||||||
|
if (a.IsFloat && b.IsFloat)
|
||||||
|
return new NumberDouble(((NumberDouble) a).Value + ((NumberDouble) b).Value);
|
||||||
|
if (a.IsFloat)
|
||||||
|
return new NumberDouble(((NumberDouble) a).Value + ((NumberLong) b).Value);
|
||||||
|
return new NumberDouble(((NumberLong) a).Value + ((NumberDouble) b).Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Number operator - (Number a, Number b)
|
||||||
|
{
|
||||||
|
if (!a.IsFloat && !b.IsFloat)
|
||||||
|
return new NumberLong(((NumberLong) a).Value - ((NumberLong) b).Value);
|
||||||
|
if (a.IsFloat && b.IsFloat)
|
||||||
|
return new NumberDouble(((NumberDouble) a).Value - ((NumberDouble) b).Value);
|
||||||
|
if (a.IsFloat)
|
||||||
|
return new NumberDouble(((NumberDouble) a).Value - ((NumberLong) b).Value);
|
||||||
|
return new NumberDouble(((NumberLong) a).Value - ((NumberDouble) b).Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Number operator * (Number a, Number b)
|
||||||
|
{
|
||||||
|
if (!a.IsFloat && !b.IsFloat)
|
||||||
|
return new NumberLong(((NumberLong) a).Value * ((NumberLong) b).Value);
|
||||||
|
if (a.IsFloat && b.IsFloat)
|
||||||
|
return new NumberDouble(((NumberDouble) a).Value * ((NumberDouble) b).Value);
|
||||||
|
if (a.IsFloat)
|
||||||
|
return new NumberDouble(((NumberDouble) a).Value * ((NumberLong) b).Value);
|
||||||
|
return new NumberDouble(((NumberLong) a).Value * ((NumberDouble) b).Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Number operator / (Number a, Number b)
|
||||||
|
{
|
||||||
|
if (!a.IsFloat && !b.IsFloat)
|
||||||
|
return new NumberLong(((NumberLong) a).Value / ((NumberLong) b).Value);
|
||||||
|
if (a.IsFloat && b.IsFloat)
|
||||||
|
return new NumberDouble(((NumberDouble) a).Value / ((NumberDouble) b).Value);
|
||||||
|
if (a.IsFloat)
|
||||||
|
return new NumberDouble(((NumberDouble) a).Value / ((NumberLong) b).Value);
|
||||||
|
return new NumberDouble(((NumberLong) a).Value / ((NumberDouble) b).Value);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Equality
|
||||||
|
private bool Equals(Number other)
|
||||||
|
{
|
||||||
|
if (!IsFloat && !other.IsFloat)
|
||||||
|
return ((NumberLong) this).Value.Equals(((NumberLong) other).Value);
|
||||||
|
if (IsFloat && other.IsFloat)
|
||||||
|
return ((NumberDouble) this).Value.Equals(((NumberDouble) other).Value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable 659
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
#pragma warning restore 659
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
|
if (ReferenceEquals(this, obj)) return true;
|
||||||
|
if (obj.GetType() != this.GetType()) return false;
|
||||||
|
return Equals((Number) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Upsilon.BaseTypes.Number
|
||||||
|
{
|
||||||
|
public class NumberDouble : Number
|
||||||
|
{
|
||||||
|
public double Value { get; }
|
||||||
|
protected override bool IsFloat { get; } = true;
|
||||||
|
|
||||||
|
public NumberDouble(double value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Value.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Upsilon.BaseTypes.Number
|
||||||
|
{
|
||||||
|
public class NumberLong : Number
|
||||||
|
{
|
||||||
|
public long Value { get; }
|
||||||
|
protected override bool IsFloat { get; } = true;
|
||||||
|
|
||||||
|
public NumberLong(long val)
|
||||||
|
{
|
||||||
|
Value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Value.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
namespace Upsilon.BaseTypes
|
||||||
|
{
|
||||||
|
public enum Type
|
||||||
|
{
|
||||||
|
Nil,
|
||||||
|
Boolean,
|
||||||
|
Number,
|
||||||
|
String,
|
||||||
|
Function,
|
||||||
|
UserData,
|
||||||
|
Thread,
|
||||||
|
Table
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Upsilon.BaseTypes.Number;
|
||||||
|
using Upsilon.Parser;
|
||||||
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public class Binder
|
||||||
|
{
|
||||||
|
private readonly Diagnostics _diagnostics;
|
||||||
|
private BoundScope _scope;
|
||||||
|
|
||||||
|
public Binder(BoundScope parentScope, Diagnostics diagnostics)
|
||||||
|
{
|
||||||
|
_diagnostics = diagnostics;
|
||||||
|
_scope = new BoundScope(parentScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundScript BindScript(ScriptSyntax e)
|
||||||
|
{
|
||||||
|
var bound = BindExpression(e.Statement);
|
||||||
|
return new BoundScript(bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundExpression BindExpression(ExpressionSyntax e)
|
||||||
|
{
|
||||||
|
switch (e.Kind)
|
||||||
|
{
|
||||||
|
case SyntaxKind.UnaryExpression:
|
||||||
|
break;
|
||||||
|
case SyntaxKind.BinaryExpression:
|
||||||
|
return BindBinaryExpression((BinaryExpressionSyntax) e);
|
||||||
|
case SyntaxKind.LiteralExpression:
|
||||||
|
return BindLiteralExpression((LiteralExpressionSyntax) e);
|
||||||
|
case SyntaxKind.ParenthesizedExpression:
|
||||||
|
break;
|
||||||
|
case SyntaxKind.AssignmentExpression:
|
||||||
|
break;
|
||||||
|
case SyntaxKind.VariableExpression:
|
||||||
|
break;
|
||||||
|
case SyntaxKind.BadExpression:
|
||||||
|
break;
|
||||||
|
case SyntaxKind.ScriptUnit:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
throw new NotImplementedException(e.Kind.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoundExpression BindBinaryExpression(BinaryExpressionSyntax e)
|
||||||
|
{
|
||||||
|
var left = BindExpression(e.Left);
|
||||||
|
var right = BindExpression(e.Right);
|
||||||
|
var op = BoundBinaryOperator.BindBinaryOperator(e.Operator.Kind, left.Type, right.Type);
|
||||||
|
if (op == null)
|
||||||
|
{
|
||||||
|
_diagnostics.LogUnknownOperator(e.Span, e.Operator.Kind, left.Type, right.Type);
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
return new BoundBinaryExpression(op, left, right, op.OutType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoundExpression BindLiteralExpression(LiteralExpressionSyntax e)
|
||||||
|
{
|
||||||
|
var value = e.Value;
|
||||||
|
var type = Type.Nil;
|
||||||
|
object outValue = null;
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case double d:
|
||||||
|
type = Type.Number;
|
||||||
|
outValue = new NumberDouble(d);
|
||||||
|
break;
|
||||||
|
case bool b:
|
||||||
|
type = Type.Boolean;
|
||||||
|
outValue = value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_diagnostics.LogUnknownType(e.Span);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return new BoundLiteralExpression(outValue, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.Parser;
|
||||||
|
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public class BoundBinaryExpression : BoundExpression
|
||||||
|
{
|
||||||
|
public BoundBinaryExpression(BoundBinaryOperator op, BoundExpression leftExpression, BoundExpression rightExpression, Type type)
|
||||||
|
{
|
||||||
|
Operator = op;
|
||||||
|
LeftExpression = leftExpression;
|
||||||
|
RightExpression = rightExpression;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BoundKind Kind => BoundKind.BoundBinaryExpression;
|
||||||
|
public override Type Type { get; }
|
||||||
|
|
||||||
|
public BoundBinaryOperator Operator { get; }
|
||||||
|
public BoundExpression LeftExpression { get; }
|
||||||
|
public BoundExpression RightExpression { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Upsilon.Parser;
|
||||||
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public class BoundBinaryOperator
|
||||||
|
{
|
||||||
|
public enum OperatorKind
|
||||||
|
{
|
||||||
|
Addition, Subtraction, Multiplication, Division, Equality, Inequality
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type LeftType { get; }
|
||||||
|
public Type RightType { get; }
|
||||||
|
public Type OutType { get; }
|
||||||
|
public OperatorKind Kind { get; }
|
||||||
|
|
||||||
|
public BoundBinaryOperator(OperatorKind kind, Type outType)
|
||||||
|
{
|
||||||
|
Kind = kind;
|
||||||
|
LeftType = outType;
|
||||||
|
RightType = outType;
|
||||||
|
OutType = outType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundBinaryOperator(OperatorKind kind, Type leftType, Type rightType, Type outType)
|
||||||
|
{
|
||||||
|
Kind = kind;
|
||||||
|
LeftType = leftType;
|
||||||
|
RightType = rightType;
|
||||||
|
OutType = outType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundBinaryOperator[] Operators = new BoundBinaryOperator[]
|
||||||
|
{
|
||||||
|
// Math operators
|
||||||
|
new BoundBinaryOperator(OperatorKind.Addition, Type.Number),
|
||||||
|
new BoundBinaryOperator(OperatorKind.Subtraction, Type.Number),
|
||||||
|
new BoundBinaryOperator(OperatorKind.Multiplication, Type.Number),
|
||||||
|
new BoundBinaryOperator(OperatorKind.Division, Type.Number),
|
||||||
|
|
||||||
|
// Number equality
|
||||||
|
new BoundBinaryOperator(OperatorKind.Equality, Type.Number, Type.Number, Type.Boolean),
|
||||||
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.Number, Type.Number, Type.Boolean),
|
||||||
|
|
||||||
|
// Boolean equality
|
||||||
|
new BoundBinaryOperator(OperatorKind.Equality, Type.Boolean),
|
||||||
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.Boolean),
|
||||||
|
};
|
||||||
|
|
||||||
|
public static BoundBinaryOperator BindBinaryOperator(SyntaxKind operatorToken, Type left, Type right)
|
||||||
|
{
|
||||||
|
OperatorKind kind;
|
||||||
|
switch (operatorToken)
|
||||||
|
{
|
||||||
|
case SyntaxKind.Plus:
|
||||||
|
kind = OperatorKind.Addition;
|
||||||
|
break;
|
||||||
|
case SyntaxKind.Minus:
|
||||||
|
kind = OperatorKind.Subtraction;
|
||||||
|
break;
|
||||||
|
case SyntaxKind.Star:
|
||||||
|
kind = OperatorKind.Multiplication;
|
||||||
|
break;
|
||||||
|
case SyntaxKind.Slash:
|
||||||
|
kind = OperatorKind.Division;
|
||||||
|
break;
|
||||||
|
case SyntaxKind.EqualsEquals:
|
||||||
|
kind = OperatorKind.Equality;
|
||||||
|
break;
|
||||||
|
case SyntaxKind.TildeEquals:
|
||||||
|
kind = OperatorKind.Inequality;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown binary operator token: " + operatorToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Operators.FirstOrDefault(op => op.Kind == kind && op.LeftType == left && op.RightType == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
|
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public abstract class BoundExpression : BoundNode
|
||||||
|
{
|
||||||
|
public abstract Type Type { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public enum BoundKind
|
||||||
|
{
|
||||||
|
BoundScript,
|
||||||
|
|
||||||
|
BoundLiteralExpression,
|
||||||
|
BoundBinaryExpression,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
|
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public class BoundLiteralExpression : BoundExpression
|
||||||
|
{
|
||||||
|
public BoundLiteralExpression(object value, Type type)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BoundKind Kind => BoundKind.BoundLiteralExpression;
|
||||||
|
public override Type Type { get; }
|
||||||
|
public object Value { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public abstract class BoundNode
|
||||||
|
{
|
||||||
|
public abstract BoundKind Kind { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public class BoundScope
|
||||||
|
{
|
||||||
|
private readonly BoundScope _parentScope;
|
||||||
|
private readonly Dictionary<string, VariableSymbol> _variables;
|
||||||
|
|
||||||
|
public BoundScope(BoundScope parentScope)
|
||||||
|
{
|
||||||
|
_parentScope = parentScope;
|
||||||
|
_variables = new Dictionary<string, VariableSymbol>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetVariable(VariableSymbol var)
|
||||||
|
{
|
||||||
|
if (_variables.ContainsKey(var.Name))
|
||||||
|
_variables[var.Name] = var;
|
||||||
|
else
|
||||||
|
_variables.Add(var.Name, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetGlobalVariable(VariableSymbol var)
|
||||||
|
{
|
||||||
|
if (_parentScope == null)
|
||||||
|
{
|
||||||
|
SetVariable(var);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_parentScope.SetGlobalVariable(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool TryGetVariable(string key, out VariableSymbol result)
|
||||||
|
{
|
||||||
|
if (_variables.TryGetValue(key, out result))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_parentScope != null)
|
||||||
|
{
|
||||||
|
return _parentScope.TryGetVariable(key, out result);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public class BoundScript : BoundNode
|
||||||
|
{
|
||||||
|
public BoundScript(BoundExpression statement)
|
||||||
|
{
|
||||||
|
Statement = statement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BoundKind Kind => BoundKind.BoundScript;
|
||||||
|
|
||||||
|
public BoundExpression Statement { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
|
|
||||||
|
namespace Upsilon.Binder
|
||||||
|
{
|
||||||
|
public class VariableSymbol
|
||||||
|
{
|
||||||
|
public VariableSymbol(string name, Type type)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type Type { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.Parser;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon
|
namespace Upsilon
|
||||||
|
@ -37,6 +39,16 @@ namespace Upsilon
|
||||||
{
|
{
|
||||||
LogError($"Null Reference Encountered", span);
|
LogError($"Null Reference Encountered", span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void LogUnknownType(TextSpan eSpan)
|
||||||
|
{
|
||||||
|
LogError($"Unknown Type found", eSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogUnknownOperator(TextSpan eSpan, SyntaxKind text, Type leftType, Type rightType)
|
||||||
|
{
|
||||||
|
LogError($"No binary operator {text} found for types '{leftType}' and '{rightType}'", eSpan);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DiagnosticsMessage
|
public class DiagnosticsMessage
|
||||||
|
@ -71,7 +83,7 @@ namespace Upsilon
|
||||||
|
|
||||||
public string AfterError(int i = 5)
|
public string AfterError(int i = 5)
|
||||||
{
|
{
|
||||||
return Diagnostics.ScriptString.GetSpan(Span.Start + 1, i);
|
return Diagnostics.ScriptString.GetSpan(Span.Start + Span.Length, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
using Upsilon.BaseTypes.Number;
|
||||||
|
using Upsilon.Binder;
|
||||||
using Upsilon.Parser;
|
using Upsilon.Parser;
|
||||||
|
|
||||||
namespace Upsilon.Evaluator
|
namespace Upsilon.Evaluator
|
||||||
|
@ -7,46 +9,39 @@ namespace Upsilon.Evaluator
|
||||||
{
|
{
|
||||||
private readonly Diagnostics _diagnostics;
|
private readonly Diagnostics _diagnostics;
|
||||||
public Script Script { get; }
|
public Script Script { get; }
|
||||||
public VariableScope Scope { get; }
|
|
||||||
|
|
||||||
public Evaluator(Script script, VariableScope scope, Diagnostics diagnostics)
|
public Evaluator(Script script, Diagnostics diagnostics)
|
||||||
{
|
{
|
||||||
_diagnostics = diagnostics;
|
_diagnostics = diagnostics;
|
||||||
Script = script;
|
Script = script;
|
||||||
Scope = scope;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public object Evaluate(ScriptSyntax e)
|
public object Evaluate(ScriptSyntax e)
|
||||||
|
{
|
||||||
|
return EvaluateExpression(e.Statement);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public object Evaluate(BoundScript e)
|
||||||
{
|
{
|
||||||
return EvaluateExpression(e.Statement);
|
return EvaluateExpression(e.Statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Evaluate(ExpressionSyntax e)
|
private object EvaluateExpression(BoundExpression e)
|
||||||
{
|
|
||||||
return EvaluateExpression(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private object EvaluateExpression(ExpressionSyntax e)
|
|
||||||
{
|
{
|
||||||
switch (e.Kind)
|
switch (e.Kind)
|
||||||
{
|
{
|
||||||
case SyntaxKind.UnaryExpression:
|
case BoundKind.BoundLiteralExpression:
|
||||||
return EvaluateUnaryExpression((UnaryExpressionSyntax) e);
|
return ((BoundLiteralExpression) e).Value;
|
||||||
case SyntaxKind.BinaryExpression:
|
case BoundKind.BoundBinaryExpression:
|
||||||
return EvaluateBinaryExpression((BinaryExpressionSyntax) e);
|
return EvaluateBinaryExpression((BoundBinaryExpression) 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:
|
default:
|
||||||
throw new Exception("Invalid expression: " + e.Kind);
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
private object EvaluateUnaryExpression(UnaryExpressionSyntax e)
|
private object EvaluateUnaryExpression(UnaryExpressionSyntax e)
|
||||||
{
|
{
|
||||||
var operand = EvaluateExpression(e.Expression);
|
var operand = EvaluateExpression(e.Expression);
|
||||||
|
@ -61,66 +56,42 @@ namespace Upsilon.Evaluator
|
||||||
default:
|
default:
|
||||||
throw new Exception("Invalid Unary Operator: " + e.Operator.Kind);
|
throw new Exception("Invalid Unary Operator: " + e.Operator.Kind);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private object EvaluateBinaryExpression(BinaryExpressionSyntax e)
|
private object EvaluateBinaryExpression(BoundBinaryExpression e)
|
||||||
{
|
{
|
||||||
var left = EvaluateExpression(e.Left);
|
var left = EvaluateExpression(e.LeftExpression);
|
||||||
var right = EvaluateExpression(e.Right);
|
var right = EvaluateExpression(e.RightExpression);
|
||||||
try
|
switch (e.Operator.Kind)
|
||||||
{
|
{
|
||||||
switch (e.Operator.Kind)
|
case BoundBinaryOperator.OperatorKind.Addition:
|
||||||
{
|
return ((Number)left) + ((Number)right);
|
||||||
case SyntaxKind.Plus:
|
case BoundBinaryOperator.OperatorKind.Subtraction:
|
||||||
return (double) left + (double) right;
|
return ((Number)left) - ((Number)right);
|
||||||
case SyntaxKind.Minus:
|
case BoundBinaryOperator.OperatorKind.Multiplication:
|
||||||
return (double) left - (double) right;
|
return ((Number)left) * ((Number)right);
|
||||||
case SyntaxKind.Star:
|
case BoundBinaryOperator.OperatorKind.Division:
|
||||||
return (double) left * (double) right;
|
return ((Number)left) / ((Number)right);
|
||||||
case SyntaxKind.Slash:
|
case BoundBinaryOperator.OperatorKind.Equality:
|
||||||
return (double) left / (double) right;
|
return Equals(left, right);
|
||||||
case SyntaxKind.AndKeyword:
|
case BoundBinaryOperator.OperatorKind.Inequality:
|
||||||
return (bool) left && (bool) right;
|
return !Equals(left, right);
|
||||||
case SyntaxKind.OrKeyword:
|
default:
|
||||||
return (bool) left || (bool) right;
|
throw new Exception("Invalid Binary Operator: " + e.Operator);
|
||||||
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)
|
private object EvaluateAssignmentExpression(AssignmentExpressionSyntax e)
|
||||||
{
|
{
|
||||||
var variableName = e.Identifier.Name;
|
var variableName = e.Identifier.Name;
|
||||||
var val = EvaluateExpression(e.Expression);
|
var val = EvaluateExpression(e.Expression);
|
||||||
if (e.LocalToken == null)
|
|
||||||
{
|
|
||||||
Scope.SetGlobalVariable(variableName, val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Scope.SetVariable(variableName, val);
|
|
||||||
}
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private object EvaluateVariableExpression(VariableExpressionSyntax e)
|
private object EvaluateVariableExpression(VariableExpressionSyntax e)
|
||||||
{
|
{
|
||||||
var varName = e.Identifier.Name;
|
var varName = e.Identifier.Name;
|
||||||
if (Scope.TryGetVariable(varName, out var value))
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
_diagnostics.LogUnknownVariable(e.Span, varName);
|
_diagnostics.LogUnknownVariable(e.Span, varName);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,37 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.Binder;
|
||||||
using Upsilon.Parser;
|
using Upsilon.Parser;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Evaluator
|
namespace Upsilon.Evaluator
|
||||||
{
|
{
|
||||||
public class Script : VariableScope
|
public class Script
|
||||||
{
|
{
|
||||||
private SourceText ScriptString { get; }
|
private SourceText ScriptString { get; }
|
||||||
private Evaluator Evaluator { get; }
|
private Evaluator Evaluator { get; }
|
||||||
public readonly ScriptSyntax Parsed;
|
private readonly ScriptSyntax _parsed;
|
||||||
public Diagnostics Diagnostics { get; }
|
public Diagnostics Diagnostics { get; }
|
||||||
|
private Binder.Binder Binder { get; }
|
||||||
|
|
||||||
public Script(string scriptString)
|
public Script(string scriptString)
|
||||||
{
|
{
|
||||||
ScriptString = new SourceText(scriptString);
|
ScriptString = new SourceText(scriptString);
|
||||||
Diagnostics = new Diagnostics(ScriptString);
|
Diagnostics = new Diagnostics(ScriptString);
|
||||||
Parsed = Parser.Parser.Parse(scriptString, Diagnostics);
|
_parsed = Parser.Parser.Parse(scriptString, Diagnostics);
|
||||||
Evaluator = new Evaluator(this, this, Diagnostics);
|
Binder = new Binder.Binder(new BoundScope(null), Diagnostics);
|
||||||
}
|
Evaluator = new Evaluator(this, Diagnostics);
|
||||||
|
|
||||||
public Script(string scriptString, Dictionary<string, object> variables = null)
|
|
||||||
:base(variables: variables)
|
|
||||||
{
|
|
||||||
ScriptString = new SourceText(scriptString);
|
|
||||||
Diagnostics = new Diagnostics(ScriptString);
|
|
||||||
Evaluator = new Evaluator(this, this, Diagnostics);
|
|
||||||
Parsed = Parser.Parser.Parse(scriptString, Diagnostics);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Evaluate()
|
public object Evaluate()
|
||||||
{
|
{
|
||||||
return Evaluator.Evaluate(Parsed);
|
var bound = Binder.BindScript(_parsed);
|
||||||
|
return Evaluator.Evaluate(bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Evaluate<T>()
|
public T Evaluate<T>()
|
||||||
{
|
{
|
||||||
return (T)Evaluator.Evaluate(Parsed);
|
var bound = Binder.BindScript(_parsed);
|
||||||
|
return (T)Evaluator.Evaluate(bound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,53 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Upsilon.Evaluator
|
|
||||||
{
|
|
||||||
public class VariableScope
|
|
||||||
{
|
|
||||||
private VariableScope _parentScope;
|
|
||||||
public readonly Dictionary<string, object> Variables = new Dictionary<string, object>();
|
|
||||||
|
|
||||||
public VariableScope(VariableScope parentScope = null, Dictionary<string, object> variables = null)
|
|
||||||
{
|
|
||||||
_parentScope = parentScope;
|
|
||||||
if (variables != null)
|
|
||||||
Variables = variables;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void SetVariable(string key, object value)
|
|
||||||
{
|
|
||||||
if (Variables.ContainsKey(key))
|
|
||||||
Variables[key] = value;
|
|
||||||
else
|
|
||||||
Variables.Add(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetGlobalVariable(string key, object value)
|
|
||||||
{
|
|
||||||
if (_parentScope == null)
|
|
||||||
{
|
|
||||||
SetVariable(key, value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_parentScope.SetGlobalVariable(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public bool TryGetVariable(string key, out object result)
|
|
||||||
{
|
|
||||||
if (Variables.TryGetValue(key, out result))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (_parentScope != null)
|
|
||||||
{
|
|
||||||
return _parentScope.TryGetVariable(key, out result);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ namespace Upsilon.Parser
|
||||||
public override SyntaxKind Kind => SyntaxKind.BadExpression;
|
public override SyntaxKind Kind => SyntaxKind.BadExpression;
|
||||||
public override IEnumerable<SyntaxNode> ChildNodes()
|
public override IEnumerable<SyntaxNode> ChildNodes()
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
yield break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,16 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.Parser
|
namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
public class BinaryExpressionSyntax : ExpressionSyntax
|
public sealed class BinaryExpressionSyntax : ExpressionSyntax
|
||||||
{
|
{
|
||||||
public BinaryExpressionSyntax(ExpressionSyntax left, SyntaxToken @operator, ExpressionSyntax right)
|
public BinaryExpressionSyntax(ExpressionSyntax left, SyntaxToken @operator, ExpressionSyntax right)
|
||||||
{
|
{
|
||||||
Left = left;
|
Left = left;
|
||||||
Operator = @operator;
|
Operator = @operator;
|
||||||
Right = right;
|
Right = right;
|
||||||
|
Span = new TextSpan(left.Span.Start, right.Span.End);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SyntaxKind Kind => SyntaxKind.BinaryExpression;
|
public override SyntaxKind Kind => SyntaxKind.BinaryExpression;
|
||||||
|
|
|
@ -2,12 +2,13 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Upsilon.Parser
|
namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
public class LiteralExpressionSyntax : ExpressionSyntax
|
public sealed class LiteralExpressionSyntax : ExpressionSyntax
|
||||||
{
|
{
|
||||||
public LiteralExpressionSyntax(SyntaxToken literal, object value)
|
public LiteralExpressionSyntax(SyntaxToken literal, object value)
|
||||||
{
|
{
|
||||||
Literal = literal;
|
Literal = literal;
|
||||||
Value = value;
|
Value = value;
|
||||||
|
Span = literal.Span;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SyntaxKind Kind => SyntaxKind.LiteralExpression;
|
public override SyntaxKind Kind => SyntaxKind.LiteralExpression;
|
||||||
|
|
|
@ -10,6 +10,6 @@ namespace Upsilon.Text
|
||||||
|
|
||||||
public int Start { get; }
|
public int Start { get; }
|
||||||
public int Length { get; }
|
public int Length { get; }
|
||||||
public int End => Start + End;
|
public int End => Start + Length;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,7 +20,7 @@ namespace Yc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parsed = new Script(input, variables);
|
var parsed = new Script(input);
|
||||||
if (parsed.Diagnostics.Messages.Count > 0)
|
if (parsed.Diagnostics.Messages.Count > 0)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
@ -47,7 +47,7 @@ namespace Yc
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine(evaluate);
|
Console.WriteLine(evaluate);
|
||||||
variables = parsed.Variables;
|
//variables = parsed.Variables;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue