Bind unary operators

This commit is contained in:
Deukhoofd 2018-11-11 19:56:53 +01:00
parent 4e331712a8
commit 82dff87d4d
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
9 changed files with 119 additions and 23 deletions

View File

@ -51,6 +51,12 @@ namespace Upsilon.BaseTypes.Number
} }
#endregion #endregion
public static Number operator - (Number n)
{
if (n.IsFloat)
return new NumberDouble(-((NumberDouble)n).Value);
return new NumberLong(-((NumberLong)n).Value);
}
#region Equality #region Equality
private bool Equals(Number other) private bool Equals(Number other)

View File

@ -28,7 +28,7 @@ namespace Upsilon.Binder
switch (e.Kind) switch (e.Kind)
{ {
case SyntaxKind.UnaryExpression: case SyntaxKind.UnaryExpression:
break; return BindUnaryExpression((UnaryExpressionSyntax) e);
case SyntaxKind.BinaryExpression: case SyntaxKind.BinaryExpression:
return BindBinaryExpression((BinaryExpressionSyntax) e); return BindBinaryExpression((BinaryExpressionSyntax) e);
case SyntaxKind.LiteralExpression: case SyntaxKind.LiteralExpression:
@ -49,14 +49,27 @@ namespace Upsilon.Binder
throw new NotImplementedException(e.Kind.ToString()); 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) private BoundExpression BindBinaryExpression(BinaryExpressionSyntax e)
{ {
var left = BindExpression(e.Left); var left = BindExpression(e.Left);
var right = BindExpression(e.Right); 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) 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 left;
} }
return new BoundBinaryExpression(op, left, right, op.OutType); return new BoundBinaryExpression(op, left, right, op.OutType);

View File

@ -50,7 +50,7 @@ namespace Upsilon.Binder
new BoundBinaryOperator(OperatorKind.Inequality, Type.Boolean), 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; OperatorKind kind;
switch (operatorToken) switch (operatorToken)

View File

@ -6,5 +6,6 @@ namespace Upsilon.Binder
BoundLiteralExpression, BoundLiteralExpression,
BoundBinaryExpression, BoundBinaryExpression,
BoundUnaryExpression
} }
} }

View File

@ -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; }
}
}

View File

@ -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);
}
}
}

View File

@ -45,10 +45,16 @@ namespace Upsilon
LogError($"Unknown Type found", eSpan); 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); 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 public class DiagnosticsMessage

View File

@ -16,12 +16,6 @@ namespace Upsilon.Evaluator
Script = script; Script = script;
} }
/*
public object Evaluate(ScriptSyntax e)
{
return EvaluateExpression(e.Statement);
}*/
public object Evaluate(BoundScript e) public object Evaluate(BoundScript e)
{ {
return EvaluateExpression(e.Statement); return EvaluateExpression(e.Statement);
@ -35,28 +29,28 @@ namespace Upsilon.Evaluator
return ((BoundLiteralExpression) e).Value; return ((BoundLiteralExpression) e).Value;
case BoundKind.BoundBinaryExpression: case BoundKind.BoundBinaryExpression:
return EvaluateBinaryExpression((BoundBinaryExpression) e); return EvaluateBinaryExpression((BoundBinaryExpression) e);
case BoundKind.BoundUnaryExpression:
return EvaluateUnaryExpression((BoundUnaryExpression) e);
default: default:
throw new ArgumentOutOfRangeException(); throw new NotImplementedException();
} }
throw new NotImplementedException();
} }
/* private object EvaluateUnaryExpression(BoundUnaryExpression e)
private object EvaluateUnaryExpression(UnaryExpressionSyntax e)
{ {
var operand = EvaluateExpression(e.Expression); var operand = EvaluateExpression(e.InExpression);
switch (e.Operator.Kind) switch (e.Operator.Kind)
{ {
case SyntaxKind.Plus: case BoundUnaryOperator.OperatorKind.Identity:
return operand; return operand;
case SyntaxKind.Minus: case BoundUnaryOperator.OperatorKind.Negation:
return -(double) operand; return -((Number)operand);
case SyntaxKind.NotKeyword: case BoundUnaryOperator.OperatorKind.LogicalNegation:
return !(bool)operand; return !(bool) operand;
default: default:
throw new Exception("Invalid Unary Operator: " + e.Operator.Kind); throw new Exception("Invalid Unary Operator: " + e.Operator.Kind);
} }
}*/ }
private object EvaluateBinaryExpression(BoundBinaryExpression e) private object EvaluateBinaryExpression(BoundBinaryExpression e)
{ {

View File

@ -44,7 +44,7 @@ namespace Upsilon.Parser
if (Current.Kind == kind) if (Current.Kind == kind)
return NextToken(); return NextToken();
_diagnostics.LogBadCharacter(new TextSpan(_position, 1)); _diagnostics.LogBadCharacter(Current.Span);
return new SyntaxToken(kind, Current.Span.Start, "", null); return new SyntaxToken(kind, Current.Span.Start, "", null);
} }