implement break, return, and continue

This commit is contained in:
dfsek
2020-12-23 01:37:51 -07:00
parent 1158ae958a
commit b4342a36aa
16 changed files with 179 additions and 45 deletions

View File

@@ -11,7 +11,10 @@ import com.dfsek.terra.api.structures.parser.lang.constants.NumericConstant;
import com.dfsek.terra.api.structures.parser.lang.constants.StringConstant;
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.parser.lang.keywords.BreakKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.ContinueKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.IfKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.ReturnKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.WhileKeyword;
import com.dfsek.terra.api.structures.parser.lang.operations.BinaryOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanAndOperation;
@@ -244,7 +247,7 @@ public class Parser {
Token token = tokens.get(0);
if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE);
ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE);
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc)
parsedItems.add(parseLoopLike(tokens, parsedVariables));
@@ -272,7 +275,10 @@ public class Parser {
ParserUtil.checkType(tokens.remove(0), Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
parsedItems.add(parseAssignment(temp, tokens, parsedVariables));
} else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
} else if(token.getType().equals(Token.Type.RETURN)) parsedItems.add(new ReturnKeyword(tokens.remove(0).getPosition()));
else if(token.getType().equals(Token.Type.BREAK)) parsedItems.add(new BreakKeyword(tokens.remove(0).getPosition()));
else if(token.getType().equals(Token.Type.CONTINUE)) parsedItems.add(new ContinueKeyword(tokens.remove(0).getPosition()));
else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
if(!tokens.isEmpty()) ParserUtil.checkType(tokens.remove(0), Token.Type.STATEMENT_END, Token.Type.BLOCK_END);
}

View File

@@ -7,7 +7,7 @@ import com.dfsek.terra.api.structures.tokenizer.Position;
import java.util.List;
public class Block implements Item<Void> {
public class Block implements Item<Block.ReturnLevel> {
private final List<Item<?>> items;
private final Position position;
@@ -21,19 +21,36 @@ public class Block implements Item<Void> {
}
@Override
public Void apply(Location location, Rotation rotation) {
items.forEach(item -> item.apply(location, rotation));
return null;
public ReturnLevel apply(Location location, Rotation rotation) {
for(Item<?> item : items) {
Object result = item.apply(location, rotation);
if(result instanceof ReturnLevel) {
ReturnLevel level = (ReturnLevel) result;
if(!level.equals(ReturnLevel.NONE)) return level;
}
}
return ReturnLevel.NONE;
}
@Override
public Void apply(Location location, Chunk chunk, Rotation rotation) {
items.forEach(item -> item.apply(location, chunk, rotation));
return null;
public ReturnLevel apply(Location location, Chunk chunk, Rotation rotation) {
for(Item<?> item : items) {
Object result = item.apply(location, chunk, rotation);
if(result instanceof ReturnLevel) {
ReturnLevel level = (ReturnLevel) result;
if(!level.equals(ReturnLevel.NONE)) return level;
}
}
return ReturnLevel.NONE;
}
@Override
public Position getPosition() {
return position;
}
public enum ReturnLevel {
NONE, BREAK, CONTINUE, RETURN
}
}

View File

@@ -0,0 +1,36 @@
package com.dfsek.terra.api.structures.parser.lang.keywords;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.structures.parser.lang.Block;
import com.dfsek.terra.api.structures.parser.lang.Keyword;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.tokenizer.Position;
public class BreakKeyword implements Keyword<Block.ReturnLevel> {
private final Position position;
public BreakKeyword(Position position) {
this.position = position;
}
@Override
public Block.ReturnLevel apply(Location location, Rotation rotation) {
return Block.ReturnLevel.BREAK;
}
@Override
public Block.ReturnLevel apply(Location location, Chunk chunk, Rotation rotation) {
return Block.ReturnLevel.BREAK;
}
@Override
public Position getPosition() {
return position;
}
@Override
public ReturnType returnType() {
return ReturnType.VOID;
}
}

View File

@@ -0,0 +1,36 @@
package com.dfsek.terra.api.structures.parser.lang.keywords;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.structures.parser.lang.Block;
import com.dfsek.terra.api.structures.parser.lang.Keyword;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.tokenizer.Position;
public class ContinueKeyword implements Keyword<Block.ReturnLevel> {
private final Position position;
public ContinueKeyword(Position position) {
this.position = position;
}
@Override
public Block.ReturnLevel apply(Location location, Rotation rotation) {
return Block.ReturnLevel.CONTINUE;
}
@Override
public Block.ReturnLevel apply(Location location, Chunk chunk, Rotation rotation) {
return Block.ReturnLevel.CONTINUE;
}
@Override
public Position getPosition() {
return position;
}
@Override
public ReturnType returnType() {
return ReturnType.VOID;
}
}

View File

@@ -8,7 +8,7 @@ import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.tokenizer.Position;
public class IfKeyword implements Keyword<Void> {
public class IfKeyword implements Keyword<Block.ReturnLevel> {
private final Block conditional;
private final Returnable<Boolean> statement;
private final Position position;
@@ -20,15 +20,15 @@ public class IfKeyword implements Keyword<Void> {
}
@Override
public Void apply(Location location, Rotation rotation) {
if(statement.apply(location, rotation)) conditional.apply(location, rotation);
return null;
public Block.ReturnLevel apply(Location location, Rotation rotation) {
if(statement.apply(location, rotation)) return conditional.apply(location, rotation);
return Block.ReturnLevel.NONE;
}
@Override
public Void apply(Location location, Chunk chunk, Rotation rotation) {
if(statement.apply(location, chunk, rotation)) conditional.apply(location, chunk, rotation);
return null;
public Block.ReturnLevel apply(Location location, Chunk chunk, Rotation rotation) {
if(statement.apply(location, chunk, rotation)) return conditional.apply(location, chunk, rotation);
return Block.ReturnLevel.NONE;
}
@Override

View File

@@ -2,11 +2,12 @@ package com.dfsek.terra.api.structures.parser.lang.keywords;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.structures.parser.lang.Block;
import com.dfsek.terra.api.structures.parser.lang.Keyword;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.tokenizer.Position;
public class ReturnKeyword implements Keyword<Void> {
public class ReturnKeyword implements Keyword<Block.ReturnLevel> {
private final Position position;
public ReturnKeyword(Position position) {
@@ -14,13 +15,13 @@ public class ReturnKeyword implements Keyword<Void> {
}
@Override
public Void apply(Location location, Rotation rotation) {
return null;
public Block.ReturnLevel apply(Location location, Rotation rotation) {
return Block.ReturnLevel.RETURN;
}
@Override
public Void apply(Location location, Chunk chunk, Rotation rotation) {
return null;
public Block.ReturnLevel apply(Location location, Chunk chunk, Rotation rotation) {
return Block.ReturnLevel.RETURN;
}
@Override

View File

@@ -8,7 +8,7 @@ import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.tokenizer.Position;
public class WhileKeyword implements Keyword<Void> {
public class WhileKeyword implements Keyword<Block.ReturnLevel> {
private final Block conditional;
private final Returnable<Boolean> statement;
private final Position position;
@@ -20,15 +20,23 @@ public class WhileKeyword implements Keyword<Void> {
}
@Override
public Void apply(Location location, Rotation rotation) {
while(statement.apply(location, rotation)) conditional.apply(location, rotation);
return null;
public Block.ReturnLevel apply(Location location, Rotation rotation) {
while(statement.apply(location, rotation)) {
Block.ReturnLevel level = conditional.apply(location, rotation);
if(level.equals(Block.ReturnLevel.BREAK)) break;
if(level.equals(Block.ReturnLevel.RETURN)) return Block.ReturnLevel.RETURN;
}
return Block.ReturnLevel.NONE;
}
@Override
public Void apply(Location location, Chunk chunk, Rotation rotation) {
while(statement.apply(location, chunk, rotation)) conditional.apply(location, chunk, rotation);
return null;
public Block.ReturnLevel apply(Location location, Chunk chunk, Rotation rotation) {
while(statement.apply(location, chunk, rotation)) {
Block.ReturnLevel level = conditional.apply(location, chunk, rotation);
if(level.equals(Block.ReturnLevel.BREAK)) break;
if(level.equals(Block.ReturnLevel.RETURN)) return Block.ReturnLevel.RETURN;
}
return Block.ReturnLevel.NONE;
}
@Override

View File

@@ -1,6 +1,7 @@
package com.dfsek.terra.api.structures.script.functions;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.Chunk;
@@ -9,7 +10,9 @@ import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.constants.ConstantExpression;
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.RotationUtil;
import com.dfsek.terra.api.structures.tokenizer.Position;
import net.jafama.FastMath;
public class BlockFunction implements Function<Void> {
private final BlockData data;
@@ -33,7 +36,11 @@ public class BlockFunction implements Function<Void> {
@Override
public Void apply(Location location, Rotation rotation) {
location.clone().add(x.apply(location, rotation).intValue(), y.apply(location, rotation).intValue(), z.apply(location, rotation).intValue()).getBlock().setBlockData(data, false);
Vector2 xz = new Vector2(x.apply(location, rotation).doubleValue(), z.apply(location, rotation).doubleValue());
RotationUtil.rotateVector(xz, rotation);
location.clone().add(FastMath.roundToInt(xz.getX()), y.apply(location, rotation).intValue(), FastMath.roundToInt(xz.getZ())).getBlock().setBlockData(data, false);
return null;
}

View File

@@ -1,6 +1,7 @@
package com.dfsek.terra.api.structures.script.functions;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.world.Chunk;
@@ -8,9 +9,11 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.RotationUtil;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.api.structures.world.LandCheck;
import com.dfsek.terra.api.structures.world.OceanCheck;
import net.jafama.FastMath;
public class CheckFunction implements Function<String> {
private final TerraPlugin main;
@@ -31,8 +34,13 @@ public class CheckFunction implements Function<String> {
}
private Vector3 getVector(Location location, Chunk chunk, Rotation rotation) {
return location.clone().add(chunk == null ? new Vector3(x.apply(location, rotation).intValue(), y.apply(location, rotation).intValue(), z.apply(location, rotation).intValue())
: new Vector3(x.apply(location, chunk, rotation).intValue(), y.apply(location, chunk, rotation).intValue(), z.apply(location, chunk, rotation).intValue())).toVector();
Vector2 xz = chunk == null ? new Vector2(x.apply(location, rotation).doubleValue(), z.apply(location, rotation).doubleValue())
: new Vector2(x.apply(location, chunk, rotation).doubleValue(), z.apply(location, chunk, rotation).doubleValue());
RotationUtil.rotateVector(xz, rotation);
return location.clone().add(chunk == null ? new Vector3(FastMath.roundToInt(xz.getX()), y.apply(location, rotation).intValue(), FastMath.roundToInt(xz.getZ()))
: new Vector3(FastMath.roundToInt(xz.getX()), y.apply(location, chunk, rotation).intValue(), FastMath.roundToInt(xz.getZ()))).toVector();
}
@Override

View File

@@ -26,9 +26,8 @@ public class RotationUtil {
*
* @param orig Vector to rotate.
* @param r Rotation
* @return Rotated coordinate pair
*/
public static Vector2 getRotatedCoords(Vector2 orig, Rotation r) {
public static void rotateVector(Vector2 orig, Rotation r) {
Vector2 copy = orig.clone();
switch(r) {
case CW_90:
@@ -41,7 +40,8 @@ public class RotationUtil {
copy.multiply(-1);
break;
}
return copy;
orig.setX(copy.getX());
orig.setZ(copy.getZ());
}
/**

View File

@@ -183,6 +183,10 @@ public class Token {
BOOLEAN_VARIABLE,
IF_STATEMENT,
WHILE_LOOP
WHILE_LOOP,
RETURN,
CONTINUE,
BREAK
}
}

View File

@@ -12,7 +12,6 @@ public class Tokenizer {
private final Lookahead reader;
public static final Set<Character> syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', ',', '\\', '=', '{', '}', '+', '-', '*', '/', '>', '<', '!'); // Reserved chars
private final Set<String> keywords = Sets.newHashSet("if", "while", "num", "bool", "str");
public Tokenizer(String data) {
@@ -41,14 +40,15 @@ public class Tokenizer {
return new Token("==", Token.Type.EQUALS_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
if(reader.matches("!=", true))
return new Token("!=", Token.Type.NOT_EQUALS_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
if(reader.matches(">", true))
return new Token(">", Token.Type.GREATER_THAN_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
if(reader.matches("<", true))
return new Token("<", Token.Type.LESS_THAN_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
if(reader.matches(">=", true))
return new Token(">=", Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
if(reader.matches("<=", true))
return new Token("<=", Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
if(reader.matches(">", true))
return new Token(">", Token.Type.GREATER_THAN_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
if(reader.matches("<", true))
return new Token("<", Token.Type.LESS_THAN_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
if(reader.matches("||", true))
return new Token("||", Token.Type.BOOLEAN_OR, new Position(reader.getLine(), reader.getIndex()));
@@ -134,6 +134,13 @@ public class Tokenizer {
if(tokenString.equals("while"))
return new Token(tokenString, Token.Type.WHILE_LOOP, new Position(reader.getLine(), reader.getIndex()));
if(tokenString.equals("return"))
return new Token(tokenString, Token.Type.RETURN, new Position(reader.getLine(), reader.getIndex()));
if(tokenString.equals("continue"))
return new Token(tokenString, Token.Type.CONTINUE, new Position(reader.getLine(), reader.getIndex()));
if(tokenString.equals("break"))
return new Token(tokenString, Token.Type.BREAK, new Position(reader.getLine(), reader.getIndex()));
return new Token(tokenString, Token.Type.IDENTIFIER, new Position(reader.getLine(), reader.getIndex()));
}

View File

@@ -46,7 +46,7 @@ public class TerraTree implements Tree {
Rotation rotation = Rotation.fromDegrees(random.nextInt(4) * 90);
StructureInfo info = struc.getStructureInfo();
for(StructureContainedBlock spawn : struc.getSpawns()) {
Vector2 rot = RotationUtil.getRotatedCoords(new Vector2(spawn.getX() - info.getCenterX(), spawn.getZ() - info.getCenterZ()), rotation);
Vector2 rot = RotationUtil.rotateVector(new Vector2(spawn.getX() - info.getCenterX(), spawn.getZ() - info.getCenterZ()), rotation);
int x = (int) rot.getX();
int z = (int) rot.getZ();
switch(spawn.getRequirement()) {

View File

@@ -44,7 +44,7 @@ public class StructurePopulator implements TerraBlockPopulator {
struc.paste(spawn, chunk, rotation, main);
for(StructureContainedInventory i : struc.getInventories()) {
try {
Vector2 lootCoords = RotationUtil.getRotatedCoords(new Vector2(i.getX() - struc.getStructureInfo().getCenterX(), i.getZ() - struc.getStructureInfo().getCenterZ()), rotation.inverse());
Vector2 lootCoords = RotationUtil.rotateVector(new Vector2(i.getX() - struc.getStructureInfo().getCenterX(), i.getZ() - struc.getStructureInfo().getCenterZ()), rotation.inverse());
Location inv = spawn.clone().add(lootCoords.getX(), i.getY(), lootCoords.getZ());
if(FastMath.floorDiv(inv.getBlockX(), 16) != chunk.getX() || FastMath.floorDiv(inv.getBlockZ(), 16) != chunk.getZ())
continue;

View File

@@ -12,13 +12,16 @@ bool truetest = false;
num iterator = 0;
while(iterator < 5) {
test("fdsgdf" + 2 + stringVar, iterator);
test("always, even after " + 2, iterator);
iterator = iterator + 1;
if(iterator > 2) {
continue;
}
test("not after " + 2, iterator);
}
if(true && !(boolean && false) && true) {
test(0,-1,0, "minecraft:green_w" + "ool");
num scopedVar = 2;
test("if statement" + 2 + stringVar, 1 + testVar + scopedVar);
}

View File

@@ -21,6 +21,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
public class LoadRawCommand extends LoadCommand implements DebugCommand {
@@ -49,7 +50,7 @@ public class LoadRawCommand extends LoadCommand implements DebugCommand {
System.out.println("Done parsing");
main.apply(new Location(new BukkitWorld(sender.getWorld()), sender.getLocation().getX(), sender.getLocation().getY(), sender.getLocation().getZ()), Rotation.NONE);
main.apply(new Location(new BukkitWorld(sender.getWorld()), sender.getLocation().getX(), sender.getLocation().getY(), sender.getLocation().getZ()), Rotation.fromDegrees(90 * ThreadLocalRandom.current().nextInt(4)));
} catch(IOException | ParseException e) {
e.printStackTrace();