Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/main/interpreter/ExpressionParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,4 @@ public <T> MSBool getNegatedBoolean(T ctx) {
throw new RuntimeException("Condition must be a bool");
}
}

}
83 changes: 56 additions & 27 deletions src/main/interpreter/Visitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
Expand All @@ -26,6 +27,8 @@ public class Visitor extends MineScriptBaseVisitor<MSType> {
private final SymbolTable symbolTable;
private boolean hasReturned = false;

private final BigInteger INT_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
private final BigInteger INT_MIN = BigInteger.valueOf(Integer.MIN_VALUE);
private Block placingBlock;
private boolean shouldBreak;
private int turtleDelay;
Expand Down Expand Up @@ -212,7 +215,7 @@ public MSType visitIsIsNot(MineScriptParser.IsIsNotContext ctx) {
return new MSBool(switch (ctx.op.getText()) {
case "is" -> left.equals(right);
case "is not" -> !left.equals(right);
default -> throw new RuntimeException("Unknown operator ' '" + ctx.op.getText() + "'");
default -> throw new RuntimeException("Unknown operator: " + ctx.op.getText());
});
}

Expand Down Expand Up @@ -254,15 +257,11 @@ public MSType visitAddSub(MineScriptParser.AddSubContext ctx) {
MSType left = visit(ctx.expression(0));
MSType right = visit(ctx.expression(1));

/*Check that both sides are numbers otherwise throw an error*/
if (left instanceof MSNumber l && right instanceof MSNumber r) {
return new MSNumber(switch (ctx.op.getText()) {
case "+" -> l.getValue() + r.getValue();
case "-" -> l.getValue() - r.getValue();
default -> throw new RuntimeException("Unknown operator: " + ctx.op.getText());
});
if (!(left instanceof MSNumber l) || !(right instanceof MSNumber r)) {
throw new RuntimeException("Cannot use '" + ctx.op.getText() + "' operator on " + left.getTypeName() + " and " + right.getTypeName());
}
throw new RuntimeException("Cannot use '" + ctx.op.getText() + "' operator on " + left.getTypeName() + " and " + right.getTypeName());

return calculateArithmeticExpression(l, r, ctx.op.getText());
}

@Override
Expand All @@ -280,7 +279,11 @@ public MSType visitParenExpr(MineScriptParser.ParenExprContext ctx) {

@Override
public MSType visitNumber(MineScriptParser.NumberContext ctx) {
return new MSNumber(Integer.parseInt(ctx.NUMBER().getText()));
try {
return new MSNumber(Integer.parseInt(ctx.NUMBER().getText()));
} catch (NumberFormatException e) {
throw new RuntimeException("Number (" + ctx.NUMBER().getText() + ") is not within the range. Number range from " + INT_MIN + " to " + INT_MAX);
}
}

@Override
Expand All @@ -289,31 +292,27 @@ public MSType visitMultDivMod(MineScriptParser.MultDivModContext ctx) {
MSType right = visit(ctx.expression(1));

/*Check that both sides are numbers otherwise throw an error*/
if (left instanceof MSNumber l && right instanceof MSNumber r) {
return new MSNumber(switch (ctx.op.getText()) {
case "*" -> l.getValue() * r.getValue();
case "/" -> l.getValue() / r.getValue();
case "%" -> l.getValue() % r.getValue();
default -> throw new RuntimeException("Unknown operator: " + ctx.op.getText());
});
if (!(left instanceof MSNumber l) || !(right instanceof MSNumber r)) {
throw new RuntimeException("Cannot use '" + ctx.op.getText() + "' operator on " + left.getTypeName() + " and " + right.getTypeName());
}
throw new RuntimeException("Cannot use '" + ctx.op.getText() + "' operator on " + left.getTypeName() + " and " + right.getTypeName());

return calculateArithmeticExpression(l, r, ctx.op.getText());
}

@Override
public MSType visitPow(MineScriptParser.PowContext ctx) {
MSType left = visit(ctx.expression(0));
MSType right = visit(ctx.expression(1));

if (left instanceof MSNumber l && right instanceof MSNumber r) {
/*Check if the exponent is negative*/
if (r.getValue() < 0) {
throw new RuntimeException("Cannot raise to negative power");
}
return new MSNumber((int) Math.pow(l.getValue(), r.getValue()));
if (!(left instanceof MSNumber l) || !(right instanceof MSNumber r)) {
throw new RuntimeException("Cannot use '^' operator on " + left.getTypeName() + " and " + right.getTypeName());
}
if (r.getValue() < 0) {
throw new RuntimeException("Cannot raise to negative power");
}

throw new RuntimeException("Cannot use '^' operator on " + left.getTypeName() + " and " + right.getTypeName());
return calculateArithmeticExpression(l, r, "^");

}

@Override
Expand Down Expand Up @@ -675,6 +674,37 @@ private ArrayList<MSType> getActualParams(MineScriptParser.Actual_parametersCont
return actualParams;
}

/**
* @param left the left side of the expression
* @param right the right side of the expression
* @param operator the operator to use
* @return the result of the expression
* @throws RuntimeException if the result is too big or too small to be an int
*/
private MSNumber calculateArithmeticExpression(MSNumber left, MSNumber right, String operator) {
// Convert to BigIntegers to avoid overflow
BigInteger leftBig = BigInteger.valueOf(left.getValue());
BigInteger rightBig = BigInteger.valueOf(right.getValue());
BigInteger result = switch (operator) {
case "+" -> leftBig.add(rightBig);
case "-" -> leftBig.subtract(rightBig);
case "*" -> leftBig.multiply(rightBig);
case "/" -> leftBig.divide(rightBig);
case "%" -> leftBig.mod(rightBig);
case "^" -> leftBig.pow(rightBig.intValue());
default -> throw new RuntimeException("Unknown operator: " + operator);
};

// Check if the result is in the range of an int
if (result.compareTo(INT_MAX) > 0) {
throw new RuntimeException("Result of '" + leftBig + " " + operator + " " + rightBig + "' is too big. Maximum number is " + Integer.MAX_VALUE);
} else if (result.compareTo(INT_MIN) < 0) {
throw new RuntimeException("Result of '" + leftBig + " " + operator + " " + rightBig + "' is too small. Minimum number is " + Integer.MIN_VALUE);
}
return new MSNumber(result.intValue());

}

/**
* @param id Function name
* @param argumentsCount Possible number of arguments. Each index represents a possible number of arguments
Expand All @@ -700,8 +730,7 @@ private String getFuncCallErrorMessage(String id, int[] argumentsCount, String p
if (argumentsCount[argumentsCount.length - 1] != 1) {
message.append("s");
}
if (!paramTypes.equals(""))
message.append(" (").append(paramTypes).append(")");
if (!paramTypes.equals("")) message.append(" (").append(paramTypes).append(")");
}
message.append(" but ").append(actualParams.size()).append(" were given");

Expand Down
4 changes: 2 additions & 2 deletions src/test/interpreter/VisitorUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ void visitNumberValidInputReturnsNumber(int value) {
}

@Test
void visitNumberInvalidInputThrowsIllegalArgumentException(){
void visitNumberInvalidInputThrowsRuntimeException(){
Mockito.when(mockNumberContext.NUMBER()).thenReturn(new MockTerminalNode("abc"));
Assertions.assertThrows(IllegalArgumentException.class, () -> spyVisitor.visitNumber(mockNumberContext));
Assertions.assertThrows(RuntimeException.class, () -> spyVisitor.visitNumber(mockNumberContext));
}
}