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
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)

View File

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

View File

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

View File

@ -6,5 +6,6 @@ namespace Upsilon.Binder
BoundLiteralExpression,
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);
}
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

View File

@ -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)
{

View File

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