diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java index 4c38fc671..7d092d84d 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java @@ -9,9 +9,7 @@ package com.dfsek.terra.addons.terrascript.parser; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; import com.dfsek.terra.addons.terrascript.parser.lang.Block; @@ -65,23 +63,12 @@ import com.dfsek.terra.api.util.generic.pair.Pair; @SuppressWarnings("unchecked") public class Parser { private final String source; - private final Map>> functions = new HashMap<>(); private final List ignoredFunctions = new ArrayList<>(); public Parser(String source) { this.source = source; } - public Parser registerFunction(String name, FunctionBuilder> functionBuilder) { - functions.put(name, functionBuilder); - return this; - } - - public Parser ignoreFunction(String name) { - ignoredFunctions.add(name); - return this; - } - /** * Parse input * @@ -89,8 +76,7 @@ public class Parser { * * @throws ParseException If parsing fails. */ - public Executable parse() { - ScopeBuilder scopeBuilder = new ScopeBuilder(); + public Executable parse(ScopeBuilder scopeBuilder) { return new Executable(parseBlock(new Tokenizer(source), scopeBuilder), scopeBuilder); } @@ -155,7 +141,7 @@ public class Parser { if(f.isVariableDeclaration()) { VariableAssignmentNode forVar = parseVariableDeclaration(tokenizer, scopeBuilder); Token name = tokenizer.current(); - if(functions.containsKey(name.getContent()) || scopeBuilder.contains(name.getContent())) + if(scopeBuilder.containsKey(name.getContent()) || scopeBuilder.contains(name.getContent())) throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition()); initializer = forVar; } else initializer = parseExpression(tokenizer, true, scopeBuilder); @@ -197,7 +183,7 @@ public class Parser { } else if(id.isType(Token.Type.GROUP_BEGIN)) { // Parse grouped expression expression = parseExpressionGroup(tokenizer, scopeBuilder); } else { - if(functions.containsKey(id.getContent())) + if(scopeBuilder.containsKey(id.getContent())) expression = parseFunctionInvocation(tokenizer, false, scopeBuilder); else if(scopeBuilder.contains(id.getContent())) { ParserUtil.ensureType(tokenizer.consume(), Token.Type.IDENTIFIER); @@ -315,7 +301,7 @@ public class Parser { ParserUtil.checkVarType(type, returnType); // Check for type mismatch Token identifier = tokenizer.consume(); ParserUtil.ensureType(identifier, Token.Type.IDENTIFIER); - if(functions.containsKey(identifier.getContent()) || scopeBuilder.contains(identifier.getContent())) + if(scopeBuilder.containsKey(identifier.getContent()) || scopeBuilder.contains(identifier.getContent())) throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition()); ParserUtil.ensureType(tokenizer.consume(), Token.Type.ASSIGNMENT); @@ -407,7 +393,7 @@ public class Parser { Token identifier = tokenizer.consume(); ParserUtil.ensureType(identifier, Token.Type.IDENTIFIER); // First token must be identifier - if(!functions.containsKey(identifier.getContent())) + if(!scopeBuilder.containsKey(identifier.getContent())) throw new ParseException("No such function \"" + identifier.getContent() + "\"", identifier.getPosition()); ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_BEGIN); // Second is body begin @@ -422,8 +408,8 @@ public class Parser { return Function.NULL; } - if(functions.containsKey(identifier.getContent())) { - FunctionBuilder builder = functions.get(identifier.getContent()); + if(scopeBuilder.containsKey(identifier.getContent())) { + FunctionBuilder builder = scopeBuilder.get(identifier.getContent()); if(builder.argNumber() != -1 && args.size() != builder.argNumber()) throw new ParseException("Expected " + builder.argNumber() + " arguments, found " + args.size(), identifier.getPosition()); diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java index c647cc124..671271c82 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java @@ -1,6 +1,10 @@ package com.dfsek.terra.addons.terrascript.parser.lang; +import com.dfsek.terra.addons.terrascript.parser.Parser; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; + import net.jafama.FastMath; import java.util.HashMap; @@ -46,6 +50,8 @@ public class Scope { } public static final class ScopeBuilder { + + private final Map>> functions; private final Map> indices; private int numSize, boolSize, strSize = 0; private ScopeBuilder parent; @@ -53,6 +59,7 @@ public class Scope { private boolean inLoop; public ScopeBuilder() { + this.functions = new HashMap<>(); this.indices = new HashMap<>(); } @@ -61,6 +68,7 @@ public class Scope { this.numSize = parent.numSize; this.boolSize = parent.boolSize; this.strSize = parent.strSize; + this.functions = new HashMap<>(parent.functions); this.indices = new HashMap<>(parent.indices); this.inLoop = inLoop; } @@ -75,6 +83,19 @@ public class Scope { public ScopeBuilder subInLoop() { return new ScopeBuilder(this, true); } + public ScopeBuilder registerFunction(String name, FunctionBuilder> functionBuilder) { + functions.put(name, functionBuilder); + return this; + } + + public boolean containsKey(String functionName) { + return functions.containsKey(functionName); + } + + public FunctionBuilder get(String functionName) { + return functions.get(functionName); + } + private String check(String id) { if(indices.containsKey(id)) { throw new IllegalArgumentException("Variable with ID " + id + " already registered."); diff --git a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java index 66cbb5abf..6d7eee265 100644 --- a/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java +++ b/common/addons/structure-terrascript-loader/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java @@ -7,6 +7,10 @@ package com.dfsek.terra.addons.terrascript.script; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; + +import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder; + import net.jafama.FastMath; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; @@ -70,10 +74,12 @@ public class StructureScript implements Structure, Keyed { this.id = id; this.profile = "terrascript_direct:" + id; - //noinspection unchecked - functionRegistry.forEach((key, function) -> parser.registerFunction(key.getID(), function)); // Register registry functions. + ScopeBuilder scope = new ScopeBuilder(); - parser + //noinspection unchecked + functionRegistry.forEach((key, function) -> scope.registerFunction(key.getID(), function)); // Register registry functions. + + scope .registerFunction("block", new BlockFunctionBuilder(platform)) .registerFunction("debugBlock", new BlockFunctionBuilder(platform)) .registerFunction("structure", new StructureFunctionBuilder(structureRegistry, platform)) @@ -120,11 +126,7 @@ public class StructureScript implements Structure, Keyed { .registerFunction("min", new BinaryNumberFunctionBuilder( (number, number2) -> FastMath.min(number.doubleValue(), number2.doubleValue()))); - if(!platform.getTerraConfig().isDebugScript()) { - parser.ignoreFunction("debugBlock"); - } - - executable = parser.parse(); + executable = parser.parse(scope); this.platform = platform; } diff --git a/common/addons/structure-terrascript-loader/src/test/java/structure/ParserTest.java b/common/addons/structure-terrascript-loader/src/test/java/structure/ParserTest.java index ab62ec3d9..7428cabed 100644 --- a/common/addons/structure-terrascript-loader/src/test/java/structure/ParserTest.java +++ b/common/addons/structure-terrascript-loader/src/test/java/structure/ParserTest.java @@ -8,6 +8,8 @@ package structure; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder; + import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.Test; @@ -33,7 +35,8 @@ public class ParserTest { Parser parser = new Parser( IOUtils.toString(Objects.requireNonNull(getClass().getResourceAsStream("/test.tesf")), Charset.defaultCharset())); - parser.registerFunction("test", new FunctionBuilder() { + ScopeBuilder scope = new ScopeBuilder(); + scope.registerFunction("test", new FunctionBuilder() { @Override public Test1 build(List> argumentList, SourcePosition position) { return new Test1(argumentList.get(0), argumentList.get(1), position); @@ -56,7 +59,7 @@ public class ParserTest { }); long l = System.nanoTime(); - Executable block = parser.parse(); + Executable block = parser.parse(scope); long t = System.nanoTime() - l; System.out.println("Took " + (double) t / 1000000);