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