From 4c0793dc399c12d7b1cb75abdecee5bdf9621dd8 Mon Sep 17 00:00:00 2001 From: Hazurl Date: Tue, 18 Jul 2023 22:27:48 +0200 Subject: [PATCH] [interval] Implements 'in' operator --- .../leekscript/compiler/LexicalParser.java | 2 ++ .../compiler/expression/LeekExpression.java | 9 ++++++++- .../compiler/expression/Operators.java | 11 +++++++++-- .../runner/values/IntervalLeekValue.java | 5 +++++ src/test/java/test/TestGeneral.java | 4 ++-- src/test/java/test/TestInterval.java | 18 +++++++++++++----- 6 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/main/java/leekscript/compiler/LexicalParser.java b/src/main/java/leekscript/compiler/LexicalParser.java index 7c6fd9b7..92fe0347 100644 --- a/src/main/java/leekscript/compiler/LexicalParser.java +++ b/src/main/java/leekscript/compiler/LexicalParser.java @@ -131,6 +131,8 @@ private boolean tryParseIdentifier() { addToken("instanceof", TokenType.OPERATOR); } else if (wordEquals(word, "as")) { addToken("as", TokenType.OPERATOR); + } else if (wordEquals(word, "in")) { + addToken("in", TokenType.OPERATOR); } else { addToken(word, TokenType.STRING); } diff --git a/src/main/java/leekscript/compiler/expression/LeekExpression.java b/src/main/java/leekscript/compiler/expression/LeekExpression.java index 4a153ddf..4831004b 100644 --- a/src/main/java/leekscript/compiler/expression/LeekExpression.java +++ b/src/main/java/leekscript/compiler/expression/LeekExpression.java @@ -877,6 +877,13 @@ public void writeJavaCode(MainLeekBlock mainblock, JavaWriter writer) { } mExpression1.writeJavaCode(mainblock, writer); return; + case Operators.IN: + // In LS, the expression is `expr in interval`, in Java, it's `interval.contains(expr)` + mExpression2.writeJavaCode(mainblock, writer); + writer.addCode(".contains("); + mExpression1.writeJavaCode(mainblock, writer); + writer.addCode(")"); + return; case Operators.NON_NULL_ASSERTION: writer.compileConvert(mainblock, 0, mExpression2, type); return; @@ -1081,7 +1088,7 @@ public void analyze(WordCompiler compiler) throws LeekCompilerException { type = mExpression1.getType().mul(mExpression2.getType()); } else if (mOperator == Operators.POWERASSIGN) { type = mExpression1.getType().pow(mExpression2.getType()); - } else if (mOperator == Operators.NOT || mOperator == Operators.EQUALS_EQUALS || mOperator == Operators.LESS || mOperator == Operators.MORE || mOperator == Operators.MOREEQUALS || mOperator == Operators.LESSEQUALS || mOperator == Operators.EQUALS || mOperator == Operators.AND || mOperator == Operators.OR || mOperator == Operators.NOTEQUALS || mOperator == Operators.NOT_EQUALS_EQUALS || mOperator == Operators.INSTANCEOF) { + } else if (mOperator == Operators.NOT || mOperator == Operators.EQUALS_EQUALS || mOperator == Operators.LESS || mOperator == Operators.MORE || mOperator == Operators.MOREEQUALS || mOperator == Operators.LESSEQUALS || mOperator == Operators.EQUALS || mOperator == Operators.AND || mOperator == Operators.OR || mOperator == Operators.NOTEQUALS || mOperator == Operators.NOT_EQUALS_EQUALS || mOperator == Operators.INSTANCEOF || mOperator == Operators.IN) { type = Type.BOOL; } else if (mOperator == Operators.BITAND || mOperator == Operators.BITNOT || mOperator == Operators.BITOR || mOperator == Operators.BITXOR || mOperator == Operators.SHIFT_LEFT || mOperator == Operators.SHIFT_RIGHT || mOperator == Operators.SHIFT_UNSIGNED_RIGHT || mOperator == Operators.INTEGER_DIVISION) { diff --git a/src/main/java/leekscript/compiler/expression/Operators.java b/src/main/java/leekscript/compiler/expression/Operators.java index 0f451c20..4211c943 100644 --- a/src/main/java/leekscript/compiler/expression/Operators.java +++ b/src/main/java/leekscript/compiler/expression/Operators.java @@ -54,7 +54,9 @@ public class Operators { public final static int INTEGER_DIVISION = 51; public final static int INTEGER_DIVISION_EQ = 52; public final static int AS = 53; - public final static int NON_NULL_ASSERTION = 54; + public final static int NON_NULL_ASSERTION = 54; + public final static int IN = 55; + public final static int getOperator(String operator, int version) { if(operator.equals("[")) return CROCHET; @@ -113,7 +115,9 @@ public final static int getOperator(String operator, int version) { if(operator.equals("instanceof")) return INSTANCEOF; if(operator.equals("\\")) return INTEGER_DIVISION; if(operator.equals("\\=")) return INTEGER_DIVISION_EQ; - if(operator.equals("as")) return AS; + if(operator.equals("as")) return AS; + if(operator.equals("in")) return IN; + return -1; } @@ -155,6 +159,7 @@ public static int getPriority(int operator) { case MORE: case MOREEQUALS: case INSTANCEOF: + case IN: return 8; case EQUALS: case NOTEQUALS: @@ -316,6 +321,8 @@ public static String getString(int operator) { return "instanceof"; case AS: return "as"; + case IN: + return "in"; } return "null"; } diff --git a/src/main/java/leekscript/runner/values/IntervalLeekValue.java b/src/main/java/leekscript/runner/values/IntervalLeekValue.java index bf9af38a..e3a5e937 100644 --- a/src/main/java/leekscript/runner/values/IntervalLeekValue.java +++ b/src/main/java/leekscript/runner/values/IntervalLeekValue.java @@ -62,4 +62,9 @@ public String toString(AI ai, Set visited) throws LeekRunException { return sb.append("]").toString(); } + + public boolean contains(Object value) throws LeekRunException { + ai.ops(1); + return ai.lessequals(from, value) && ai.lessequals(value, to); + } } diff --git a/src/test/java/test/TestGeneral.java b/src/test/java/test/TestGeneral.java index 7756c632..98715be9 100644 --- a/src/test/java/test/TestGeneral.java +++ b/src/test/java/test/TestGeneral.java @@ -79,7 +79,7 @@ public void run() { code_v1("var " + word + " = 2;").error(Error.NONE); code_v2("var " + word + " = 2;").error(Error.THIS_NOT_ALLOWED_HERE); code_v3_("var " + word + " = 2;").error(Error.VARIABLE_NAME_UNAVAILABLE); - } else if (word.equals("instanceof") || word.equals("as")) { + } else if (word.equals("instanceof") || word.equals("as") || word.equals("in")) { code_v1_2("var " + word + " = 2;").error(Error.VAR_NAME_EXPECTED); code_v3_("var " + word + " = 2;").error(Error.VAR_NAME_EXPECTED); } else if (word.equals("function")) { @@ -99,7 +99,7 @@ public void run() { for (var word : LexicalParser.reservedWords) { if (word.equals("this")) { code_v3_("global " + word + " = 2;").error(Error.VARIABLE_NAME_UNAVAILABLE); - } else if (word.equals("instanceof") || word.equals("as") || word.equals("void")) { + } else if (word.equals("instanceof") || word.equals("as") || word.equals("void") || word.equals("in")) { code_v3_("global " + word + " = 2;").error(Error.VAR_NAME_EXPECTED_AFTER_GLOBAL); } else if (word.equals("function")) { code_v3_("global " + word + " = 2;").error(Error.VARIABLE_NAME_UNAVAILABLE); diff --git a/src/test/java/test/TestInterval.java b/src/test/java/test/TestInterval.java index 48314af0..b763f4f4 100644 --- a/src/test/java/test/TestInterval.java +++ b/src/test/java/test/TestInterval.java @@ -1,14 +1,22 @@ package test; -import leekscript.common.Error; - public class TestInterval extends TestCommon { public void run() throws Exception { section("Interval.constructor()"); - code_v4_("return [1..2];").debug().equals("[1..2]"); - code_v4_("return [-10..-2];").debug().equals("[-10..-2]"); - code_v4_("return [1 * 5 .. 8 + 5];").debug().equals("[5..13]"); + code_v4_("return [1..2];").equals("[1..2]"); + code_v4_("return [-10..-2];").equals("[-10..-2]"); + code_v4_("return [1 * 5 .. 8 + 5];").equals("[5..13]"); + + section("Interval.in"); + code_v4_("return 1 in [1..2];").equals("true"); + code_v4_("return 1 in [0..2];").equals("true"); + code_v4_("return 2 in [1..2];").equals("true"); + code_v4_("return 3 in [1..2];").equals("false"); + code_v4_("return 0 in [1..2];").equals("false"); + code_v4_("return 1 in [1..1];").equals("true"); + code_v4_("return 1 in [2..1];").equals("false"); + code_strict_v4_("boolean x = 1 in [1..1]; return x").equals("true"); } }