Implement number comparison operators
This commit is contained in:
parent
a9f4ef1b65
commit
6ba3860e84
|
@ -60,6 +60,7 @@ namespace Upsilon.BaseTypes.Number
|
|||
return new ScriptNumberLong(-((ScriptNumberLong)n).Value);
|
||||
}
|
||||
|
||||
|
||||
#region Equality
|
||||
private bool Equals(ScriptNumber other)
|
||||
{
|
||||
|
@ -82,6 +83,40 @@ namespace Upsilon.BaseTypes.Number
|
|||
|
||||
#endregion
|
||||
|
||||
public static ScriptBoolean operator < (ScriptNumber a, ScriptNumber b)
|
||||
{
|
||||
if (!a.IsFloat && !b.IsFloat)
|
||||
return new ScriptBoolean(((ScriptNumberLong) a).Value < ((ScriptNumberLong) b).Value);
|
||||
if (a.IsFloat && b.IsFloat)
|
||||
return new ScriptBoolean(((ScriptNumberDouble) a).Value < ((ScriptNumberDouble) b).Value);
|
||||
if (a.IsFloat)
|
||||
return new ScriptBoolean(((ScriptNumberDouble) a).Value < ((ScriptNumberLong) b).Value);
|
||||
return new ScriptBoolean(((ScriptNumberLong) a).Value < ((ScriptNumberDouble) b).Value);
|
||||
}
|
||||
|
||||
public static ScriptBoolean operator > (ScriptNumber a, ScriptNumber b)
|
||||
{
|
||||
if (!a.IsFloat && !b.IsFloat)
|
||||
return new ScriptBoolean(((ScriptNumberLong) a).Value > ((ScriptNumberLong) b).Value);
|
||||
if (a.IsFloat && b.IsFloat)
|
||||
return new ScriptBoolean(((ScriptNumberDouble) a).Value > ((ScriptNumberDouble) b).Value);
|
||||
if (a.IsFloat)
|
||||
return new ScriptBoolean(((ScriptNumberDouble) a).Value > ((ScriptNumberLong) b).Value);
|
||||
return new ScriptBoolean(((ScriptNumberLong) a).Value > ((ScriptNumberDouble) b).Value);
|
||||
}
|
||||
|
||||
public static ScriptBoolean operator <= (ScriptNumber a, ScriptNumber b)
|
||||
{
|
||||
return (a < b) || a.Equals(b);
|
||||
}
|
||||
|
||||
public static ScriptBoolean operator >= (ScriptNumber a, ScriptNumber b)
|
||||
{
|
||||
return !(a < b) || a.Equals(b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static explicit operator double(ScriptNumber n)
|
||||
{
|
||||
if (n.IsFloat)
|
||||
|
|
|
@ -9,7 +9,11 @@ namespace Upsilon.Binder
|
|||
{
|
||||
public enum OperatorKind
|
||||
{
|
||||
Addition, Subtraction, Multiplication, Division, Equality, Inequality
|
||||
Addition, Subtraction, Multiplication, Division, Equality, Inequality,
|
||||
GreaterEquals,
|
||||
Greater,
|
||||
LessEquals,
|
||||
Less
|
||||
}
|
||||
|
||||
private Type LeftType { get; }
|
||||
|
@ -45,6 +49,12 @@ namespace Upsilon.Binder
|
|||
new BoundBinaryOperator(OperatorKind.Equality, Type.Number, Type.Number, Type.Boolean),
|
||||
new BoundBinaryOperator(OperatorKind.Inequality, Type.Number, Type.Number, Type.Boolean),
|
||||
|
||||
// Number comparison
|
||||
new BoundBinaryOperator(OperatorKind.Less, Type.Number, Type.Number, Type.Boolean),
|
||||
new BoundBinaryOperator(OperatorKind.LessEquals, Type.Number, Type.Number, Type.Boolean),
|
||||
new BoundBinaryOperator(OperatorKind.Greater, Type.Number, Type.Number, Type.Boolean),
|
||||
new BoundBinaryOperator(OperatorKind.GreaterEquals, Type.Number, Type.Number, Type.Boolean),
|
||||
|
||||
// Boolean equality
|
||||
new BoundBinaryOperator(OperatorKind.Equality, Type.Boolean),
|
||||
new BoundBinaryOperator(OperatorKind.Inequality, Type.Boolean),
|
||||
|
@ -82,6 +92,18 @@ namespace Upsilon.Binder
|
|||
case SyntaxKind.TildeEquals:
|
||||
kind = OperatorKind.Inequality;
|
||||
break;
|
||||
case SyntaxKind.Less:
|
||||
kind = OperatorKind.Less;
|
||||
break;
|
||||
case SyntaxKind.LessEquals:
|
||||
kind = OperatorKind.LessEquals;
|
||||
break;
|
||||
case SyntaxKind.Greater:
|
||||
kind = OperatorKind.Greater;
|
||||
break;
|
||||
case SyntaxKind.GreaterEquals:
|
||||
kind = OperatorKind.GreaterEquals;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown binary operator token: " + operatorToken);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
|||
using Upsilon.BaseTypes.UserData;
|
||||
using Upsilon.Binder;
|
||||
using Upsilon.Binder.VariableSymbols;
|
||||
using Upsilon.Exceptions;
|
||||
using Upsilon.Text;
|
||||
using Type = Upsilon.BaseTypes.Type;
|
||||
|
||||
namespace Upsilon.Evaluator
|
||||
|
@ -328,11 +330,47 @@ namespace Upsilon.Evaluator
|
|||
return new ScriptBoolean(Equals(left, right));
|
||||
case BoundBinaryOperator.OperatorKind.Inequality:
|
||||
return new ScriptBoolean(!Equals(left, right));
|
||||
case BoundBinaryOperator.OperatorKind.Less:
|
||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||
{
|
||||
return ((ScriptNumber)left) < ((ScriptNumber)right);
|
||||
}
|
||||
ThrowException($"Can't find operator for types '{left.Type}' and '{right.Type}'", e.Span);
|
||||
return new ScriptNull();
|
||||
case BoundBinaryOperator.OperatorKind.LessEquals:
|
||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||
{
|
||||
return ((ScriptNumber)left) <= ((ScriptNumber)right);
|
||||
}
|
||||
ThrowException($"Can't find operator for types '{left.Type}' and '{right.Type}'", e.Span);
|
||||
return new ScriptNull();
|
||||
case BoundBinaryOperator.OperatorKind.Greater:
|
||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||
{
|
||||
return ((ScriptNumber)left) > ((ScriptNumber)right);
|
||||
}
|
||||
ThrowException($"Can't find operator for types '{left.Type}' and '{right.Type}'", e.Span);
|
||||
return new ScriptNull();
|
||||
case BoundBinaryOperator.OperatorKind.GreaterEquals:
|
||||
if (left.Type == Type.Number && right.Type == Type.Number)
|
||||
{
|
||||
return ((ScriptNumber)left) >= ((ScriptNumber)right);
|
||||
}
|
||||
ThrowException($"Can't find operator for types '{left.Type}' and '{right.Type}'", e.Span);
|
||||
return new ScriptNull();
|
||||
|
||||
default:
|
||||
throw new Exception("Invalid Binary Operator: " + e.Operator);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowException(string message, TextSpan location)
|
||||
{
|
||||
var (i, pos) = _script.ScriptString.GetLinePosition(location.Start);
|
||||
var line = _script.ScriptString.GetLine(i);
|
||||
throw new ScriptRuntimeException(message, i, pos, line);
|
||||
}
|
||||
|
||||
private void EvaluateAssignmentStatement(BoundVariableAssignment e)
|
||||
{
|
||||
var val = EvaluateExpression(e.BoundExpression);
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
|
||||
namespace Upsilon.Exceptions
|
||||
{
|
||||
public class ScriptRuntimeException : Exception
|
||||
{
|
||||
public string ErrorMessage { get; }
|
||||
public int Line { get; }
|
||||
public int Character { get; }
|
||||
public string ErrorLine { get; }
|
||||
|
||||
public ScriptRuntimeException(string errorMessage, int line, int character, string errorLine)
|
||||
{
|
||||
ErrorMessage = errorMessage;
|
||||
Line = line;
|
||||
Character = character;
|
||||
ErrorLine = errorLine;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ErrorMessage} at ({Line}, {Character})\n{ErrorLine}";
|
||||
}
|
||||
|
||||
public override string Message => ToString();
|
||||
}
|
||||
}
|
|
@ -118,6 +118,20 @@ namespace Upsilon.Parser
|
|||
return new SyntaxToken(SyntaxKind.TildeEquals, _position - 1, "~=", null);
|
||||
}
|
||||
return new SyntaxToken(SyntaxKind.Tilde, _position, "~", null);
|
||||
case '<':
|
||||
if (Next == '=')
|
||||
{
|
||||
_position++;
|
||||
return new SyntaxToken(SyntaxKind.LessEquals, _position - 1, "<=", null);
|
||||
}
|
||||
return new SyntaxToken(SyntaxKind.Less, _position, "<", null);
|
||||
case '>':
|
||||
if (Next == '=')
|
||||
{
|
||||
_position++;
|
||||
return new SyntaxToken(SyntaxKind.GreaterEquals, _position - 1, ">=", null);
|
||||
}
|
||||
return new SyntaxToken(SyntaxKind.Greater, _position, ">", null);
|
||||
default:
|
||||
if (char.IsLetter(Current) || Current == '_')
|
||||
return LexIdentifierOrKeyword();
|
||||
|
|
|
@ -29,6 +29,10 @@ namespace Upsilon.Parser
|
|||
OpenBracket,
|
||||
CloseBracket,
|
||||
PoundSign,
|
||||
Less,
|
||||
LessEquals,
|
||||
Greater,
|
||||
GreaterEquals,
|
||||
|
||||
// key words
|
||||
TrueKeyword,
|
||||
|
|
|
@ -34,8 +34,12 @@ namespace Upsilon.Parser
|
|||
{
|
||||
// equality operators
|
||||
case SyntaxKind.EqualsEquals:
|
||||
return Precedence.Equality;
|
||||
case SyntaxKind.TildeEquals:
|
||||
|
||||
case SyntaxKind.Greater:
|
||||
case SyntaxKind.GreaterEquals:
|
||||
case SyntaxKind.Less:
|
||||
case SyntaxKind.LessEquals:
|
||||
return Precedence.Equality;
|
||||
|
||||
// logical operators
|
||||
|
|
Loading…
Reference in New Issue