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 Upsilon.BaseTypes;
|
||||
using Upsilon.Parser;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon
|
||||
|
@ -37,6 +39,16 @@ namespace Upsilon
|
|||
{
|
||||
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
|
||||
|
@ -71,7 +83,7 @@ namespace Upsilon
|
|||
|
||||
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 Upsilon.BaseTypes.Number;
|
||||
using Upsilon.Binder;
|
||||
using Upsilon.Parser;
|
||||
|
||||
namespace Upsilon.Evaluator
|
||||
|
@ -7,46 +9,39 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
private readonly Diagnostics _diagnostics;
|
||||
public Script Script { get; }
|
||||
public VariableScope Scope { get; }
|
||||
|
||||
public Evaluator(Script script, VariableScope scope, Diagnostics diagnostics)
|
||||
public Evaluator(Script script, Diagnostics diagnostics)
|
||||
{
|
||||
_diagnostics = diagnostics;
|
||||
Script = script;
|
||||
Scope = scope;
|
||||
}
|
||||
|
||||
/*
|
||||
public object Evaluate(ScriptSyntax e)
|
||||
{
|
||||
return EvaluateExpression(e.Statement);
|
||||
}*/
|
||||
|
||||
public object Evaluate(BoundScript e)
|
||||
{
|
||||
return EvaluateExpression(e.Statement);
|
||||
}
|
||||
|
||||
public object Evaluate(ExpressionSyntax e)
|
||||
{
|
||||
return EvaluateExpression(e);
|
||||
}
|
||||
|
||||
private object EvaluateExpression(ExpressionSyntax e)
|
||||
private object EvaluateExpression(BoundExpression 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);
|
||||
case BoundKind.BoundLiteralExpression:
|
||||
return ((BoundLiteralExpression) e).Value;
|
||||
case BoundKind.BoundBinaryExpression:
|
||||
return EvaluateBinaryExpression((BoundBinaryExpression) e);
|
||||
default:
|
||||
throw new Exception("Invalid expression: " + e.Kind);
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/*
|
||||
private object EvaluateUnaryExpression(UnaryExpressionSyntax e)
|
||||
{
|
||||
var operand = EvaluateExpression(e.Expression);
|
||||
|
@ -61,66 +56,42 @@ namespace Upsilon.Evaluator
|
|||
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
|
||||
private object EvaluateBinaryExpression(BoundBinaryExpression e)
|
||||
{
|
||||
var left = EvaluateExpression(e.LeftExpression);
|
||||
var right = EvaluateExpression(e.RightExpression);
|
||||
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:
|
||||
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 SyntaxKind.TildeEquals:
|
||||
case BoundBinaryOperator.OperatorKind.Inequality:
|
||||
return !Equals(left, right);
|
||||
default:
|
||||
throw new Exception("Invalid Binary Operator: " + e.Operator.Kind);
|
||||
}
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
_diagnostics.LogNullReferenceError(e.Span);
|
||||
return null;
|
||||
throw new Exception("Invalid Binary Operator: " + e.Operator);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,41 +1,37 @@
|
|||
using System.Collections.Generic;
|
||||
using Upsilon.Binder;
|
||||
using Upsilon.Parser;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.Evaluator
|
||||
{
|
||||
public class Script : VariableScope
|
||||
public class Script
|
||||
{
|
||||
private SourceText ScriptString { get; }
|
||||
private Evaluator Evaluator { get; }
|
||||
public readonly ScriptSyntax Parsed;
|
||||
private readonly ScriptSyntax _parsed;
|
||||
public Diagnostics Diagnostics { get; }
|
||||
private Binder.Binder Binder { get; }
|
||||
|
||||
public Script(string scriptString)
|
||||
{
|
||||
ScriptString = new SourceText(scriptString);
|
||||
Diagnostics = new Diagnostics(ScriptString);
|
||||
Parsed = Parser.Parser.Parse(scriptString, Diagnostics);
|
||||
Evaluator = new Evaluator(this, 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);
|
||||
_parsed = Parser.Parser.Parse(scriptString, Diagnostics);
|
||||
Binder = new Binder.Binder(new BoundScope(null), Diagnostics);
|
||||
Evaluator = new Evaluator(this, Diagnostics);
|
||||
}
|
||||
|
||||
public object Evaluate()
|
||||
{
|
||||
return Evaluator.Evaluate(Parsed);
|
||||
var bound = Binder.BindScript(_parsed);
|
||||
return Evaluator.Evaluate(bound);
|
||||
}
|
||||
|
||||
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 IEnumerable<SyntaxNode> ChildNodes()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.Parser
|
||||
{
|
||||
public class BinaryExpressionSyntax : ExpressionSyntax
|
||||
public sealed class BinaryExpressionSyntax : ExpressionSyntax
|
||||
{
|
||||
public BinaryExpressionSyntax(ExpressionSyntax left, SyntaxToken @operator, ExpressionSyntax right)
|
||||
{
|
||||
Left = left;
|
||||
Operator = @operator;
|
||||
Right = right;
|
||||
Span = new TextSpan(left.Span.Start, right.Span.End);
|
||||
}
|
||||
|
||||
public override SyntaxKind Kind => SyntaxKind.BinaryExpression;
|
||||
|
|
|
@ -2,12 +2,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Upsilon.Parser
|
||||
{
|
||||
public class LiteralExpressionSyntax : ExpressionSyntax
|
||||
public sealed class LiteralExpressionSyntax : ExpressionSyntax
|
||||
{
|
||||
public LiteralExpressionSyntax(SyntaxToken literal, object value)
|
||||
{
|
||||
Literal = literal;
|
||||
Value = value;
|
||||
Span = literal.Span;
|
||||
}
|
||||
|
||||
public override SyntaxKind Kind => SyntaxKind.LiteralExpression;
|
||||
|
|
|
@ -10,6 +10,6 @@ namespace Upsilon.Text
|
|||
|
||||
public int Start { get; }
|
||||
public int Length { get; }
|
||||
public int End => Start + End;
|
||||
public int End => Start + Length;
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ namespace Yc
|
|||
return;
|
||||
}
|
||||
|
||||
var parsed = new Script(input, variables);
|
||||
var parsed = new Script(input);
|
||||
if (parsed.Diagnostics.Messages.Count > 0)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
|
@ -47,7 +47,7 @@ namespace Yc
|
|||
else
|
||||
{
|
||||
Console.WriteLine(evaluate);
|
||||
variables = parsed.Variables;
|
||||
//variables = parsed.Variables;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue