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 e7bf9fe0a..e31a6a7b5 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 @@ -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 tokens) throws ParseException { + private Returnable parseExpression(List 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) 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 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) left, (Returnable) right, binaryOperator.getPosition()); } return new ConcatenationOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case SUBTRACTION_OPERATOR: + return new SubtractionOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case MULTIPLICATION_OPERATOR: + return new MultiplicationOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case DIVISION_OPERATOR: + return new DivisionOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); case BOOLEAN_OPERATOR: + default: throw new UnsupportedOperationException("Unsupported binary operator: " + binaryOperator.getType()); } - } private Block parseBlock(List 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> 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()); + } + } } diff --git a/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/DivisionOperation.java b/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/DivisionOperation.java new file mode 100644 index 000000000..d39ec612b --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/DivisionOperation.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 DivisionOperation extends BinaryOperation { + public DivisionOperation(Returnable left, Returnable 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; + } +} diff --git a/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/MultiplicationOperation.java b/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/MultiplicationOperation.java index 4e54c61c7..67fb5b691 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/MultiplicationOperation.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/MultiplicationOperation.java @@ -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 { - protected MultiplicationOperation(Returnable left, Returnable right, Position position) { + public MultiplicationOperation(Returnable left, Returnable right, Position position) { super(left, right, position); } diff --git a/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/SubtractionOperation.java b/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/SubtractionOperation.java new file mode 100644 index 000000000..2a6f323fa --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/structures/parser/lang/operations/SubtractionOperation.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 SubtractionOperation extends BinaryOperation { + public SubtractionOperation(Returnable left, Returnable 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; + } +} diff --git a/common/src/main/java/com/dfsek/terra/api/structures/tokenizer/Token.java b/common/src/main/java/com/dfsek/terra/api/structures/tokenizer/Token.java index 0c1f70c75..178f9fe6c 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/tokenizer/Token.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/tokenizer/Token.java @@ -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 diff --git a/common/src/test/resources/test.tesf b/common/src/test/resources/test.tesf index 304a42ac9..8f635d3fe 100644 --- a/common/src/test/resources/test.tesf +++ b/common/src/test/resources/test.tesf @@ -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);