From 177f3428977f8800ad10e1caa229491b6c25c181 Mon Sep 17 00:00:00 2001 From: sabotack Date: Thu, 18 May 2023 13:29:28 +0200 Subject: [PATCH 1/6] fix #100: print crashes if there is no delay --- src/main/interpreter/Visitor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/interpreter/Visitor.java b/src/main/interpreter/Visitor.java index 9e14a11..80f4120 100644 --- a/src/main/interpreter/Visitor.java +++ b/src/main/interpreter/Visitor.java @@ -583,6 +583,7 @@ public MSType visitFuncCall(MineScriptParser.FuncCallContext ctx) { } else { TurtleCommands.print(server, expressionId + " is: " + text, messageType); } + timeout(1); }); } default -> { From b6d539198bb2e5fb5dbc4e55fec6af3a3bee68f4 Mon Sep 17 00:00:00 2001 From: sabotack Date: Thu, 18 May 2023 13:40:30 +0200 Subject: [PATCH 2/6] fix #96: 32K character limit when opening screen --- src/main/java/minescript/block/entity/TurtleBlockEntity.java | 4 +++- src/main/java/minescript/screen/TextEditorScreenHandler.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/minescript/block/entity/TurtleBlockEntity.java b/src/main/java/minescript/block/entity/TurtleBlockEntity.java index a6a7694..0072183 100644 --- a/src/main/java/minescript/block/entity/TurtleBlockEntity.java +++ b/src/main/java/minescript/block/entity/TurtleBlockEntity.java @@ -45,7 +45,9 @@ public void readNbt(NbtCompound nbt) { @Override public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) { - buf.writeString(this.input.getString()); + String text = this.input.getString(); + buf.writeInt(text.length()); + buf.writeString(text, text.length()); } @Override diff --git a/src/main/java/minescript/screen/TextEditorScreenHandler.java b/src/main/java/minescript/screen/TextEditorScreenHandler.java index c5a59d0..391efbf 100644 --- a/src/main/java/minescript/screen/TextEditorScreenHandler.java +++ b/src/main/java/minescript/screen/TextEditorScreenHandler.java @@ -23,7 +23,7 @@ public class TextEditorScreenHandler extends ScreenHandler { public TextEditorScreenHandler(int syncId, PlayerInventory inventory, PacketByteBuf buf) { this(syncId, inventory, (TurtleBlockEntity) null); - inputText = buf.readString(); + inputText = buf.readString(buf.readInt()); } public TextEditorScreenHandler(int syncId, PlayerInventory inventory, @Nullable TurtleBlockEntity entity) { From 1f9e8d0456fd13231eb668e1c6b148d263454701 Mon Sep 17 00:00:00 2001 From: sabotack Date: Thu, 18 May 2023 14:21:17 +0200 Subject: [PATCH 3/6] fix #102: Thread never stopped + unsafe stop --- src/main/interpreter/Interpreter.java | 4 +++ src/main/interpreter/Visitor.java | 3 ++- .../ThreadInterruptedException.java | 5 ++++ .../minescript/block/custom/TurtleBlock.java | 7 +++-- .../minescript/network/MineScriptPackets.java | 2 -- .../packet/StopInterpreterC2SPacket.java | 27 ------------------- 6 files changed, 14 insertions(+), 34 deletions(-) create mode 100644 src/main/interpreter/exceptions/ThreadInterruptedException.java delete mode 100644 src/main/java/minescript/network/packet/StopInterpreterC2SPacket.java diff --git a/src/main/interpreter/Interpreter.java b/src/main/interpreter/Interpreter.java index 320b2b2..5caefa6 100644 --- a/src/main/interpreter/Interpreter.java +++ b/src/main/interpreter/Interpreter.java @@ -2,6 +2,7 @@ import interpreter.antlr.MineScriptLexer; import interpreter.antlr.MineScriptParser; +import interpreter.exceptions.ThreadInterruptedException; import interpreter.types.MSMessageType; import minescript.network.TurtleCommands; import net.minecraft.server.MinecraftServer; @@ -28,6 +29,7 @@ public Interpreter(String program, MinecraftServer server, ServerWorld world, Bl @Override public void run() { try { + System.out.println("Thread started"); // Create a CharStream that reads from standard input CharStream input = CharStreams.fromString(program + System.lineSeparator()); // Create a lexer that feeds off of input CharStream @@ -43,6 +45,8 @@ public void run() { ParseTree tree = parser.program(); // Begin parsing at init rule Visitor visitor = new Visitor(server, world, turtlePos, new SymbolTable()); visitor.visit(tree); + } catch (ThreadInterruptedException e) { + System.out.println(e.getMessage()); } catch (Exception e) { TurtleCommands.print(server, e.getMessage(), MSMessageType.ERROR); } diff --git a/src/main/interpreter/Visitor.java b/src/main/interpreter/Visitor.java index 80f4120..e267e61 100644 --- a/src/main/interpreter/Visitor.java +++ b/src/main/interpreter/Visitor.java @@ -3,6 +3,7 @@ import interpreter.antlr.MineScriptBaseVisitor; import interpreter.antlr.MineScriptParser; import interpreter.exceptions.SymbolNotFoundException; +import interpreter.exceptions.ThreadInterruptedException; import interpreter.types.*; import minescript.network.TurtleCommands; import net.minecraft.block.Block; @@ -764,7 +765,7 @@ private void timeout(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { - throw new RuntimeException(e); + throw new ThreadInterruptedException("Thread was interrupted while waiting"); } } } \ No newline at end of file diff --git a/src/main/interpreter/exceptions/ThreadInterruptedException.java b/src/main/interpreter/exceptions/ThreadInterruptedException.java new file mode 100644 index 0000000..f1cea4e --- /dev/null +++ b/src/main/interpreter/exceptions/ThreadInterruptedException.java @@ -0,0 +1,5 @@ +package interpreter.exceptions; + +public class ThreadInterruptedException extends RuntimeException { + public ThreadInterruptedException(String message) { super(message); } +} diff --git a/src/main/java/minescript/block/custom/TurtleBlock.java b/src/main/java/minescript/block/custom/TurtleBlock.java index 2794356..cd77004 100644 --- a/src/main/java/minescript/block/custom/TurtleBlock.java +++ b/src/main/java/minescript/block/custom/TurtleBlock.java @@ -69,10 +69,9 @@ public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockSt BlockEntity blockEntity = world.getBlockEntity(pos); if (blockEntity instanceof TurtleBlockEntity entity) { - PacketByteBuf buf = PacketByteBufs.create(); - buf.writeBlockPos(entity.getPos()); - - ClientPlayNetworking.send(MineScriptPackets.STOP_INTERPRETER_ID, buf); + if (entity.interpreterThread != null && entity.interpreterThread.isAlive()) { + entity.interpreterThread.interrupt(); + } } } super.onStateReplaced(state, world, pos, newState, moved); diff --git a/src/main/java/minescript/network/MineScriptPackets.java b/src/main/java/minescript/network/MineScriptPackets.java index 6e74104..087a6bd 100644 --- a/src/main/java/minescript/network/MineScriptPackets.java +++ b/src/main/java/minescript/network/MineScriptPackets.java @@ -7,10 +7,8 @@ public class MineScriptPackets { public static final Identifier START_INTERPRETER_ID = new Identifier("minescript", "start_interpreter"); - public static final Identifier STOP_INTERPRETER_ID = new Identifier("minescript", "stop_interpreter"); public static void registerC2SPackets() { ServerPlayNetworking.registerGlobalReceiver(START_INTERPRETER_ID, StartInterpreterC2SPacket::receive); - ServerPlayNetworking.registerGlobalReceiver(STOP_INTERPRETER_ID, StopInterpreterC2SPacket::receive); } } diff --git a/src/main/java/minescript/network/packet/StopInterpreterC2SPacket.java b/src/main/java/minescript/network/packet/StopInterpreterC2SPacket.java deleted file mode 100644 index 0f56a77..0000000 --- a/src/main/java/minescript/network/packet/StopInterpreterC2SPacket.java +++ /dev/null @@ -1,27 +0,0 @@ -package minescript.network.packet; - -import interpreter.Interpreter; -import minescript.block.entity.TurtleBlockEntity; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; - -public class StopInterpreterC2SPacket { - public static void receive(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { - BlockPos pos = buf.readBlockPos(); - - server.executeSync(() -> { - ServerWorld world = player.getWorld(); - TurtleBlockEntity entity = (TurtleBlockEntity) world.getBlockEntity(pos); - - assert entity != null; - if (entity.interpreterThread != null && entity.interpreterThread.isAlive()) { - entity.interpreterThread.stop(); - } - }); - } -} From 0acfb2ef7a03d0d9f2f26bf89b9e6578d29158bd Mon Sep 17 00:00:00 2001 From: sabotack Date: Thu, 18 May 2023 15:17:01 +0200 Subject: [PATCH 4/6] fix #101: function scoping inconsistencies --- src/main/interpreter/Interpreter.java | 3 +- src/main/interpreter/SymbolTable.java | 41 +++++++++++++++------------ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/main/interpreter/Interpreter.java b/src/main/interpreter/Interpreter.java index 5caefa6..fae6143 100644 --- a/src/main/interpreter/Interpreter.java +++ b/src/main/interpreter/Interpreter.java @@ -28,8 +28,8 @@ public Interpreter(String program, MinecraftServer server, ServerWorld world, Bl @Override public void run() { + System.out.println("Thread started"); try { - System.out.println("Thread started"); // Create a CharStream that reads from standard input CharStream input = CharStreams.fromString(program + System.lineSeparator()); // Create a lexer that feeds off of input CharStream @@ -50,5 +50,6 @@ public void run() { } catch (Exception e) { TurtleCommands.print(server, e.getMessage(), MSMessageType.ERROR); } + System.out.println("Thread finished"); } } \ No newline at end of file diff --git a/src/main/interpreter/SymbolTable.java b/src/main/interpreter/SymbolTable.java index ec506a9..99244e3 100644 --- a/src/main/interpreter/SymbolTable.java +++ b/src/main/interpreter/SymbolTable.java @@ -35,12 +35,13 @@ public void enterSymbol(String name, MSType value) { Symbol newSymbol = new Symbol(name, value); checkRestrictedKeyWords(newSymbol); - /*If the variable is already in the current scope, update it*/ - if (isVarInNewScope(name)) { - Symbol oldSymbol = hashMap.get(getPrefixName(name)); + /*If a prefixed version of the variable already exists, update it*/ + String shadowedSymbolName = getShadowedSymbolName(name); + if (shadowedSymbolName != null) { + Symbol oldSymbol = hashMap.get(shadowedSymbolName); delete(oldSymbol.name); - Symbol prefixSymbol = new Symbol(oldSymbol.name, value); - add(prefixSymbol); + Symbol newShadowedSymbol = new Symbol(oldSymbol.name, value); + add(newShadowedSymbol); return; } @@ -77,8 +78,9 @@ else if (symbol.name.equals(funcName.name())){ * @return symbol from the hash table */ public Symbol retrieveSymbol(String name) { - if (isVarInNewScope(name)) { - return hashMap.get(getPrefixName(name)); + String shadowedSymbolName = getShadowedSymbolName(name); + if (shadowedSymbolName != null) { + return hashMap.get(shadowedSymbolName); } else if (hashMap.containsKey(name)) { return hashMap.get(name); } else { @@ -108,20 +110,23 @@ private void add(Symbol symbol) { hashMap.put(symbol.name, symbol); } - /** - * @param name name of the variable - * @return true if the variable is in the current scope - */ - private boolean isVarInNewScope(String name) { - return scopeStack.peek().stream().anyMatch(s -> s.endsWith("." + name)); - } - /** * @param name id of the variable - * @return prefix of the variable + * @return name of the symbol if a prefixed version of it exists in any of the scopes, otherwise null */ - private String getPrefixName(String name) { - return scopeStack.peek().stream().filter(s -> s.contains("." + name)).findFirst().orElseThrow(); + private String getShadowedSymbolName(String name) { + if (scopeStack.empty()) return null; + + ArrayList currentScope = scopeStack.peek(); + if (currentScope.stream().anyMatch(s -> s.endsWith("." + name))) { + return currentScope.stream().filter(s -> s.endsWith("." + name)).findFirst().orElseThrow(); + } + else { + scopeStack.pop(); + String res = getShadowedSymbolName(name); + scopeStack.push(currentScope); + return res; + } } private record Symbol(String name, MSType value) { From 0fc6c7414a52049d7664ab7b0cada284ba268cc8 Mon Sep 17 00:00:00 2001 From: sabotack Date: Thu, 18 May 2023 16:32:07 +0200 Subject: [PATCH 5/6] fix #97: writeNbt and readNbt crash --- .../block/entity/TurtleBlockEntity.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/minescript/block/entity/TurtleBlockEntity.java b/src/main/java/minescript/block/entity/TurtleBlockEntity.java index 0072183..d6888cc 100644 --- a/src/main/java/minescript/block/entity/TurtleBlockEntity.java +++ b/src/main/java/minescript/block/entity/TurtleBlockEntity.java @@ -33,14 +33,30 @@ public void setTurtleInput(String input) { @Override public void writeNbt(NbtCompound nbt) { - nbt.putString("input", this.input.getString()); + String text = input.getString(); + int length = text.length(); + + int splits = (int) Math.ceil((double) length / 50000); + for (int i = 0; i < splits; i++) { + if (i == splits - 1) + nbt.putString("input" + i, text.substring(i * 50000)); + else + nbt.putString("input" + i, text.substring(i * 50000, (i + 1) * 50000)); + } + super.writeNbt(nbt); } @Override public void readNbt(NbtCompound nbt) { + StringBuilder text = new StringBuilder(); + int split = 0; + while (nbt.contains("input" + split)) { + text.append(nbt.getString("input" + split)); + split++; + } + this.input = Text.of(text.toString()); super.readNbt(nbt); - this.input = Text.of(nbt.getString("input")); } @Override From 40cf9b0da08d664df2fec2e35b88ce147b2a468d Mon Sep 17 00:00:00 2001 From: Mads Risager <55142245+MadsSR@users.noreply.github.com> Date: Mon, 22 May 2023 10:11:26 +0200 Subject: [PATCH 6/6] Fix built-in function name and sqrf logic (#105) --- src/main/interpreter/Visitor.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/interpreter/Visitor.java b/src/main/interpreter/Visitor.java index e267e61..aaddecb 100644 --- a/src/main/interpreter/Visitor.java +++ b/src/main/interpreter/Visitor.java @@ -447,7 +447,7 @@ public MSType visitFuncCall(MineScriptParser.FuncCallContext ctx) { throw new RuntimeException(getFuncCallErrorMessage(id, new int[]{1}, "number", actualParams)); } - retVal = new MSNumber((int) Math.round(Math.sqrt(n.getValue()))); + retVal = new MSNumber((int) Math.floor(Math.sqrt(n.getValue()))); } case "Random" -> { /*If no parameter is used returns a random unbounded int*/ @@ -478,21 +478,21 @@ public MSType visitFuncCall(MineScriptParser.FuncCallContext ctx) { this.turtleDelay = 200 - n.getValue() * 20; } - case "GetXPosition" -> { + case "GetXCoordinate" -> { if (actualParams.size() != 0) { throw new RuntimeException(getFuncCallErrorMessage(id, new int[]{0}, "", actualParams)); } retVal = new MSNumber(pos.getX()); } - case "GetYPosition" -> { + case "GetYCoordinate" -> { if (actualParams.size() != 0) { throw new RuntimeException(getFuncCallErrorMessage(id, new int[]{0}, "", actualParams)); } retVal = new MSNumber(pos.getY()); } - case "GetZPosition" -> { + case "GetZCoordinate" -> { if (actualParams.size() != 0) { throw new RuntimeException(getFuncCallErrorMessage(id, new int[]{0}, "", actualParams)); }