implement operator precedence

This commit is contained in:
dfsek
2020-12-21 16:22:08 -07:00
parent 8a7499d874
commit 7a75f20a2c
6 changed files with 90 additions and 14 deletions

View File

@@ -14,7 +14,10 @@ import com.dfsek.terra.api.structures.parser.lang.keywords.IfKeyword;
import com.dfsek.terra.api.structures.parser.lang.operations.BinaryOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanNotOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.ConcatenationOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.DivisionOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.MultiplicationOperation;
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.tokenizer.Position;
import com.dfsek.terra.api.structures.tokenizer.Token;
import com.dfsek.terra.api.structures.tokenizer.Tokenizer;
@@ -78,7 +81,7 @@ public class Parser {
checkType(tokens.remove(0), Token.Type.BODY_BEGIN);
Returnable<?> comparator = parseExpression(tokens);
Returnable<?> comparator = parseExpression(tokens, true);
checkReturnType(comparator, Returnable.ReturnType.BOOLEAN);
checkType(tokens.remove(0), Token.Type.BODY_END);
@@ -92,10 +95,10 @@ public class Parser {
}
@SuppressWarnings("unchecked")
private Returnable<?> parseExpression(List<Token> tokens) throws ParseException {
private Returnable<?> parseExpression(List<Token> tokens, boolean full) throws ParseException {
System.out.println(tokens.get(0));
Token first = tokens.get(0);
checkType(first, Token.Type.IDENTIFIER, Token.Type.BOOLEAN, Token.Type.STRING, Token.Type.NUMBER, Token.Type.BOOLEAN_NOT);
checkType(first, Token.Type.IDENTIFIER, Token.Type.BOOLEAN, Token.Type.STRING, Token.Type.NUMBER, Token.Type.BOOLEAN_NOT, Token.Type.BODY_BEGIN);
boolean not = false;
if(first.getType().equals(Token.Type.BOOLEAN_NOT)) {
@@ -128,30 +131,52 @@ public class Parser {
checkReturnType(expression, Returnable.ReturnType.BOOLEAN);
expression = new BooleanNotOperation((Returnable<Boolean>) expression, expression.getPosition());
}
if(tokens.get(0).isBinaryOperator()) return parseBinaryOperation(expression, tokens);
if(full && tokens.get(0).isBinaryOperator()) {
return parseBinaryOperation(expression, tokens);
}
return expression;
}
@SuppressWarnings("unchecked")
private BinaryOperation<?> parseBinaryOperation(Returnable<?> left, List<Token> tokens) throws ParseException {
Token binaryOperator = tokens.remove(0);
Returnable<?> right = parseExpression(tokens);
checkType(binaryOperator, Token.Type.ADDITION_OPERATOR, Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR, Token.Type.SUBTRACTION_OPERATOR, Token.Type.BOOLEAN_OPERATOR);
Returnable<?> right = parseExpression(tokens, false);
if(binaryOperator.isStrictArithmeticOperator()) checkArithmeticOperation(left, right, binaryOperator.getType());
Token other = tokens.get(0);
System.out.println("other: " + other);
if(other.isBinaryOperator() && (other.getType().equals(Token.Type.MULTIPLICATION_OPERATOR) || other.getType().equals(Token.Type.DIVISION_OPERATOR))) {
System.out.println("using left");
return assemble(left, parseBinaryOperation(right, tokens), binaryOperator);
} else if(other.isBinaryOperator()) {
System.out.println("using right");
return parseBinaryOperation(assemble(left, right, binaryOperator), tokens);
}
return assemble(left, right, binaryOperator);
}
@SuppressWarnings("unchecked")
private BinaryOperation<?> assemble(Returnable<?> left, Returnable<?> right, Token binaryOperator) {
switch(binaryOperator.getType()) {
case ADDITION_OPERATOR:
System.out.println(left.returnType());
System.out.println(right.returnType());
if(left.returnType().equals(Returnable.ReturnType.NUMBER) && right.returnType().equals(Returnable.ReturnType.NUMBER)) {
System.out.println("number " + binaryOperator.getPosition());
return new NumberAdditionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
}
return new ConcatenationOperation((Returnable<Object>) left, (Returnable<Object>) right, binaryOperator.getPosition());
case SUBTRACTION_OPERATOR:
return new SubtractionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
case MULTIPLICATION_OPERATOR:
return new MultiplicationOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
case DIVISION_OPERATOR:
return new DivisionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
case BOOLEAN_OPERATOR:
default:
throw new UnsupportedOperationException("Unsupported binary operator: " + binaryOperator.getType());
}
}
private Block parseBlock(List<Token> tokens) throws ParseException {
@@ -162,7 +187,6 @@ public class Parser {
main:
while(tokens.size() > 0) {
Token token = tokens.get(0);
System.out.println(token);
checkType(token, Token.Type.IDENTIFIER, Token.Type.KEYWORD, Token.Type.BLOCK_END);
switch(token.getType()) {
case KEYWORD:
@@ -210,7 +234,7 @@ public class Parser {
List<Returnable<?>> args = new GlueList<>();
while(!tokens.get(0).getType().equals(Token.Type.BODY_END)) {
args.add(parseExpression(tokens));
args.add(parseExpression(tokens, true));
checkType(tokens.get(0), Token.Type.SEPARATOR, Token.Type.BODY_END);
if(tokens.get(0).getType().equals(Token.Type.SEPARATOR)) tokens.remove(0);
}
@@ -226,4 +250,10 @@ public class Parser {
for(Returnable.ReturnType type : types) if(returnable.returnType().equals(type)) return;
throw new ParseException("Expected " + Arrays.toString(types) + " but found " + returnable.returnType() + ": " + returnable.getPosition());
}
private void checkArithmeticOperation(Returnable<?> left, Returnable<?> right, Token.Type operation) throws ParseException {
if(!left.returnType().equals(Returnable.ReturnType.NUMBER) && !right.returnType().equals(Returnable.ReturnType.NUMBER)) {
throw new ParseException("Operation " + operation + " not supported between " + left.returnType() + " and " + right.returnType());
}
}
}

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 DivisionOperation extends BinaryOperation<Number> {
public DivisionOperation(Returnable<Number> left, Returnable<Number> right, Position position) {
super(left, right, position);
}
@Override
public Number apply(Number left, Number right) {
return left.doubleValue() / right.doubleValue();
}
@Override
public ReturnType returnType() {
return ReturnType.NUMBER;
}
}

View File

@@ -4,7 +4,7 @@ import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.tokenizer.Position;
public class MultiplicationOperation extends BinaryOperation<Number> {
protected MultiplicationOperation(Returnable<Number> left, Returnable<Number> right, Position position) {
public MultiplicationOperation(Returnable<Number> left, Returnable<Number> right, Position position) {
super(left, right, position);
}

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

View File

@@ -40,6 +40,12 @@ public class Token {
|| type.equals(Type.BOOLEAN_OPERATOR);
}
public boolean isStrictArithmeticOperator() {
return type.equals(Type.SUBTRACTION_OPERATOR)
|| type.equals(Type.MULTIPLICATION_OPERATOR)
|| type.equals(Type.DIVISION_OPERATOR);
}
public enum Type {
/**
* Function identifier or language keyword

View File

@@ -1,4 +1,4 @@
test("hello" + 3 + "gdfg", 2 + 1.2);
test("hello" + 3 + "gdfg", 3 + 8*2 - 1);
if(true) {
test("fdsgdf" + 2, 3.4);