From 2656442161209524adfd1dc09d02cb046deeecff Mon Sep 17 00:00:00 2001 From: r033 Date: Thu, 19 Dec 2024 01:23:06 +1000 Subject: [PATCH] Bitwise operators and floor division operator --- .../Execution/InstructionFieldUsage.cs | 7 + .../Execution/VM/OpCode.cs | 7 + .../VM/Processor/Processor_InstructionLoop.cs | 189 ++++++++++++++++++ src/MoonSharp.Interpreter/Tree/Expression_.cs | 2 +- .../Expressions/BinaryOperatorExpression.cs | 84 +++++++- .../FunctionDefinitionExpression.cs | 4 +- .../Expressions/UnaryOperatorExpression.cs | 15 ++ src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs | 43 +++- src/MoonSharp.Interpreter/Tree/Lexer/Token.cs | 17 +- .../Tree/Lexer/TokenType.cs | 8 +- 10 files changed, 366 insertions(+), 10 deletions(-) diff --git a/src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs b/src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs index e64f1335..f3e06b4d 100644 --- a/src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs +++ b/src/MoonSharp.Interpreter/Execution/InstructionFieldUsage.cs @@ -35,6 +35,7 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op) case OpCode.Sub: case OpCode.Mul: case OpCode.Div: + case OpCode.FloorDiv: case OpCode.Mod: case OpCode.Not: case OpCode.Len: @@ -42,6 +43,12 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op) case OpCode.Power: case OpCode.CNot: case OpCode.ToBool: + case OpCode.BitwiseAnd: + case OpCode.BitwiseOr: + case OpCode.BitwiseXor: + case OpCode.BitwiseLShift: + case OpCode.BitwiseRShift: + case OpCode.BitwiseNot: return InstructionFieldUsage.None; case OpCode.Pop: case OpCode.Copy: diff --git a/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs b/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs index 15ba552b..4bd88a72 100644 --- a/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs +++ b/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs @@ -50,12 +50,19 @@ internal enum OpCode Sub, // Subtraction of the two topmost operands on the v-stack Mul, // Multiplication of the two topmost operands on the v-stack Div, // Division of the two topmost operands on the v-stack + FloorDiv, // Floor Division of the two topmost operands on the v-stack Mod, // Modulus of the two topmost operands on the v-stack Not, // Logical inversion of the topmost operand on the v-stack Len, // Size operator of the topmost operand on the v-stack Neg, // Negation (unary minus) operator of the topmost operand on the v-stack Power, // Power of the two topmost operands on the v-stack CNot, // Conditional NOT - takes second operand from the v-stack (must be bool), if true execs a NOT otherwise execs a TOBOOL + BitwiseAnd, // Bitwise AND of the two topmost operands on the v-stack + BitwiseOr, // Bitwise OR of the two topmost operands on the v-stack + BitwiseXor, // Bitwise XOR of the two topmost operands on the v-stack + BitwiseLShift, // Bitwise Left Shift of the two topmost operands on the v-stack + BitwiseRShift, // Bitwise Right Shift of the two topmost operands on the v-stack + BitwiseNot, // Unary Bitwise NOT of the topmost operand on the v-stack // Type conversions and manipulations diff --git a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs index 38c0f63e..70123637 100644 --- a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs +++ b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs @@ -74,6 +74,10 @@ private DynValue Processing_Loop(int instructionPtr) instructionPtr = ExecNeg(i, instructionPtr); if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; break; + case OpCode.BitwiseNot: + instructionPtr = ExecBitwiseNot(i, instructionPtr); + if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; + break; case OpCode.Sub: instructionPtr = ExecSub(i, instructionPtr); if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; @@ -86,6 +90,10 @@ private DynValue Processing_Loop(int instructionPtr) instructionPtr = ExecDiv(i, instructionPtr); if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; break; + case OpCode.FloorDiv: + instructionPtr = ExecFloorDiv(i, instructionPtr); + if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; + break; case OpCode.Mod: instructionPtr = ExecMod(i, instructionPtr); if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; @@ -94,6 +102,26 @@ private DynValue Processing_Loop(int instructionPtr) instructionPtr = ExecPower(i, instructionPtr); if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; break; + case OpCode.BitwiseAnd: + instructionPtr = ExecBitwiseAnd(i, instructionPtr); + if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; + break; + case OpCode.BitwiseOr: + instructionPtr = ExecBitwiseOr(i, instructionPtr); + if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; + break; + case OpCode.BitwiseXor: + instructionPtr = ExecBitwiseXor(i, instructionPtr); + if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; + break; + case OpCode.BitwiseLShift: + instructionPtr = ExecBitwiseLShift(i, instructionPtr); + if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; + break; + case OpCode.BitwiseRShift: + instructionPtr = ExecBitwiseRShift(i, instructionPtr); + if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; + break; case OpCode.Eq: instructionPtr = ExecEq(i, instructionPtr); if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; @@ -993,6 +1021,28 @@ private int ExecDiv(Instruction i, int instructionPtr) else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r); } } + + private int ExecFloorDiv(Instruction i, int instructionPtr) + { + DynValue r = m_ValueStack.Pop().ToScalar(); + DynValue l = m_ValueStack.Pop().ToScalar(); + + double? rn = r.CastToNumber(); + double? ln = l.CastToNumber(); + + if (ln.HasValue && rn.HasValue) + { + m_ValueStack.Push(DynValue.NewNumber(Math.Floor(ln.Value / rn.Value))); + return instructionPtr; + } + else + { + int ip = Internal_InvokeBinaryMetaMethod(l, r, "__idiv", instructionPtr); + if (ip >= 0) return ip; + else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r); + } + } + private int ExecPower(Instruction i, int instructionPtr) { DynValue r = m_ValueStack.Pop().ToScalar(); @@ -1015,6 +1065,126 @@ private int ExecPower(Instruction i, int instructionPtr) } + private int ExecBitwiseAnd(Instruction i, int instructionPtr) + { + DynValue r = m_ValueStack.Pop().ToScalar(); + DynValue l = m_ValueStack.Pop().ToScalar(); + + double? rn = r.CastToNumber(); + double? ln = l.CastToNumber(); + + if (ln.HasValue && rn.HasValue) + { + uint uln = (uint)Math.IEEERemainder(ln.Value, Math.Pow(2.0, 32.0)); + uint urn = (uint)Math.IEEERemainder(rn.Value, Math.Pow(2.0, 32.0)); + + m_ValueStack.Push(DynValue.NewNumber(uln & urn)); + return instructionPtr; + } + else + { + int ip = Internal_InvokeBinaryMetaMethod(l, r, "__band", instructionPtr); + if (ip >= 0) return ip; + else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r); + } + } + + private int ExecBitwiseOr(Instruction i, int instructionPtr) + { + DynValue r = m_ValueStack.Pop().ToScalar(); + DynValue l = m_ValueStack.Pop().ToScalar(); + + double? rn = r.CastToNumber(); + double? ln = l.CastToNumber(); + + if (ln.HasValue && rn.HasValue) + { + uint uln = (uint)Math.IEEERemainder(ln.Value, Math.Pow(2.0, 32.0)); + uint urn = (uint)Math.IEEERemainder(rn.Value, Math.Pow(2.0, 32.0)); + + m_ValueStack.Push(DynValue.NewNumber(uln | urn)); + return instructionPtr; + } + else + { + int ip = Internal_InvokeBinaryMetaMethod(l, r, "__bor", instructionPtr); + if (ip >= 0) return ip; + else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r); + } + } + + private int ExecBitwiseXor(Instruction i, int instructionPtr) + { + DynValue r = m_ValueStack.Pop().ToScalar(); + DynValue l = m_ValueStack.Pop().ToScalar(); + + double? rn = r.CastToNumber(); + double? ln = l.CastToNumber(); + + if (ln.HasValue && rn.HasValue) + { + uint uln = (uint)Math.IEEERemainder(ln.Value, Math.Pow(2.0, 32.0)); + uint urn = (uint)Math.IEEERemainder(rn.Value, Math.Pow(2.0, 32.0)); + + m_ValueStack.Push(DynValue.NewNumber(uln ^ urn)); + return instructionPtr; + } + else + { + int ip = Internal_InvokeBinaryMetaMethod(l, r, "__bxor", instructionPtr); + if (ip >= 0) return ip; + else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r); + } + } + + private int ExecBitwiseLShift(Instruction i, int instructionPtr) + { + DynValue r = m_ValueStack.Pop().ToScalar(); + DynValue l = m_ValueStack.Pop().ToScalar(); + + double? rn = r.CastToNumber(); + double? ln = l.CastToNumber(); + + if (ln.HasValue && rn.HasValue) + { + int iln = (int)Math.IEEERemainder(ln.Value, Math.Pow(2.0, 32.0)); + int irn = (int)Math.IEEERemainder(rn.Value, Math.Pow(2.0, 32.0)); + + m_ValueStack.Push(DynValue.NewNumber(irn < 0 ? iln >> -irn : iln << irn)); + return instructionPtr; + } + else + { + int ip = Internal_InvokeBinaryMetaMethod(l, r, "__shl", instructionPtr); + if (ip >= 0) return ip; + else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r); + } + } + + private int ExecBitwiseRShift(Instruction i, int instructionPtr) + { + DynValue r = m_ValueStack.Pop().ToScalar(); + DynValue l = m_ValueStack.Pop().ToScalar(); + + double? rn = r.CastToNumber(); + double? ln = l.CastToNumber(); + + if (ln.HasValue && rn.HasValue) + { + int iln = (int)Math.IEEERemainder(ln.Value, Math.Pow(2.0, 32.0)); + int irn = (int)Math.IEEERemainder(rn.Value, Math.Pow(2.0, 32.0)); + + m_ValueStack.Push(DynValue.NewNumber(irn < 0 ? iln << -irn : iln >> irn)); + return instructionPtr; + } + else + { + int ip = Internal_InvokeBinaryMetaMethod(l, r, "__shr", instructionPtr); + if (ip >= 0) return ip; + else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r); + } + } + private int ExecNeg(Instruction i, int instructionPtr) { DynValue r = m_ValueStack.Pop().ToScalar(); @@ -1033,6 +1203,25 @@ private int ExecNeg(Instruction i, int instructionPtr) } } + private int ExecBitwiseNot(Instruction i, int instructionPtr) + { + DynValue r = m_ValueStack.Pop().ToScalar(); + double? rn = r.CastToNumber(); + + if (rn.HasValue) + { + uint urn = (uint)Math.IEEERemainder(rn.Value, Math.Pow(2.0, 32.0)); + m_ValueStack.Push(DynValue.NewNumber(~urn)); + return instructionPtr; + } + else + { + int ip = Internal_InvokeUnaryMetaMethod(r, "__bnot", instructionPtr); + if (ip >= 0) return ip; + else throw ScriptRuntimeException.ArithmeticOnNonNumber(r); + } + } + private int ExecEq(Instruction i, int instructionPtr) { diff --git a/src/MoonSharp.Interpreter/Tree/Expression_.cs b/src/MoonSharp.Interpreter/Tree/Expression_.cs index d0235bbb..a9788234 100644 --- a/src/MoonSharp.Interpreter/Tree/Expression_.cs +++ b/src/MoonSharp.Interpreter/Tree/Expression_.cs @@ -148,7 +148,7 @@ internal static Expression SimpleExp(ScriptLoadingContext lcontext) case TokenType.Function: lcontext.Lexer.Next(); return new FunctionDefinitionExpression(lcontext, false, false); - case TokenType.Lambda: + case TokenType.Op_BitwiseOr_Or_Lambda: return new FunctionDefinitionExpression(lcontext, false, true); default: return PrimaryExp(lcontext); diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs index 255039f5..3fd40af3 100755 --- a/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs @@ -30,6 +30,14 @@ private enum Operator Div = 0x2000, Mod = 0x4000, Power = 0x8000, + + BitwiseAnd = 0x10000, + BitwiseOr = 0x20000, + BitwiseXor = 0x40000, + BitwiseLShift = 0x100000, + BitwiseRShift = 0x200000, + + FloorDiv = 0x400000, } @@ -49,10 +57,14 @@ class LinkedList } const Operator POWER = Operator.Power; - const Operator MUL_DIV_MOD = Operator.Mul | Operator.Div | Operator.Mod; + const Operator MUL_DIV_MOD = Operator.Mul | Operator.Div | Operator.Mod | Operator.FloorDiv; const Operator ADD_SUB = Operator.Add | Operator.Sub; const Operator STRCAT = Operator.StrConcat; + const Operator BITWISE_SHIFT = Operator.BitwiseLShift | Operator.BitwiseRShift; const Operator COMPARES = Operator.Less | Operator.Greater | Operator.GreaterOrEqual | Operator.LessOrEqual | Operator.Equal | Operator.NotEqual; + const Operator BITWISE_AND = Operator.BitwiseAnd; + const Operator BITWISE_XOR = Operator.BitwiseXor; + const Operator BITWISE_OR = Operator.BitwiseOr; const Operator LOGIC_AND = Operator.And; const Operator LOGIC_OR = Operator.Or; @@ -125,9 +137,21 @@ private static Expression CreateSubTree(LinkedList list, ScriptLoadingContext lc if ((opfound & STRCAT) != 0) nodes = PrioritizeRightAssociative(nodes, lcontext, STRCAT); + + if ((opfound & BITWISE_SHIFT) != 0) + nodes = PrioritizeLeftAssociative(nodes, lcontext, BITWISE_SHIFT); if ((opfound & COMPARES) != 0) nodes = PrioritizeLeftAssociative(nodes, lcontext, COMPARES); + + if ((opfound & BITWISE_AND) != 0) + nodes = PrioritizeLeftAssociative(nodes, lcontext, BITWISE_AND); + + if ((opfound & BITWISE_XOR) != 0) + nodes = PrioritizeLeftAssociative(nodes, lcontext, BITWISE_XOR); + + if ((opfound & BITWISE_OR) != 0) + nodes = PrioritizeLeftAssociative(nodes, lcontext, BITWISE_OR); if ((opfound & LOGIC_AND) != 0) nodes = PrioritizeLeftAssociative(nodes, lcontext, LOGIC_AND); @@ -232,10 +256,22 @@ private static Operator ParseBinaryOperator(Token token) return Operator.Mul; case TokenType.Op_Div: return Operator.Div; + case TokenType.Op_FloorDiv: + return Operator.FloorDiv; case TokenType.Op_Mod: return Operator.Mod; case TokenType.Op_Pwr: return Operator.Power; + case TokenType.Op_BitwiseAnd: + return Operator.BitwiseAnd; + case TokenType.Op_BitwiseOr_Or_Lambda: + return Operator.BitwiseOr; + case TokenType.Op_BitwiseXor_Or_BitwiseNot: + return Operator.BitwiseXor; + case TokenType.Op_BitwiseLShift: + return Operator.BitwiseLShift; + case TokenType.Op_BitwiseRShift: + return Operator.BitwiseRShift; default: throw new InternalErrorException("Unexpected binary operator '{0}'", token.Text); } @@ -287,10 +323,22 @@ private static OpCode OperatorToOpCode(Operator op) return OpCode.Mul; case Operator.Div: return OpCode.Div; + case Operator.FloorDiv: + return OpCode.FloorDiv; case Operator.Mod: return OpCode.Mod; case Operator.Power: return OpCode.Power; + case Operator.BitwiseAnd: + return OpCode.BitwiseAnd; + case Operator.BitwiseOr: + return OpCode.BitwiseOr; + case Operator.BitwiseXor: + return OpCode.BitwiseXor; + case Operator.BitwiseLShift: + return OpCode.BitwiseLShift; + case Operator.BitwiseRShift: + return OpCode.BitwiseRShift; default: throw new InternalErrorException("Unsupported operator {0}", op); } @@ -392,12 +440,46 @@ private double EvalArithmetic(DynValue v1, DynValue v2) return d1 * d2; case Operator.Div: return d1 / d2; + case Operator.FloorDiv: + return Math.Floor(d1 / d2); case Operator.Mod: { double mod = Math.IEEERemainder(d1, d2); if (mod < 0) mod += d2; return mod; } + case Operator.Power: + return Math.Pow(d1, d2); + case Operator.BitwiseAnd: + { + uint ud1 = (uint)Math.IEEERemainder(d1, Math.Pow(2.0, 32.0)); + uint ud2 = (uint)Math.IEEERemainder(d2, Math.Pow(2.0, 32.0)); + return ud1 & ud2; + } + case Operator.BitwiseOr: + { + uint ud1 = (uint)Math.IEEERemainder(d1, Math.Pow(2.0, 32.0)); + uint ud2 = (uint)Math.IEEERemainder(d2, Math.Pow(2.0, 32.0)); + return ud1 | ud2; + } + case Operator.BitwiseXor: + { + uint ud1 = (uint)Math.IEEERemainder(d1, Math.Pow(2.0, 32.0)); + uint ud2 = (uint)Math.IEEERemainder(d2, Math.Pow(2.0, 32.0)); + return ud1 ^ ud2; + } + case Operator.BitwiseLShift: + { + int id1 = (int)Math.IEEERemainder(d1, Math.Pow(2.0, 32.0)); + int id2 = (int)Math.IEEERemainder(d2, Math.Pow(2.0, 32.0)); + return id2 < 0 ? id1 >> -id2 : id1 << id2; + } + case Operator.BitwiseRShift: + { + int id1 = (int)Math.IEEERemainder(d1, Math.Pow(2.0, 32.0)); + int id2 = (int)Math.IEEERemainder(d2, Math.Pow(2.0, 32.0)); + return id2 < 0 ? id1 << -id2 : id1 >> id2; + } default: throw new DynamicExpressionException("Unsupported operator {0}", m_Operator); } diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs index 3146cedb..085b84cc 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs @@ -39,7 +39,7 @@ private FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSel CheckTokenType(lcontext, TokenType.Function); // here lexer should be at the '(' or at the '|' - Token openRound = CheckTokenType(lcontext, isLambda ? TokenType.Lambda : TokenType.Brk_Open_Round); + Token openRound = CheckTokenType(lcontext, isLambda ? TokenType.Op_BitwiseOr_Or_Lambda : TokenType.Brk_Open_Round); List paramnames = BuildParamList(lcontext, pushSelfParam, openRound, isLambda); // here lexer is at first token of body @@ -102,7 +102,7 @@ private Statement CreateBody(ScriptLoadingContext lcontext) private List BuildParamList(ScriptLoadingContext lcontext, bool pushSelfParam, Token openBracketToken, bool isLambda) { - TokenType closeToken = isLambda ? TokenType.Lambda : TokenType.Brk_Close_Round; + TokenType closeToken = isLambda ? TokenType.Op_BitwiseOr_Or_Lambda : TokenType.Brk_Close_Round; List paramnames = new List(); diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/UnaryOperatorExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/UnaryOperatorExpression.cs index ec763585..672d7d3e 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/UnaryOperatorExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/UnaryOperatorExpression.cs @@ -32,6 +32,9 @@ public override void Compile(ByteCode bc) case "-": bc.Emit_Operator(OpCode.Neg); break; + case "~": + bc.Emit_Operator(OpCode.BitwiseNot); + break; default: throw new InternalErrorException("Unexpected unary operator '{0}'", m_OpText); } @@ -56,6 +59,18 @@ public override DynValue Eval(ScriptExecutionContext context) if (d.HasValue) return DynValue.NewNumber(-d.Value); + throw new DynamicExpressionException("Attempt to perform arithmetic on non-numbers."); + } + case "~": + { + double? d = v.CastToNumber(); + + if (d.HasValue) + { + uint ud = (uint)Math.IEEERemainder(d.Value, Math.Pow(2.0, 32.0)); + return DynValue.NewNumber(~ud); + } + throw new DynamicExpressionException("Attempt to perform arithmetic on non-numbers."); } default: diff --git a/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs b/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs index de47d322..fe54c004 100755 --- a/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs +++ b/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs @@ -154,17 +154,30 @@ private Token ReadToken() { case '|': CursorCharNext(); - return CreateToken(TokenType.Lambda, fromLine, fromCol, "|"); + return CreateToken(TokenType.Op_BitwiseOr_Or_Lambda, fromLine, fromCol, "|"); case ';': CursorCharNext(); return CreateToken(TokenType.SemiColon, fromLine, fromCol, ";"); case '=': return PotentiallyDoubleCharOperator('=', TokenType.Op_Assignment, TokenType.Op_Equal, fromLine, fromCol); + case '&': + CursorCharNext(); + return CreateToken(TokenType.Op_BitwiseAnd, fromLine, fromCol, "&"); case '<': - return PotentiallyDoubleCharOperator('=', TokenType.Op_LessThan, TokenType.Op_LessThanEqual, fromLine, fromCol); + return PotentiallyDoubleCharOperator('=', '<', TokenType.Op_LessThan, TokenType.Op_LessThanEqual, TokenType.Op_BitwiseLShift, fromLine, fromCol); case '>': - return PotentiallyDoubleCharOperator('=', TokenType.Op_GreaterThan, TokenType.Op_GreaterThanEqual, fromLine, fromCol); + return PotentiallyDoubleCharOperator('=', '>', TokenType.Op_GreaterThan, TokenType.Op_GreaterThanEqual, TokenType.Op_BitwiseRShift, fromLine, fromCol); case '~': + if (CursorCharNext() != '=') + { + CursorCharNext(); + return CreateToken(TokenType.Op_BitwiseXor_Or_BitwiseNot, fromLine, fromCol, "~"); + } + else + { + CursorCharNext(); + return CreateToken(TokenType.Op_NotEqual, fromLine, fromCol, "~="); + } case '!': if (CursorCharNext() != '=') throw new SyntaxErrorException(CreateToken(TokenType.Invalid, fromLine, fromCol), "unexpected symbol near '{0}'", c); @@ -198,7 +211,7 @@ private Token ReadToken() case '*': return CreateSingleCharToken(TokenType.Op_Mul, fromLine, fromCol); case '/': - return CreateSingleCharToken(TokenType.Op_Div, fromLine, fromCol); + return PotentiallyDoubleCharOperator('/', TokenType.Op_Div, TokenType.Op_FloorDiv, fromLine, fromCol); case '%': return CreateSingleCharToken(TokenType.Op_Mod, fromLine, fromCol); case '^': @@ -541,6 +554,28 @@ private Token PotentiallyDoubleCharOperator(char expectedSecondChar, TokenType s return CreateToken(singleCharToken, fromLine, fromCol, op); } + private Token PotentiallyDoubleCharOperator(char expectedSecondChar, char expectedSecondChar2, TokenType singleCharToken, TokenType doubleCharToken, TokenType doubleCharToken2, int fromLine, int fromCol) + { + string op = CursorChar().ToString(); + + CursorCharNext(); + + var ch = CursorChar(); + + if (ch == expectedSecondChar) + { + CursorCharNext(); + return CreateToken(doubleCharToken, fromLine, fromCol, op + expectedSecondChar); + } + else if (ch == expectedSecondChar2) + { + CursorCharNext(); + return CreateToken(doubleCharToken2, fromLine, fromCol, op + expectedSecondChar2); + } + else + return CreateToken(singleCharToken, fromLine, fromCol, op); + } + private Token CreateNameToken(string name, int fromLine, int fromCol) diff --git a/src/MoonSharp.Interpreter/Tree/Lexer/Token.cs b/src/MoonSharp.Interpreter/Tree/Lexer/Token.cs index 287fedc9..30516513 100644 --- a/src/MoonSharp.Interpreter/Tree/Lexer/Token.cs +++ b/src/MoonSharp.Interpreter/Tree/Lexer/Token.cs @@ -118,7 +118,16 @@ public bool IsEndOfBlock() public bool IsUnaryOperator() { - return Type == TokenType.Op_MinusOrSub || Type == TokenType.Not || Type == TokenType.Op_Len; + switch (Type) + { + case TokenType.Op_MinusOrSub: + case TokenType.Not: + case TokenType.Op_Len: + case TokenType.Op_BitwiseXor_Or_BitwiseNot: + return true; + default: + return false; + } } public bool IsBinaryOperator() @@ -137,9 +146,15 @@ public bool IsBinaryOperator() case TokenType.Op_Pwr: case TokenType.Op_Mod: case TokenType.Op_Div: + case TokenType.Op_FloorDiv: case TokenType.Op_Mul: case TokenType.Op_MinusOrSub: case TokenType.Op_Add: + case TokenType.Op_BitwiseAnd: + case TokenType.Op_BitwiseOr_Or_Lambda: + case TokenType.Op_BitwiseLShift: + case TokenType.Op_BitwiseRShift: + case TokenType.Op_BitwiseXor_Or_BitwiseNot: return true; default: return false; diff --git a/src/MoonSharp.Interpreter/Tree/Lexer/TokenType.cs b/src/MoonSharp.Interpreter/Tree/Lexer/TokenType.cs index e020ca4f..96b5ec27 100644 --- a/src/MoonSharp.Interpreter/Tree/Lexer/TokenType.cs +++ b/src/MoonSharp.Interpreter/Tree/Lexer/TokenType.cs @@ -15,7 +15,7 @@ enum TokenType False, For, Function, - Lambda, + Op_BitwiseOr_Or_Lambda, Goto, If, In, @@ -52,6 +52,7 @@ enum TokenType Op_Pwr, Op_Mod, Op_Div, + Op_FloorDiv, Op_Mul, Op_MinusOrSub, Op_Add, @@ -68,6 +69,11 @@ enum TokenType Brk_Open_Curly_Shared, Op_Dollar, + + Op_BitwiseAnd, + Op_BitwiseXor_Or_BitwiseNot, + Op_BitwiseLShift, + Op_BitwiseRShift }