diff --git a/common/src/main/java/com/dfsek/terra/api/structures/parser/Parser.java b/common/src/main/java/com/dfsek/terra/api/structures/parser/Parser.java index f88a02703..8b948bfee 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/parser/Parser.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/parser/Parser.java @@ -26,6 +26,7 @@ import com.dfsek.terra.api.structures.parser.lang.operations.ConcatenationOperat import com.dfsek.terra.api.structures.parser.lang.operations.DivisionOperation; import com.dfsek.terra.api.structures.parser.lang.operations.ModuloOperation; import com.dfsek.terra.api.structures.parser.lang.operations.MultiplicationOperation; +import com.dfsek.terra.api.structures.parser.lang.operations.NegationOperation; import com.dfsek.terra.api.structures.parser.lang.operations.NumberAdditionOperation; import com.dfsek.terra.api.structures.parser.lang.operations.SubtractionOperation; import com.dfsek.terra.api.structures.parser.lang.operations.statements.EqualsStatement; @@ -217,9 +218,13 @@ public class Parser { private Returnable parseExpression(TokenHolder tokens, boolean full, Map> variableMap) throws ParseException { boolean booleanInverted = false; // Check for boolean not operator + boolean negate = false; if(tokens.get().getType().equals(Token.Type.BOOLEAN_NOT)) { booleanInverted = true; tokens.consume(); + } else if(tokens.get().getType().equals(Token.Type.SUBTRACTION_OPERATOR)) { + negate = true; + tokens.consume(); } Token id = tokens.get(); @@ -243,6 +248,9 @@ public class Parser { if(booleanInverted) { // Invert operation if boolean not detected ParserUtil.checkReturnType(expression, Returnable.ReturnType.BOOLEAN); expression = new BooleanNotOperation((Returnable) expression, expression.getPosition()); + } else if(negate) { + ParserUtil.checkReturnType(expression, Returnable.ReturnType.NUMBER); + expression = new NegationOperation((Returnable) expression, expression.getPosition()); } if(full && tokens.get().isBinaryOperator()) { // Parse binary operations diff --git a/common/src/main/java/com/dfsek/terra/api/structures/parser/ParserUtil.java b/common/src/main/java/com/dfsek/terra/api/structures/parser/ParserUtil.java index 212d99d70..724ac9099 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/parser/ParserUtil.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/parser/ParserUtil.java @@ -11,21 +11,31 @@ import java.util.Map; public class ParserUtil { - private static final Map> PRECEDENCE = new HashMap<>(); + private static final Map> PRECEDENCE = new HashMap<>(); // If second has precedence, true. private static final List ARITHMETIC = Arrays.asList(Token.Type.ADDITION_OPERATOR, Token.Type.SUBTRACTION_OPERATOR, Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR, Token.Type.MODULO_OPERATOR); private static final List COMPARISON = Arrays.asList(Token.Type.EQUALS_OPERATOR, Token.Type.NOT_EQUALS_OPERATOR, Token.Type.LESS_THAN_OPERATOR, Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, Token.Type.GREATER_THAN_OPERATOR, Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR); static { // Setup precedence - PRECEDENCE.put(Token.Type.ADDITION_OPERATOR, Arrays.asList(Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR)); - PRECEDENCE.put(Token.Type.SUBTRACTION_OPERATOR, Arrays.asList(Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR)); - PRECEDENCE.put(Token.Type.EQUALS_OPERATOR, ARITHMETIC); - PRECEDENCE.put(Token.Type.NOT_EQUALS_OPERATOR, ARITHMETIC); - PRECEDENCE.put(Token.Type.GREATER_THAN_OPERATOR, ARITHMETIC); - PRECEDENCE.put(Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR, ARITHMETIC); - PRECEDENCE.put(Token.Type.LESS_THAN_OPERATOR, ARITHMETIC); - PRECEDENCE.put(Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, ARITHMETIC); - PRECEDENCE.put(Token.Type.BOOLEAN_AND, COMPARISON); - PRECEDENCE.put(Token.Type.BOOLEAN_OR, COMPARISON); + Map add = new HashMap<>(); // Addition/subtraction before Multiplication/division. + add.put(Token.Type.MULTIPLICATION_OPERATOR, true); + add.put(Token.Type.DIVISION_OPERATOR, true); + + PRECEDENCE.put(Token.Type.ADDITION_OPERATOR, add); + PRECEDENCE.put(Token.Type.SUBTRACTION_OPERATOR, add); + + Map numericBoolean = new HashMap<>(); + + ARITHMETIC.forEach(op -> numericBoolean.put(op, true)); // Numbers before comparison + COMPARISON.forEach(op -> PRECEDENCE.put(op, numericBoolean)); + + + Map booleanOps = new HashMap<>(); + ARITHMETIC.forEach(op -> booleanOps.put(op, true)); // Everything before boolean + COMPARISON.forEach(op -> booleanOps.put(op, true)); + + + PRECEDENCE.put(Token.Type.BOOLEAN_AND, booleanOps); + PRECEDENCE.put(Token.Type.BOOLEAN_OR, booleanOps); } public static void checkType(Token token, Token.Type... expected) throws ParseException { @@ -83,6 +93,8 @@ public class ParserUtil { public static boolean hasPrecedence(Token.Type first, Token.Type second) { if(!PRECEDENCE.containsKey(first)) return false; - return PRECEDENCE.get(first).contains(second); + Map pre = PRECEDENCE.get(first); + if(!pre.containsKey(second)) return false; + return pre.get(second); } } diff --git a/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/NegationOperation.java b/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/NegationOperation.java new file mode 100644 index 000000000..cf4b01de7 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/NegationOperation.java @@ -0,0 +1,20 @@ +package com.dfsek.terra.api.structures.parser.lang.operations; + +import com.dfsek.terra.api.structures.parser.lang.Returnable; +import com.dfsek.terra.api.structures.tokenizer.Position; + +public class NegationOperation extends UnaryOperation { + public NegationOperation(Returnable input, Position position) { + super(input, position); + } + + @Override + public Number apply(Number input) { + return -input.doubleValue(); + } + + @Override + public ReturnType returnType() { + return ReturnType.NUMBER; + } +} diff --git a/common/src/main/java/com/dfsek/terra/api/structures/tokenizer/Tokenizer.java b/common/src/main/java/com/dfsek/terra/api/structures/tokenizer/Tokenizer.java index 857bcf157..d856d4653 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/tokenizer/Tokenizer.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/tokenizer/Tokenizer.java @@ -148,13 +148,11 @@ public class Tokenizer { private boolean isNumberLike() { return reader.current().isDigit() - || reader.current().is('_', '.', '-', 'E'); + || reader.current().is('_', '.', 'E'); } private boolean isNumberStart() { return reader.current().isDigit() - || reader.current().is('-') && reader.next(1).isDigit() - || reader.current().is('-') && reader.next(1).is('.') && reader.next(2).isDigit() || reader.current().is('.') && reader.next(1).isDigit(); } diff --git a/common/src/test/resources/test.tesf b/common/src/test/resources/test.tesf index ee20157ff..93fe11eda 100644 --- a/common/src/test/resources/test.tesf +++ b/common/src/test/resources/test.tesf @@ -1,5 +1,11 @@ id "testScript"; +bool thing1 = 2 > (2+2) || false; + +if(2 > 2 || 3 + 4 <= 2 && 4 + 5 > 2 / 3) { + test("ok", 2); +} + test("minecraft:green_w" + "ool", (2 * (3+1) * (2 * (1+1)))); // @@ -7,7 +13,7 @@ num testVar = 3.4; bool boolean = true; str stringVar = "hello!"; -num precedence = (3 + 2) * 2 + 3; +num precedence = 3 + 2 * 2 + 3; test("precedence: " + precedence, 2); num precedence2 = 3 * 2 + 2 * 3; test("precedence 2: " + precedence2, 2); @@ -17,6 +23,13 @@ bool iftest = false; bool truetest = false; num iterator = 0; +num thing = 4 - 2-2+2-2+2; +test("4 - 2 = " + thing, 2); + +thing = -2; +test("-2 = " + thing, 2); +thing = -thing; +test("--2 = " + thing, 2);