mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-04 06:46:21 +00:00
Handle functions in scope
This commit is contained in:
@@ -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<String, FunctionBuilder<? extends Function<?>>> functions = new HashMap<>();
|
||||
private final List<String> ignoredFunctions = new ArrayList<>();
|
||||
|
||||
public Parser(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public Parser registerFunction(String name, FunctionBuilder<? extends Function<?>> 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());
|
||||
|
||||
@@ -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<String, FunctionBuilder<? extends Function<?>>> functions;
|
||||
private final Map<String, Pair<Integer, ReturnType>> 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<? extends Function<?>> 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.");
|
||||
|
||||
@@ -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<StructureScript> {
|
||||
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<StructureScript> {
|
||||
.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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Test1>() {
|
||||
ScopeBuilder scope = new ScopeBuilder();
|
||||
scope.registerFunction("test", new FunctionBuilder<Test1>() {
|
||||
@Override
|
||||
public Test1 build(List<Expression<?>> 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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user