diff --git a/Upsilon/BaseTypes/Number/ScriptNumber.cs b/Upsilon/BaseTypes/Number/ScriptNumber.cs index edaa347..7d8924a 100644 --- a/Upsilon/BaseTypes/Number/ScriptNumber.cs +++ b/Upsilon/BaseTypes/Number/ScriptNumber.cs @@ -1,3 +1,5 @@ +using System; + namespace Upsilon.BaseTypes.Number { internal abstract class ScriptNumber : ScriptType @@ -41,6 +43,17 @@ namespace Upsilon.BaseTypes.Number return new ScriptNumberDouble(((ScriptNumberLong) a).Value * ((ScriptNumberDouble) b).Value); } + public static ScriptNumber operator % (ScriptNumber a, ScriptNumber b) + { + if (!a.IsFloat && !b.IsFloat) + return new ScriptNumberLong(((ScriptNumberLong) a).Value % ((ScriptNumberLong) b).Value); + if (a.IsFloat && b.IsFloat) + return new ScriptNumberDouble(((ScriptNumberDouble) a).Value % ((ScriptNumberDouble) b).Value); + if (a.IsFloat) + return new ScriptNumberDouble(((ScriptNumberDouble) a).Value % ((ScriptNumberLong) b).Value); + return new ScriptNumberDouble(((ScriptNumberLong) a).Value % ((ScriptNumberDouble) b).Value); + } + public static ScriptNumber operator / (ScriptNumber a, ScriptNumber b) { if (!a.IsFloat && !b.IsFloat) @@ -60,6 +73,18 @@ namespace Upsilon.BaseTypes.Number return new ScriptNumberLong(-((ScriptNumberLong)n).Value); } + public static ScriptNumber Exponent(ScriptNumber a, ScriptNumber b) + { + if (!a.IsFloat && !b.IsFloat) + return new ScriptNumberLong((long) Math.Pow(((ScriptNumberLong) a).Value, ((ScriptNumberLong) b).Value)); + if (a.IsFloat && b.IsFloat) + return new ScriptNumberDouble(Math.Pow(((ScriptNumberDouble) a).Value, ((ScriptNumberDouble) b).Value)); + if (a.IsFloat) + return new ScriptNumberDouble(Math.Pow(((ScriptNumberDouble) a).Value, ((ScriptNumberLong) b).Value)); + return new ScriptNumberDouble(Math.Pow(((ScriptNumberLong) a).Value, ((ScriptNumberDouble) b).Value)); + } + + #region Equality private bool Equals(ScriptNumber other) @@ -117,6 +142,7 @@ namespace Upsilon.BaseTypes.Number + public static explicit operator double(ScriptNumber n) { if (n.IsFloat) diff --git a/Upsilon/Binder/BoundBinaryOperator.cs b/Upsilon/Binder/BoundBinaryOperator.cs index 5fb1574..555fbc2 100644 --- a/Upsilon/Binder/BoundBinaryOperator.cs +++ b/Upsilon/Binder/BoundBinaryOperator.cs @@ -15,7 +15,9 @@ namespace Upsilon.Binder LessEquals, Less, And, - Or + Or, + Exponent, + Remainder } private Type LeftType { get; } @@ -46,6 +48,8 @@ namespace Upsilon.Binder new BoundBinaryOperator(OperatorKind.Subtraction, Type.Number), new BoundBinaryOperator(OperatorKind.Multiplication, Type.Number), new BoundBinaryOperator(OperatorKind.Division, Type.Number), + new BoundBinaryOperator(OperatorKind.Exponent, Type.Number), + new BoundBinaryOperator(OperatorKind.Remainder, Type.Number), // Number equality new BoundBinaryOperator(OperatorKind.Equality, Type.Number, Type.Number, Type.Boolean), @@ -102,6 +106,12 @@ namespace Upsilon.Binder case SyntaxKind.Slash: kind = OperatorKind.Division; break; + case SyntaxKind.PercentSign: + kind = OperatorKind.Remainder; + break; + case SyntaxKind.RoofSign: + kind = OperatorKind.Exponent; + break; case SyntaxKind.EqualsEquals: kind = OperatorKind.Equality; break; diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index d748d4c..d919cf3 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -288,7 +288,7 @@ namespace Upsilon.Evaluator } goto default; case BoundBinaryOperator.OperatorKind.Subtraction: - if (left.Type == Type.Number) + if (left.Type == Type.Number && right.Type == Type.Number) { return ((ScriptNumber)left) - ((ScriptNumber)right); } @@ -301,7 +301,7 @@ namespace Upsilon.Evaluator } goto default; case BoundBinaryOperator.OperatorKind.Multiplication: - if (left.Type == Type.Number) + if (left.Type == Type.Number && right.Type == Type.Number) { return ((ScriptNumber)left) * ((ScriptNumber)right); } @@ -314,7 +314,7 @@ namespace Upsilon.Evaluator } goto default; case BoundBinaryOperator.OperatorKind.Division: - if (left.Type == Type.Number) + if (left.Type == Type.Number && right.Type == Type.Number) { return ((ScriptNumber)left) / ((ScriptNumber)right); } @@ -326,6 +326,18 @@ namespace Upsilon.Evaluator return type; } goto default; + case BoundBinaryOperator.OperatorKind.Exponent: + if (left.Type == Type.Number && right.Type == Type.Number) + { + return ScriptNumber.Exponent((ScriptNumber) left, (ScriptNumber) right); + } + goto default; + case BoundBinaryOperator.OperatorKind.Remainder: + if (left.Type == Type.Number && right.Type == Type.Number) + { + return ((ScriptNumber)left) % ((ScriptNumber)right); + } + goto default; case BoundBinaryOperator.OperatorKind.Equality: return new ScriptBoolean(Equals(left, right)); case BoundBinaryOperator.OperatorKind.Inequality: diff --git a/Upsilon/Parser/Lexer.cs b/Upsilon/Parser/Lexer.cs index 9eebd3b..22b65fe 100644 --- a/Upsilon/Parser/Lexer.cs +++ b/Upsilon/Parser/Lexer.cs @@ -102,6 +102,10 @@ namespace Upsilon.Parser return new SyntaxToken(SyntaxKind.Comma, _position, ",", null); case '#': return new SyntaxToken(SyntaxKind.PoundSign, _position, "#", null); + case '%': + return new SyntaxToken(SyntaxKind.PercentSign, _position, "%", null); + case '^': + return new SyntaxToken(SyntaxKind.RoofSign, _position, "^", null); case '"': return LexString(); case '=': diff --git a/Upsilon/Parser/SyntaxKind.cs b/Upsilon/Parser/SyntaxKind.cs index 14b8941..9a9cf8f 100644 --- a/Upsilon/Parser/SyntaxKind.cs +++ b/Upsilon/Parser/SyntaxKind.cs @@ -87,5 +87,7 @@ namespace Upsilon.Parser NumericForStatement, BreakStatement, GenericForStatement, + PercentSign, + RoofSign } } \ No newline at end of file diff --git a/Upsilon/Parser/SyntaxKindPrecedence.cs b/Upsilon/Parser/SyntaxKindPrecedence.cs index e39f692..8b4a27b 100644 --- a/Upsilon/Parser/SyntaxKindPrecedence.cs +++ b/Upsilon/Parser/SyntaxKindPrecedence.cs @@ -5,13 +5,12 @@ namespace Upsilon.Parser public enum Precedence { None = 0, - Or, - And, + LogicalOr, + LogicalAnd, Equality, - PlusMinus, - StarSlash, + Additive, + Multiplicative, Unary, - Exponentiation } public static Precedence UnaryOperatorPrecedence(this SyntaxKind kind) @@ -44,18 +43,23 @@ namespace Upsilon.Parser // logical operators case SyntaxKind.AndKeyword: - return Precedence.And; + return Precedence.LogicalAnd; case SyntaxKind.OrKeyword: - return Precedence.Or; + return Precedence.LogicalOr; // math operators case SyntaxKind.Plus: case SyntaxKind.Minus: - return Precedence.PlusMinus; + return Precedence.Additive; case SyntaxKind.Star: case SyntaxKind.Slash: - return Precedence.StarSlash; + case SyntaxKind.PercentSign: + case SyntaxKind.RoofSign: + return Precedence.Multiplicative; + + + default: return Precedence.None; }