implement precedence matrix and NegationOperation

This commit is contained in:
dfsek
2021-01-02 03:40:51 -07:00
parent 0fef1619d2
commit a5105f9f9d
5 changed files with 67 additions and 16 deletions

View File

@@ -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<String, Variable<?>> 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<Boolean>) expression, expression.getPosition());
} else if(negate) {
ParserUtil.checkReturnType(expression, Returnable.ReturnType.NUMBER);
expression = new NegationOperation((Returnable<Number>) expression, expression.getPosition());
}
if(full && tokens.get().isBinaryOperator()) { // Parse binary operations

View File

@@ -11,21 +11,31 @@ import java.util.Map;
public class ParserUtil {
private static final Map<Token.Type, List<Token.Type>> PRECEDENCE = new HashMap<>();
private static final Map<Token.Type, Map<Token.Type, Boolean>> PRECEDENCE = new HashMap<>(); // If second has precedence, true.
private static final List<Token.Type> 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<Token.Type> 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<Token.Type, Boolean> 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<Token.Type, Boolean> numericBoolean = new HashMap<>();
ARITHMETIC.forEach(op -> numericBoolean.put(op, true)); // Numbers before comparison
COMPARISON.forEach(op -> PRECEDENCE.put(op, numericBoolean));
Map<Token.Type, Boolean> 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<Token.Type, Boolean> pre = PRECEDENCE.get(first);
if(!pre.containsKey(second)) return false;
return pre.get(second);
}
}

View File

@@ -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<Number> {
public NegationOperation(Returnable<Number> input, Position position) {
super(input, position);
}
@Override
public Number apply(Number input) {
return -input.doubleValue();
}
@Override
public ReturnType returnType() {
return ReturnType.NUMBER;
}
}

View File

@@ -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();
}

View File

@@ -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);