From 3561979ded6b2ad25275e41f77942acc2df98071 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 11 Nov 2018 18:12:42 +0100 Subject: [PATCH] Lots of work on type binding --- Upsilon/BaseTypes/Number/Number.cs | 78 +++++++++++++ Upsilon/BaseTypes/Number/NumberDouble.cs | 25 +++++ Upsilon/BaseTypes/Number/NumberLong.cs | 25 +++++ Upsilon/BaseTypes/Type.cs | 14 +++ Upsilon/Binder/Binder.cs | 87 +++++++++++++++ Upsilon/Binder/BoundBinaryExpression.cs | 23 ++++ Upsilon/Binder/BoundBinaryOperator.cs | 83 ++++++++++++++ Upsilon/Binder/BoundExpression.cs | 9 ++ Upsilon/Binder/BoundKind.cs | 10 ++ Upsilon/Binder/BoundLiteralExpression.cs | 17 +++ Upsilon/Binder/BoundNode.cs | 7 ++ Upsilon/Binder/BoundScope.cs | 51 +++++++++ Upsilon/Binder/BoundScript.cs | 14 +++ Upsilon/Binder/VariableSymbol.cs | 16 +++ Upsilon/Diagnostics.cs | 14 ++- Upsilon/Evaluator/Evaluator.cs | 105 +++++++----------- Upsilon/Evaluator/Script.cs | 26 ++--- Upsilon/Evaluator/VariableScope.cs | 53 --------- .../ExpressionSyntax/BadExpressionSyntax.cs | 2 +- .../BinaryExpressionSyntax.cs | 4 +- .../LiteralExpressionSyntax.cs | 3 +- Upsilon/Text/TextSpan.cs | 2 +- Yc/Program.cs | 4 +- 23 files changed, 530 insertions(+), 142 deletions(-) create mode 100644 Upsilon/BaseTypes/Number/Number.cs create mode 100644 Upsilon/BaseTypes/Number/NumberDouble.cs create mode 100644 Upsilon/BaseTypes/Number/NumberLong.cs create mode 100644 Upsilon/BaseTypes/Type.cs create mode 100644 Upsilon/Binder/Binder.cs create mode 100644 Upsilon/Binder/BoundBinaryExpression.cs create mode 100644 Upsilon/Binder/BoundBinaryOperator.cs create mode 100644 Upsilon/Binder/BoundExpression.cs create mode 100644 Upsilon/Binder/BoundKind.cs create mode 100644 Upsilon/Binder/BoundLiteralExpression.cs create mode 100644 Upsilon/Binder/BoundNode.cs create mode 100644 Upsilon/Binder/BoundScope.cs create mode 100644 Upsilon/Binder/BoundScript.cs create mode 100644 Upsilon/Binder/VariableSymbol.cs delete mode 100644 Upsilon/Evaluator/VariableScope.cs diff --git a/Upsilon/BaseTypes/Number/Number.cs b/Upsilon/BaseTypes/Number/Number.cs new file mode 100644 index 0000000..4fd3b06 --- /dev/null +++ b/Upsilon/BaseTypes/Number/Number.cs @@ -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 + + } +} \ No newline at end of file diff --git a/Upsilon/BaseTypes/Number/NumberDouble.cs b/Upsilon/BaseTypes/Number/NumberDouble.cs new file mode 100644 index 0000000..1140fc2 --- /dev/null +++ b/Upsilon/BaseTypes/Number/NumberDouble.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/Upsilon/BaseTypes/Number/NumberLong.cs b/Upsilon/BaseTypes/Number/NumberLong.cs new file mode 100644 index 0000000..01a5364 --- /dev/null +++ b/Upsilon/BaseTypes/Number/NumberLong.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/Upsilon/BaseTypes/Type.cs b/Upsilon/BaseTypes/Type.cs new file mode 100644 index 0000000..184c332 --- /dev/null +++ b/Upsilon/BaseTypes/Type.cs @@ -0,0 +1,14 @@ +namespace Upsilon.BaseTypes +{ + public enum Type + { + Nil, + Boolean, + Number, + String, + Function, + UserData, + Thread, + Table + } +} \ No newline at end of file diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs new file mode 100644 index 0000000..f6dd792 --- /dev/null +++ b/Upsilon/Binder/Binder.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundBinaryExpression.cs b/Upsilon/Binder/BoundBinaryExpression.cs new file mode 100644 index 0000000..143faa6 --- /dev/null +++ b/Upsilon/Binder/BoundBinaryExpression.cs @@ -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; } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundBinaryOperator.cs b/Upsilon/Binder/BoundBinaryOperator.cs new file mode 100644 index 0000000..bfb82e7 --- /dev/null +++ b/Upsilon/Binder/BoundBinaryOperator.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundExpression.cs b/Upsilon/Binder/BoundExpression.cs new file mode 100644 index 0000000..31f8f40 --- /dev/null +++ b/Upsilon/Binder/BoundExpression.cs @@ -0,0 +1,9 @@ +using Upsilon.BaseTypes; + +namespace Upsilon.Binder +{ + public abstract class BoundExpression : BoundNode + { + public abstract Type Type { get; } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundKind.cs b/Upsilon/Binder/BoundKind.cs new file mode 100644 index 0000000..37d9cdc --- /dev/null +++ b/Upsilon/Binder/BoundKind.cs @@ -0,0 +1,10 @@ +namespace Upsilon.Binder +{ + public enum BoundKind + { + BoundScript, + + BoundLiteralExpression, + BoundBinaryExpression, + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundLiteralExpression.cs b/Upsilon/Binder/BoundLiteralExpression.cs new file mode 100644 index 0000000..e185602 --- /dev/null +++ b/Upsilon/Binder/BoundLiteralExpression.cs @@ -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; } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundNode.cs b/Upsilon/Binder/BoundNode.cs new file mode 100644 index 0000000..87639d6 --- /dev/null +++ b/Upsilon/Binder/BoundNode.cs @@ -0,0 +1,7 @@ +namespace Upsilon.Binder +{ + public abstract class BoundNode + { + public abstract BoundKind Kind { get; } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundScope.cs b/Upsilon/Binder/BoundScope.cs new file mode 100644 index 0000000..348cfbd --- /dev/null +++ b/Upsilon/Binder/BoundScope.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; + +namespace Upsilon.Binder +{ + public class BoundScope + { + private readonly BoundScope _parentScope; + private readonly Dictionary _variables; + + public BoundScope(BoundScope parentScope) + { + _parentScope = parentScope; + _variables = new Dictionary(); + } + + 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; + } + + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundScript.cs b/Upsilon/Binder/BoundScript.cs new file mode 100644 index 0000000..b6bf5d8 --- /dev/null +++ b/Upsilon/Binder/BoundScript.cs @@ -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; } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/VariableSymbol.cs b/Upsilon/Binder/VariableSymbol.cs new file mode 100644 index 0000000..9ea1efd --- /dev/null +++ b/Upsilon/Binder/VariableSymbol.cs @@ -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; } + } +} \ No newline at end of file diff --git a/Upsilon/Diagnostics.cs b/Upsilon/Diagnostics.cs index 5e7f405..4071b24 100644 --- a/Upsilon/Diagnostics.cs +++ b/Upsilon/Diagnostics.cs @@ -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); } } diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index c85a56d..d750737 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -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) + private object EvaluateBinaryExpression(BoundBinaryExpression e) { - var left = EvaluateExpression(e.Left); - var right = EvaluateExpression(e.Right); - try + var left = EvaluateExpression(e.LeftExpression); + var right = EvaluateExpression(e.RightExpression); + switch (e.Operator.Kind) { - 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; + 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); } } + /* 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; } diff --git a/Upsilon/Evaluator/Script.cs b/Upsilon/Evaluator/Script.cs index 4cefd72..08a537e 100644 --- a/Upsilon/Evaluator/Script.cs +++ b/Upsilon/Evaluator/Script.cs @@ -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 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() { - return (T)Evaluator.Evaluate(Parsed); + var bound = Binder.BindScript(_parsed); + return (T)Evaluator.Evaluate(bound); } } } \ No newline at end of file diff --git a/Upsilon/Evaluator/VariableScope.cs b/Upsilon/Evaluator/VariableScope.cs deleted file mode 100644 index fe98f38..0000000 --- a/Upsilon/Evaluator/VariableScope.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Upsilon.Evaluator -{ - public class VariableScope - { - private VariableScope _parentScope; - public readonly Dictionary Variables = new Dictionary(); - - public VariableScope(VariableScope parentScope = null, Dictionary 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; - } - } -} \ No newline at end of file diff --git a/Upsilon/Parser/ExpressionSyntax/BadExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/BadExpressionSyntax.cs index 35ff20e..ead605e 100644 --- a/Upsilon/Parser/ExpressionSyntax/BadExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/BadExpressionSyntax.cs @@ -7,7 +7,7 @@ namespace Upsilon.Parser public override SyntaxKind Kind => SyntaxKind.BadExpression; public override IEnumerable ChildNodes() { - throw new System.NotImplementedException(); + yield break; } } } \ No newline at end of file diff --git a/Upsilon/Parser/ExpressionSyntax/BinaryExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/BinaryExpressionSyntax.cs index 5b4522d..9d9152f 100644 --- a/Upsilon/Parser/ExpressionSyntax/BinaryExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/BinaryExpressionSyntax.cs @@ -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; diff --git a/Upsilon/Parser/ExpressionSyntax/LiteralExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/LiteralExpressionSyntax.cs index 1a09b1d..bb6c480 100644 --- a/Upsilon/Parser/ExpressionSyntax/LiteralExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/LiteralExpressionSyntax.cs @@ -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; diff --git a/Upsilon/Text/TextSpan.cs b/Upsilon/Text/TextSpan.cs index 8990676..2f6264d 100644 --- a/Upsilon/Text/TextSpan.cs +++ b/Upsilon/Text/TextSpan.cs @@ -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; } } \ No newline at end of file diff --git a/Yc/Program.cs b/Yc/Program.cs index a706b4b..0c0004a 100644 --- a/Yc/Program.cs +++ b/Yc/Program.cs @@ -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; } } }