From 82dff87d4dc0d3640236b421ed5e99fd602d6184 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 11 Nov 2018 19:56:53 +0100 Subject: [PATCH] Bind unary operators --- Upsilon/BaseTypes/Number/Number.cs | 6 +++ Upsilon/Binder/Binder.cs | 19 +++++++-- Upsilon/Binder/BoundBinaryOperator.cs | 2 +- Upsilon/Binder/BoundKind.cs | 1 + Upsilon/Binder/BoundUnaryExpression.cs | 20 +++++++++ Upsilon/Binder/BoundUnaryOperator.cs | 56 ++++++++++++++++++++++++++ Upsilon/Diagnostics.cs | 8 +++- Upsilon/Evaluator/Evaluator.cs | 28 +++++-------- Upsilon/Parser/Parser.cs | 2 +- 9 files changed, 119 insertions(+), 23 deletions(-) create mode 100644 Upsilon/Binder/BoundUnaryExpression.cs create mode 100644 Upsilon/Binder/BoundUnaryOperator.cs diff --git a/Upsilon/BaseTypes/Number/Number.cs b/Upsilon/BaseTypes/Number/Number.cs index 4fd3b06..1f59f8f 100644 --- a/Upsilon/BaseTypes/Number/Number.cs +++ b/Upsilon/BaseTypes/Number/Number.cs @@ -51,6 +51,12 @@ namespace Upsilon.BaseTypes.Number } #endregion + public static Number operator - (Number n) + { + if (n.IsFloat) + return new NumberDouble(-((NumberDouble)n).Value); + return new NumberLong(-((NumberLong)n).Value); + } #region Equality private bool Equals(Number other) diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 76900c4..3fe2d3a 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -28,7 +28,7 @@ namespace Upsilon.Binder switch (e.Kind) { case SyntaxKind.UnaryExpression: - break; + return BindUnaryExpression((UnaryExpressionSyntax) e); case SyntaxKind.BinaryExpression: return BindBinaryExpression((BinaryExpressionSyntax) e); case SyntaxKind.LiteralExpression: @@ -49,14 +49,27 @@ namespace Upsilon.Binder throw new NotImplementedException(e.Kind.ToString()); } + private BoundExpression BindUnaryExpression(UnaryExpressionSyntax e) + { + var inExp = BindExpression(e.Expression); + var op = BoundUnaryOperator.Bind(e.Operator.Kind, inExp.Type); + if (op == null) + { + _diagnostics.LogUnknownUnaryOperator(e.Span, e.Operator.Kind, inExp.Type); + return inExp; + } + + return new BoundUnaryExpression(op, inExp, op.OutType); + } + 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); + var op = BoundBinaryOperator.Bind(e.Operator.Kind, left.Type, right.Type); if (op == null) { - _diagnostics.LogUnknownOperator(e.Span, e.Operator.Kind, left.Type, right.Type); + _diagnostics.LogUnknownBinaryOperator(e.Span, e.Operator.Kind, left.Type, right.Type); return left; } return new BoundBinaryExpression(op, left, right, op.OutType); diff --git a/Upsilon/Binder/BoundBinaryOperator.cs b/Upsilon/Binder/BoundBinaryOperator.cs index bfb82e7..1330bea 100644 --- a/Upsilon/Binder/BoundBinaryOperator.cs +++ b/Upsilon/Binder/BoundBinaryOperator.cs @@ -50,7 +50,7 @@ namespace Upsilon.Binder new BoundBinaryOperator(OperatorKind.Inequality, Type.Boolean), }; - public static BoundBinaryOperator BindBinaryOperator(SyntaxKind operatorToken, Type left, Type right) + public static BoundBinaryOperator Bind(SyntaxKind operatorToken, Type left, Type right) { OperatorKind kind; switch (operatorToken) diff --git a/Upsilon/Binder/BoundKind.cs b/Upsilon/Binder/BoundKind.cs index 37d9cdc..caf80fd 100644 --- a/Upsilon/Binder/BoundKind.cs +++ b/Upsilon/Binder/BoundKind.cs @@ -6,5 +6,6 @@ namespace Upsilon.Binder BoundLiteralExpression, BoundBinaryExpression, + BoundUnaryExpression } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundUnaryExpression.cs b/Upsilon/Binder/BoundUnaryExpression.cs new file mode 100644 index 0000000..77d9555 --- /dev/null +++ b/Upsilon/Binder/BoundUnaryExpression.cs @@ -0,0 +1,20 @@ +using Upsilon.BaseTypes; + +namespace Upsilon.Binder +{ + public class BoundUnaryExpression : BoundExpression + { + public override BoundKind Kind => BoundKind.BoundUnaryExpression; + public override Type Type { get; } + + public BoundUnaryExpression(BoundUnaryOperator op, BoundExpression inExpression, Type type) + { + Operator = op; + InExpression = inExpression; + Type = type; + } + + public BoundExpression InExpression { get; } + public BoundUnaryOperator Operator { get; } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundUnaryOperator.cs b/Upsilon/Binder/BoundUnaryOperator.cs new file mode 100644 index 0000000..2caa6e0 --- /dev/null +++ b/Upsilon/Binder/BoundUnaryOperator.cs @@ -0,0 +1,56 @@ +using System; +using System.Linq; +using Upsilon.Parser; +using Type = Upsilon.BaseTypes.Type; + +namespace Upsilon.Binder +{ + public class BoundUnaryOperator + { + public enum OperatorKind + { + Identity, + Negation, + LogicalNegation + } + + public Type InType { get; } + public Type OutType { get; } + public OperatorKind Kind { get; } + + private BoundUnaryOperator(OperatorKind kind, Type inType, Type outType) + { + Kind = kind; + InType = inType; + OutType = outType; + } + + private static BoundUnaryOperator[] _operators= new BoundUnaryOperator[] + { + new BoundUnaryOperator(OperatorKind.Identity, Type.Number, Type.Number), + new BoundUnaryOperator(OperatorKind.Negation, Type.Number, Type.Number), + new BoundUnaryOperator(OperatorKind.LogicalNegation, Type.Boolean, Type.Boolean), + }; + + public static BoundUnaryOperator Bind(SyntaxKind operatorToken, Type inType) + { + OperatorKind kind; + switch (operatorToken) + { + case SyntaxKind.Plus: + kind = OperatorKind.Identity; + break; + case SyntaxKind.Minus: + kind = OperatorKind.Negation; + break; + case SyntaxKind.NotKeyword: + kind = OperatorKind.LogicalNegation; + break; + default: + throw new Exception("Unknown unary operator token: " + operatorToken); + } + + return _operators.FirstOrDefault(op => op.Kind == kind && op.InType == inType); + } + } +} \ No newline at end of file diff --git a/Upsilon/Diagnostics.cs b/Upsilon/Diagnostics.cs index 4071b24..6a00fc1 100644 --- a/Upsilon/Diagnostics.cs +++ b/Upsilon/Diagnostics.cs @@ -45,10 +45,16 @@ namespace Upsilon LogError($"Unknown Type found", eSpan); } - public void LogUnknownOperator(TextSpan eSpan, SyntaxKind text, Type leftType, Type rightType) + public void LogUnknownBinaryOperator(TextSpan eSpan, SyntaxKind text, Type leftType, Type rightType) { LogError($"No binary operator {text} found for types '{leftType}' and '{rightType}'", eSpan); } + + public void LogUnknownUnaryOperator(TextSpan eSpan, SyntaxKind text, Type inType) + { + LogError($"No unary operator {text} found for type '{inType}'", eSpan); + } + } public class DiagnosticsMessage diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index d750737..cd5e75c 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -16,12 +16,6 @@ namespace Upsilon.Evaluator Script = script; } - /* - public object Evaluate(ScriptSyntax e) - { - return EvaluateExpression(e.Statement); - }*/ - public object Evaluate(BoundScript e) { return EvaluateExpression(e.Statement); @@ -35,28 +29,28 @@ namespace Upsilon.Evaluator return ((BoundLiteralExpression) e).Value; case BoundKind.BoundBinaryExpression: return EvaluateBinaryExpression((BoundBinaryExpression) e); + case BoundKind.BoundUnaryExpression: + return EvaluateUnaryExpression((BoundUnaryExpression) e); default: - throw new ArgumentOutOfRangeException(); + throw new NotImplementedException(); } - throw new NotImplementedException(); } - /* - private object EvaluateUnaryExpression(UnaryExpressionSyntax e) + private object EvaluateUnaryExpression(BoundUnaryExpression e) { - var operand = EvaluateExpression(e.Expression); + var operand = EvaluateExpression(e.InExpression); switch (e.Operator.Kind) { - case SyntaxKind.Plus: + case BoundUnaryOperator.OperatorKind.Identity: return operand; - case SyntaxKind.Minus: - return -(double) operand; - case SyntaxKind.NotKeyword: - return !(bool)operand; + case BoundUnaryOperator.OperatorKind.Negation: + return -((Number)operand); + case BoundUnaryOperator.OperatorKind.LogicalNegation: + return !(bool) operand; default: throw new Exception("Invalid Unary Operator: " + e.Operator.Kind); } - }*/ + } private object EvaluateBinaryExpression(BoundBinaryExpression e) { diff --git a/Upsilon/Parser/Parser.cs b/Upsilon/Parser/Parser.cs index 40c5bb5..2f28030 100644 --- a/Upsilon/Parser/Parser.cs +++ b/Upsilon/Parser/Parser.cs @@ -44,7 +44,7 @@ namespace Upsilon.Parser if (Current.Kind == kind) return NextToken(); - _diagnostics.LogBadCharacter(new TextSpan(_position, 1)); + _diagnostics.LogBadCharacter(Current.Span); return new SyntaxToken(kind, Current.Span.Start, "", null); }