From 6f0dd2c38c063e3e435bf88bfd4e30ad5513f159 Mon Sep 17 00:00:00 2001 From: lofcz Date: Mon, 4 Apr 2022 23:49:16 +0200 Subject: [PATCH] Implement ?!, ?!= --- .../Execution/VM/OpCode.cs | 1 + .../VM/Processor/Processor_InstructionLoop.cs | 16 +++++++++++++ .../Expressions/BinaryOperatorExpression.cs | 24 +++++++++++++++++-- src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs | 14 +++++++++-- src/MoonSharp.Interpreter/Tree/Lexer/Token.cs | 1 + .../Tree/Lexer/TokenType.cs | 2 ++ .../Tree/Statements/AssignmentStatement.cs | 10 ++++++++ .../Operators/11-nill-coalescing-inverse.lua | 2 ++ .../Operators/11-nill-coalescing-inverse.txt | 1 + .../12-nill-coalescing-assignment-inverse.lua | 2 ++ .../12-nill-coalescing-assignment-inverse.txt | 1 + ...-nill-coalescing-assignment-inverse-ok.lua | 3 +++ ...-nill-coalescing-assignment-inverse-ok.txt | 1 + 13 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/11-nill-coalescing-inverse.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/11-nill-coalescing-inverse.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/12-nill-coalescing-assignment-inverse.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/12-nill-coalescing-assignment-inverse.txt create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/13-nill-coalescing-assignment-inverse-ok.lua create mode 100644 src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/13-nill-coalescing-assignment-inverse-ok.txt diff --git a/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs b/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs index 89aca8c8..1a41236d 100644 --- a/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs +++ b/src/MoonSharp.Interpreter/Execution/VM/OpCode.cs @@ -89,6 +89,7 @@ internal enum OpCode IterUpd, // Updates the var part of an iterator NilCoalescing, + NilCoalescingInverse, // Meta Invalid, // Crashes the executor with an unrecoverable NotImplementedException. This MUST always be the last opcode in enum diff --git a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs index 1a0bca9c..4b647bce 100644 --- a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs +++ b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs @@ -293,6 +293,10 @@ private DynValue Processing_Loop(int instructionPtr, bool canAwait = false) instructionPtr = ExecNilCoalescingAssignment(i, instructionPtr); if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; break; + case OpCode.NilCoalescingInverse: + instructionPtr = ExecNilCoalescingAssignmentInverse(i, instructionPtr); + if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine; + break; case OpCode.Invalid: throw new NotImplementedException(string.Format("Invalid opcode : {0}", i.String)); default: @@ -864,6 +868,18 @@ private int ExecNilCoalescingAssignment(Instruction i, int instructionPtr) m_ValueStack.Pop(); return instructionPtr; } + + private int ExecNilCoalescingAssignmentInverse(Instruction i, int instructionPtr) + { + ref DynValue lhs = ref m_ValueStack.Peek(1); + if (lhs.IsNotNil()) + { + m_ValueStack.Set(1, m_ValueStack.Peek()); + } + + m_ValueStack.Pop(); + return instructionPtr; + } private int ExecRet(Instruction i, int currentPtr) { diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs index 41d03e1b..2b2e85f1 100755 --- a/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs @@ -33,7 +33,8 @@ public enum Operator BitXor = 0x100000, BitLShift = 0x200000, BitRShiftA = 0x400000, - BitRShiftL = 0x4800000 + BitRShiftL = 0x4800000, + NilCoalescingInverse = 0x9000000, } /// @@ -65,6 +66,7 @@ class LinkedList const Operator LOGIC_OR = Operator.Or; const Operator NIL_COAL_ASSIGN = Operator.NilCoalescing; const Operator SHIFTS = Operator.BitLShift | Operator.BitRShiftA | Operator.BitRShiftL; + const Operator NIL_COAL_INVERSE = Operator.NilCoalescingInverse; public static object BeginOperatorChain() { @@ -158,6 +160,9 @@ private static Expression CreateSubTree(LinkedList list, ScriptLoadingContext lc if ((opfound & NIL_COAL_ASSIGN) != 0) nodes = PrioritizeLeftAssociative(nodes, lcontext, NIL_COAL_ASSIGN); + + if ((opfound & NIL_COAL_INVERSE) != 0) + nodes = PrioritizeLeftAssociative(nodes, lcontext, NIL_COAL_INVERSE); if (nodes.Next != null || nodes.Prev != null) throw new InternalErrorException("Expression reduction didn't work! - 1"); @@ -261,6 +266,8 @@ private static Operator ParseBinaryOperator(Token token) return Operator.Power; case TokenType.Op_NilCoalesce: return Operator.NilCoalescing; + case TokenType.Op_NilCoalesceInverse: + return Operator.NilCoalescingInverse; case TokenType.Op_Or: return Operator.BitOr; case TokenType.Op_And: @@ -346,6 +353,8 @@ public static OpCode OperatorToOpCode(Operator op) return OpCode.BRShiftA; case Operator.BitRShiftL: return OpCode.BRShiftL; + case Operator.NilCoalescingInverse: + return OpCode.NilCoalescingInverse; default: throw new InternalErrorException("Unsupported operator {0}", op); } @@ -401,6 +410,12 @@ public override bool EvalLiteral(out DynValue dv) else dv = v1; return true; } + if (m_Operator == Operator.NilCoalescingInverse) + { + if (v1.IsNotNil()) dv = v2; + else dv = v1; + return true; + } if (m_Operator == Operator.Or) { if (v1.CastToBool()) @@ -453,7 +468,12 @@ public override DynValue Eval(ScriptExecutionContext context) if (m_Operator == Operator.NilCoalescing) { if (v1.IsNil()) return m_Exp2.Eval(context); - else return v1; + return v1; + } + if (m_Operator == Operator.NilCoalescingInverse) + { + if (v1.IsNotNil()) return m_Exp2.Eval(context); + return v1; } if (m_Operator == Operator.Or) { diff --git a/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs b/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs index 334572d2..0d894e57 100755 --- a/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs +++ b/src/MoonSharp.Interpreter/Tree/Lexer/Lexer.cs @@ -480,10 +480,20 @@ private Token ReadToken() CursorCharNext(); return CreateToken(TokenType.Op_NilCoalescingAssignment, fromLine, fromCol, "??="); } - else + + return CreateToken(TokenType.Op_NilCoalesce, fromLine, fromCol, "??"); + } + + if (next == '!') + { + char next2 = CursorCharNext(); + if (next2 == '=') { - return CreateToken(TokenType.Op_NilCoalesce, fromLine, fromCol, "??"); + CursorCharNext(); + return CreateToken(TokenType.Op_NilCoalescingAssignmentInverse, fromLine, fromCol, "?!="); } + + return CreateToken(TokenType.Op_NilCoalesceInverse, fromLine, fromCol, "?!"); } return CreateToken(TokenType.Ternary, fromLine, fromCol, "?"); diff --git a/src/MoonSharp.Interpreter/Tree/Lexer/Token.cs b/src/MoonSharp.Interpreter/Tree/Lexer/Token.cs index cbe3af64..275135a9 100644 --- a/src/MoonSharp.Interpreter/Tree/Lexer/Token.cs +++ b/src/MoonSharp.Interpreter/Tree/Lexer/Token.cs @@ -135,6 +135,7 @@ public bool IsBinaryOperator() case TokenType.Op_MinusOrSub: case TokenType.Op_Add: case TokenType.Op_NilCoalesce: + case TokenType.Op_NilCoalesceInverse: case TokenType.Op_Or: case TokenType.Op_And: case TokenType.Op_Xor: diff --git a/src/MoonSharp.Interpreter/Tree/Lexer/TokenType.cs b/src/MoonSharp.Interpreter/Tree/Lexer/TokenType.cs index 54c97ac0..05fe1698 100644 --- a/src/MoonSharp.Interpreter/Tree/Lexer/TokenType.cs +++ b/src/MoonSharp.Interpreter/Tree/Lexer/TokenType.cs @@ -82,7 +82,9 @@ enum TokenType Op_OrEq, //Nil operators Op_NilCoalesce, + Op_NilCoalesceInverse, Op_NilCoalescingAssignment, + Op_NilCoalescingAssignmentInverse, Ternary, Comment, diff --git a/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs b/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs index 31c28dd2..43d1f067 100644 --- a/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs +++ b/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs @@ -47,6 +47,12 @@ public AssignmentStatement(ScriptLoadingContext lcontext, Token startToken) AssignmentOp = Operator.NilCoalescing; m_RValues = Expression.ExprList(lcontext); } + else if (lcontext.Syntax == ScriptSyntax.CLike && lcontext.Lexer.Current.Type == TokenType.Op_NilCoalesceInverse) + { + CheckTokenType(lcontext, TokenType.Op_NilCoalesceInverse); + AssignmentOp = Operator.NilCoalescingInverse; + m_RValues = Expression.ExprList(lcontext); + } else { if (names.Count > 0) @@ -127,6 +133,10 @@ public AssignmentStatement(ScriptLoadingContext lcontext, Expression firstExpres AssignmentOp = Operator.NilCoalescing; lcontext.Lexer.Next(); break; + case TokenType.Op_NilCoalescingAssignmentInverse: + AssignmentOp = Operator.NilCoalescingInverse; + lcontext.Lexer.Next(); + break; default: CheckTokenType(lcontext, TokenType.Op_Assignment); break; diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/11-nill-coalescing-inverse.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/11-nill-coalescing-inverse.lua new file mode 100644 index 00000000..f1c78b2e --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/11-nill-coalescing-inverse.lua @@ -0,0 +1,2 @@ +x = 10 ?! 100 +print(x) \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/11-nill-coalescing-inverse.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/11-nill-coalescing-inverse.txt new file mode 100644 index 00000000..105d7d9a --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/11-nill-coalescing-inverse.txt @@ -0,0 +1 @@ +100 \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/12-nill-coalescing-assignment-inverse.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/12-nill-coalescing-assignment-inverse.lua new file mode 100644 index 00000000..6ab84780 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/12-nill-coalescing-assignment-inverse.lua @@ -0,0 +1,2 @@ +x ?!= 500 +print(x) \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/12-nill-coalescing-assignment-inverse.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/12-nill-coalescing-assignment-inverse.txt new file mode 100644 index 00000000..90b5a842 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/12-nill-coalescing-assignment-inverse.txt @@ -0,0 +1 @@ +nil \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/13-nill-coalescing-assignment-inverse-ok.lua b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/13-nill-coalescing-assignment-inverse-ok.lua new file mode 100644 index 00000000..c9f28c07 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/13-nill-coalescing-assignment-inverse-ok.lua @@ -0,0 +1,3 @@ +x = 10 +x ?!= 500 +print(x) \ No newline at end of file diff --git a/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/13-nill-coalescing-assignment-inverse-ok.txt b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/13-nill-coalescing-assignment-inverse-ok.txt new file mode 100644 index 00000000..eb1f4948 --- /dev/null +++ b/src/MoonSharp.Tests/EndToEnd/CLike/SyntaxCLike/Operators/13-nill-coalescing-assignment-inverse-ok.txt @@ -0,0 +1 @@ +500 \ No newline at end of file