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);
|
return new ScriptNumberLong(-((ScriptNumberLong)n).Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region Equality
|
#region Equality
|
||||||
private bool Equals(ScriptNumber other)
|
private bool Equals(ScriptNumber other)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +83,40 @@ namespace Upsilon.BaseTypes.Number
|
||||||
|
|
||||||
#endregion
|
#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)
|
public static explicit operator double(ScriptNumber n)
|
||||||
{
|
{
|
||||||
if (n.IsFloat)
|
if (n.IsFloat)
|
||||||
|
|
|
@ -9,7 +9,11 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
public enum OperatorKind
|
public enum OperatorKind
|
||||||
{
|
{
|
||||||
Addition, Subtraction, Multiplication, Division, Equality, Inequality
|
Addition, Subtraction, Multiplication, Division, Equality, Inequality,
|
||||||
|
GreaterEquals,
|
||||||
|
Greater,
|
||||||
|
LessEquals,
|
||||||
|
Less
|
||||||
}
|
}
|
||||||
|
|
||||||
private Type LeftType { get; }
|
private Type LeftType { get; }
|
||||||
|
@ -45,6 +49,12 @@ namespace Upsilon.Binder
|
||||||
new BoundBinaryOperator(OperatorKind.Equality, Type.Number, Type.Number, Type.Boolean),
|
new BoundBinaryOperator(OperatorKind.Equality, Type.Number, Type.Number, Type.Boolean),
|
||||||
new BoundBinaryOperator(OperatorKind.Inequality, 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
|
// Boolean equality
|
||||||
new BoundBinaryOperator(OperatorKind.Equality, Type.Boolean),
|
new BoundBinaryOperator(OperatorKind.Equality, Type.Boolean),
|
||||||
new BoundBinaryOperator(OperatorKind.Inequality, Type.Boolean),
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.Boolean),
|
||||||
|
@ -82,6 +92,18 @@ namespace Upsilon.Binder
|
||||||
case SyntaxKind.TildeEquals:
|
case SyntaxKind.TildeEquals:
|
||||||
kind = OperatorKind.Inequality;
|
kind = OperatorKind.Inequality;
|
||||||
break;
|
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:
|
default:
|
||||||
throw new Exception("Unknown binary operator token: " + operatorToken);
|
throw new Exception("Unknown binary operator token: " + operatorToken);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||||
using Upsilon.BaseTypes.UserData;
|
using Upsilon.BaseTypes.UserData;
|
||||||
using Upsilon.Binder;
|
using Upsilon.Binder;
|
||||||
using Upsilon.Binder.VariableSymbols;
|
using Upsilon.Binder.VariableSymbols;
|
||||||
|
using Upsilon.Exceptions;
|
||||||
|
using Upsilon.Text;
|
||||||
using Type = Upsilon.BaseTypes.Type;
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
namespace Upsilon.Evaluator
|
namespace Upsilon.Evaluator
|
||||||
|
@ -328,11 +330,47 @@ namespace Upsilon.Evaluator
|
||||||
return new ScriptBoolean(Equals(left, right));
|
return new ScriptBoolean(Equals(left, right));
|
||||||
case BoundBinaryOperator.OperatorKind.Inequality:
|
case BoundBinaryOperator.OperatorKind.Inequality:
|
||||||
return new ScriptBoolean(!Equals(left, right));
|
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:
|
default:
|
||||||
throw new Exception("Invalid Binary Operator: " + e.Operator);
|
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)
|
private void EvaluateAssignmentStatement(BoundVariableAssignment e)
|
||||||
{
|
{
|
||||||
var val = EvaluateExpression(e.BoundExpression);
|
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.TildeEquals, _position - 1, "~=", null);
|
||||||
}
|
}
|
||||||
return new SyntaxToken(SyntaxKind.Tilde, _position, "~", 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:
|
default:
|
||||||
if (char.IsLetter(Current) || Current == '_')
|
if (char.IsLetter(Current) || Current == '_')
|
||||||
return LexIdentifierOrKeyword();
|
return LexIdentifierOrKeyword();
|
||||||
|
|
|
@ -29,6 +29,10 @@ namespace Upsilon.Parser
|
||||||
OpenBracket,
|
OpenBracket,
|
||||||
CloseBracket,
|
CloseBracket,
|
||||||
PoundSign,
|
PoundSign,
|
||||||
|
Less,
|
||||||
|
LessEquals,
|
||||||
|
Greater,
|
||||||
|
GreaterEquals,
|
||||||
|
|
||||||
// key words
|
// key words
|
||||||
TrueKeyword,
|
TrueKeyword,
|
||||||
|
|
|
@ -34,8 +34,12 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
// equality operators
|
// equality operators
|
||||||
case SyntaxKind.EqualsEquals:
|
case SyntaxKind.EqualsEquals:
|
||||||
return Precedence.Equality;
|
|
||||||
case SyntaxKind.TildeEquals:
|
case SyntaxKind.TildeEquals:
|
||||||
|
|
||||||
|
case SyntaxKind.Greater:
|
||||||
|
case SyntaxKind.GreaterEquals:
|
||||||
|
case SyntaxKind.Less:
|
||||||
|
case SyntaxKind.LessEquals:
|
||||||
return Precedence.Equality;
|
return Precedence.Equality;
|
||||||
|
|
||||||
// logical operators
|
// logical operators
|
||||||
|
|
Loading…
Reference in New Issue