mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-02 16:05:29 +00:00
use local variable table for terrascript
This commit is contained in:
parent
613b96288a
commit
b2cc0d48aa
@ -15,9 +15,12 @@ import java.util.Map;
|
||||
|
||||
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.Executable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Item;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable.ReturnType;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.BooleanConstant;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.ConstantExpression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.NumericConstant;
|
||||
@ -48,12 +51,17 @@ import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.Grea
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.LessThanOrEqualsStatement;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.LessThanStatement;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.NotEqualsStatement;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.VariableAssignmentNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.VariableDeclarationNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.VariableReferenceNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.BoolAssignmentNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.NumAssignmentNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.StrAssignmentNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.VariableAssignmentNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.BoolVariableReferenceNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.NumVariableReferenceNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.StrVariableReferenceNode;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Token;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Tokenizer;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -83,11 +91,12 @@ public class Parser {
|
||||
*
|
||||
* @throws ParseException If parsing fails.
|
||||
*/
|
||||
public Block parse() {
|
||||
return parseBlock(new Tokenizer(data), new HashMap<>(), false);
|
||||
public Executable parse() {
|
||||
ScopeBuilder scopeBuilder = new ScopeBuilder();
|
||||
return new Executable(parseBlock(new Tokenizer(data), false, scopeBuilder), scopeBuilder);
|
||||
}
|
||||
|
||||
private Keyword<?> parseLoopLike(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap, boolean loop) throws ParseException {
|
||||
private Keyword<?> parseLoopLike(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) throws ParseException {
|
||||
|
||||
Token identifier = tokens.consume();
|
||||
ParserUtil.checkType(identifier, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP);
|
||||
@ -95,43 +104,43 @@ public class Parser {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
|
||||
|
||||
return switch(identifier.getType()) {
|
||||
case FOR_LOOP -> parseForLoop(tokens, variableMap, identifier.getPosition());
|
||||
case IF_STATEMENT -> parseIfStatement(tokens, variableMap, identifier.getPosition(), loop);
|
||||
case WHILE_LOOP -> parseWhileLoop(tokens, variableMap, identifier.getPosition());
|
||||
case FOR_LOOP -> parseForLoop(tokens, identifier.getPosition(), scopeBuilder);
|
||||
case IF_STATEMENT -> parseIfStatement(tokens, identifier.getPosition(), loop, scopeBuilder);
|
||||
case WHILE_LOOP -> parseWhileLoop(tokens, identifier.getPosition(), scopeBuilder);
|
||||
default -> throw new UnsupportedOperationException(
|
||||
"Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
|
||||
};
|
||||
}
|
||||
|
||||
private WhileKeyword parseWhileLoop(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap, Position start) {
|
||||
Returnable<?> first = parseExpression(tokens, true, variableMap);
|
||||
private WhileKeyword parseWhileLoop(Tokenizer tokens, Position start, ScopeBuilder scopeBuilder) {
|
||||
Returnable<?> first = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkReturnType(first, Returnable.ReturnType.BOOLEAN);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
|
||||
return new WhileKeyword(parseStatementBlock(tokens, variableMap, true), (Returnable<Boolean>) first, start); // While loop
|
||||
return new WhileKeyword(parseStatementBlock(tokens, true, scopeBuilder), (Returnable<Boolean>) first, start); // While loop
|
||||
}
|
||||
|
||||
private IfKeyword parseIfStatement(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap, Position start, boolean loop) {
|
||||
Returnable<?> condition = parseExpression(tokens, true, variableMap);
|
||||
private IfKeyword parseIfStatement(Tokenizer tokens, Position start, boolean loop, ScopeBuilder scopeBuilder) {
|
||||
Returnable<?> condition = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkReturnType(condition, Returnable.ReturnType.BOOLEAN);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
|
||||
Block elseBlock = null;
|
||||
Block statement = parseStatementBlock(tokens, variableMap, loop);
|
||||
Block statement = parseStatementBlock(tokens, loop, scopeBuilder);
|
||||
|
||||
List<IfKeyword.Pair<Returnable<Boolean>, Block>> elseIf = new ArrayList<>();
|
||||
List<Pair<Returnable<Boolean>, Block>> elseIf = new ArrayList<>();
|
||||
|
||||
while(tokens.hasNext() && tokens.get().getType().equals(Token.Type.ELSE)) {
|
||||
tokens.consume(); // Consume else.
|
||||
if(tokens.get().getType().equals(Token.Type.IF_STATEMENT)) {
|
||||
tokens.consume(); // Consume if.
|
||||
Returnable<?> elseCondition = parseExpression(tokens, true, variableMap);
|
||||
Returnable<?> elseCondition = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkReturnType(elseCondition, Returnable.ReturnType.BOOLEAN);
|
||||
elseIf.add(new IfKeyword.Pair<>((Returnable<Boolean>) elseCondition, parseStatementBlock(tokens, variableMap, loop)));
|
||||
elseIf.add(Pair.of((Returnable<Boolean>) elseCondition, parseStatementBlock(tokens, loop, scopeBuilder)));
|
||||
} else {
|
||||
elseBlock = parseStatementBlock(tokens, variableMap, loop);
|
||||
elseBlock = parseStatementBlock(tokens, loop, scopeBuilder);
|
||||
break; // Else must be last.
|
||||
}
|
||||
}
|
||||
@ -139,51 +148,51 @@ public class Parser {
|
||||
return new IfKeyword(statement, (Returnable<Boolean>) condition, elseIf, elseBlock, start); // If statement
|
||||
}
|
||||
|
||||
private Block parseStatementBlock(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap, boolean loop) {
|
||||
private Block parseStatementBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) {
|
||||
|
||||
if(tokens.get().getType().equals(Token.Type.BLOCK_BEGIN)) {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN);
|
||||
Block block = parseBlock(tokens, variableMap, loop);
|
||||
Block block = parseBlock(tokens, loop, scopeBuilder);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_END);
|
||||
return block;
|
||||
} else {
|
||||
Position position = tokens.get().getPosition();
|
||||
Block block = new Block(Collections.singletonList(parseItem(tokens, variableMap, loop)), position);
|
||||
Block block = new Block(Collections.singletonList(parseItem(tokens, loop, scopeBuilder)), position);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
private ForKeyword parseForLoop(Tokenizer tokens, Map<String, Returnable.ReturnType> old, Position start) {
|
||||
Map<String, Returnable.ReturnType> variableMap = new HashMap<>(old); // New scope
|
||||
private ForKeyword parseForLoop(Tokenizer tokens, Position start, ScopeBuilder scopeBuilder) {
|
||||
scopeBuilder = scopeBuilder.sub(); // new scope
|
||||
Token f = tokens.get();
|
||||
ParserUtil.checkType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER);
|
||||
Item<?> initializer;
|
||||
if(f.isVariableDeclaration()) {
|
||||
VariableDeclarationNode<?> forVar = parseVariableDeclaration(tokens, variableMap);
|
||||
VariableAssignmentNode<?> forVar = parseVariableDeclaration(tokens, scopeBuilder);
|
||||
Token name = tokens.get();
|
||||
if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent()))
|
||||
if(functions.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(tokens, true, variableMap);
|
||||
} else initializer = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
Returnable<?> conditional = parseExpression(tokens, true, variableMap);
|
||||
Returnable<?> conditional = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkReturnType(conditional, Returnable.ReturnType.BOOLEAN);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
|
||||
Item<?> incrementer;
|
||||
Token token = tokens.get();
|
||||
if(variableMap.containsKey(token.getContent())) { // Assume variable assignment
|
||||
incrementer = parseAssignment(tokens, variableMap);
|
||||
} else incrementer = parseFunction(tokens, true, variableMap);
|
||||
if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment
|
||||
incrementer = parseAssignment(tokens, scopeBuilder);
|
||||
} else incrementer = parseFunction(tokens, true, scopeBuilder);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
|
||||
return new ForKeyword(parseStatementBlock(tokens, variableMap, true), initializer, (Returnable<Boolean>) conditional, incrementer,
|
||||
return new ForKeyword(parseStatementBlock(tokens, true, scopeBuilder), initializer, (Returnable<Boolean>) conditional, incrementer,
|
||||
start);
|
||||
}
|
||||
|
||||
private Returnable<?> parseExpression(Tokenizer tokens, boolean full, Map<String, Returnable.ReturnType> variableMap) {
|
||||
private Returnable<?> parseExpression(Tokenizer tokens, boolean full, ScopeBuilder scopeBuilder) {
|
||||
boolean booleanInverted = false; // Check for boolean not operator
|
||||
boolean negate = false;
|
||||
if(tokens.get().getType().equals(Token.Type.BOOLEAN_NOT)) {
|
||||
@ -202,13 +211,21 @@ public class Parser {
|
||||
if(id.isConstant()) {
|
||||
expression = parseConstantExpression(tokens);
|
||||
} else if(id.getType().equals(Token.Type.GROUP_BEGIN)) { // Parse grouped expression
|
||||
expression = parseGroup(tokens, variableMap);
|
||||
expression = parseGroup(tokens, scopeBuilder);
|
||||
} else {
|
||||
if(functions.containsKey(id.getContent()))
|
||||
expression = parseFunction(tokens, false, variableMap);
|
||||
else if(variableMap.containsKey(id.getContent())) {
|
||||
expression = parseFunction(tokens, false, scopeBuilder);
|
||||
else if(scopeBuilder.contains(id.getContent())) {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER);
|
||||
expression = new VariableReferenceNode(id.getContent(), id.getPosition(), variableMap.get(id.getContent()));
|
||||
String varId = id.getContent();
|
||||
ReturnType varType = scopeBuilder.getType(varId);
|
||||
expression = switch(varType) {
|
||||
case NUMBER -> new NumVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId));
|
||||
case STRING -> new StrVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId));
|
||||
case BOOLEAN -> new BoolVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId));
|
||||
default -> throw new ParseException("Illegal type for variable reference: " + varType, id.getPosition());
|
||||
};
|
||||
|
||||
} else throw new ParseException("Unexpected token \" " + id.getContent() + "\"", id.getPosition());
|
||||
}
|
||||
|
||||
@ -221,7 +238,7 @@ public class Parser {
|
||||
}
|
||||
|
||||
if(full && tokens.get().isBinaryOperator()) { // Parse binary operations
|
||||
return parseBinaryOperation(expression, tokens, variableMap);
|
||||
return parseBinaryOperation(expression, tokens, scopeBuilder);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
@ -243,25 +260,25 @@ public class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
private Returnable<?> parseGroup(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap) {
|
||||
private Returnable<?> parseGroup(Tokenizer tokens, ScopeBuilder scopeBuilder) {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
|
||||
Returnable<?> expression = parseExpression(tokens, true, variableMap); // Parse inside of group as a separate expression
|
||||
Returnable<?> expression = parseExpression(tokens, true, scopeBuilder); // Parse inside of group as a separate expression
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
return expression;
|
||||
}
|
||||
|
||||
private BinaryOperation<?, ?> parseBinaryOperation(Returnable<?> left, Tokenizer tokens,
|
||||
Map<String, Returnable.ReturnType> variableMap) {
|
||||
ScopeBuilder scopeBuilder) {
|
||||
Token binaryOperator = tokens.consume();
|
||||
ParserUtil.checkBinaryOperator(binaryOperator);
|
||||
|
||||
Returnable<?> right = parseExpression(tokens, false, variableMap);
|
||||
Returnable<?> right = parseExpression(tokens, false, scopeBuilder);
|
||||
|
||||
Token other = tokens.get();
|
||||
if(ParserUtil.hasPrecedence(binaryOperator.getType(), other.getType())) {
|
||||
return assemble(left, parseBinaryOperation(right, tokens, variableMap), binaryOperator);
|
||||
return assemble(left, parseBinaryOperation(right, tokens, scopeBuilder), binaryOperator);
|
||||
} else if(other.isBinaryOperator()) {
|
||||
return parseBinaryOperation(assemble(left, right, binaryOperator), tokens, variableMap);
|
||||
return parseBinaryOperation(assemble(left, right, binaryOperator), tokens, scopeBuilder);
|
||||
}
|
||||
return assemble(left, right, binaryOperator);
|
||||
}
|
||||
@ -306,7 +323,7 @@ public class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
private VariableDeclarationNode<?> parseVariableDeclaration(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap) {
|
||||
private VariableAssignmentNode<?> parseVariableDeclaration(Tokenizer tokens, ScopeBuilder scopeBuilder) {
|
||||
Token type = tokens.consume();
|
||||
ParserUtil.checkType(type, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
|
||||
|
||||
@ -315,30 +332,34 @@ public class Parser {
|
||||
ParserUtil.checkVarType(type, returnType); // Check for type mismatch
|
||||
Token identifier = tokens.consume();
|
||||
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER);
|
||||
if(functions.containsKey(identifier.getContent()) || variableMap.containsKey(identifier.getContent()))
|
||||
if(functions.containsKey(identifier.getContent()) || scopeBuilder.contains(identifier.getContent()))
|
||||
throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition());
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT);
|
||||
|
||||
Returnable<?> value = parseExpression(tokens, true, variableMap);
|
||||
Returnable<?> value = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkReturnType(value, returnType);
|
||||
|
||||
variableMap.put(identifier.getContent(), returnType);
|
||||
|
||||
return new VariableDeclarationNode<>(tokens.get().getPosition(), identifier.getContent(), value, returnType);
|
||||
|
||||
String id = identifier.getContent();
|
||||
|
||||
return switch(type.getType()) {
|
||||
case NUMBER -> new NumAssignmentNode((Returnable<Number>) value, identifier.getPosition(), scopeBuilder.num(id));
|
||||
case STRING -> new StrAssignmentNode((Returnable<String>) value, identifier.getPosition(), scopeBuilder.str(id));
|
||||
case BOOLEAN -> new BoolAssignmentNode((Returnable<Boolean>) value, identifier.getPosition(), scopeBuilder.bool(id));
|
||||
default -> throw new ParseException("Illegal type for variable assignment: " + type, value.getPosition());
|
||||
};
|
||||
}
|
||||
|
||||
private Block parseBlock(Tokenizer tokens, Map<String, Returnable.ReturnType> superVars, boolean loop) {
|
||||
private Block parseBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) {
|
||||
List<Item<?>> parsedItems = new ArrayList<>();
|
||||
|
||||
Map<String, Returnable.ReturnType> parsedVariables = new HashMap<>(
|
||||
superVars); // New hashmap as to not mutate parent scope's declarations.
|
||||
scopeBuilder = scopeBuilder.sub();
|
||||
|
||||
Token first = tokens.get();
|
||||
|
||||
while(tokens.hasNext()) {
|
||||
Token token = tokens.get();
|
||||
if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
|
||||
Item<?> parsedItem = parseItem(tokens, parsedVariables, loop);
|
||||
Item<?> parsedItem = parseItem(tokens, loop, scopeBuilder);
|
||||
if(parsedItem != Function.NULL) {
|
||||
parsedItems.add(parsedItem);
|
||||
}
|
||||
@ -347,7 +368,7 @@ public class Parser {
|
||||
return new Block(parsedItems, first.getPosition());
|
||||
}
|
||||
|
||||
private Item<?> parseItem(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap, boolean loop) {
|
||||
private Item<?> parseItem(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) {
|
||||
Token token = tokens.get();
|
||||
if(loop) ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
|
||||
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE,
|
||||
@ -357,14 +378,14 @@ public class Parser {
|
||||
Token.Type.FAIL);
|
||||
|
||||
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc)
|
||||
return parseLoopLike(tokens, variableMap, loop);
|
||||
return parseLoopLike(tokens, loop, scopeBuilder);
|
||||
} else if(token.isIdentifier()) { // Parse identifiers
|
||||
if(variableMap.containsKey(token.getContent())) { // Assume variable assignment
|
||||
return parseAssignment(tokens, variableMap);
|
||||
} else return parseFunction(tokens, true, variableMap);
|
||||
if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment
|
||||
return parseAssignment(tokens, scopeBuilder);
|
||||
} else return parseFunction(tokens, true, scopeBuilder);
|
||||
} else if(token.isVariableDeclaration()) {
|
||||
|
||||
return parseVariableDeclaration(tokens, variableMap);
|
||||
return parseVariableDeclaration(tokens, scopeBuilder);
|
||||
|
||||
} else if(token.getType().equals(Token.Type.RETURN)) return new ReturnKeyword(tokens.consume().getPosition());
|
||||
else if(token.getType().equals(Token.Type.BREAK)) return new BreakKeyword(tokens.consume().getPosition());
|
||||
@ -373,21 +394,30 @@ public class Parser {
|
||||
else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
|
||||
}
|
||||
|
||||
private VariableAssignmentNode<?> parseAssignment(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap) {
|
||||
private VariableAssignmentNode<?> parseAssignment(Tokenizer tokens, ScopeBuilder scopeBuilder) {
|
||||
Token identifier = tokens.consume();
|
||||
|
||||
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT);
|
||||
|
||||
Returnable<?> value = parseExpression(tokens, true, variableMap);
|
||||
Returnable<?> value = parseExpression(tokens, true, scopeBuilder);
|
||||
|
||||
ParserUtil.checkReturnType(value, variableMap.get(identifier.getContent()));
|
||||
String id = identifier.getContent();
|
||||
|
||||
return new VariableAssignmentNode<>(value, identifier.getContent(), identifier.getPosition());
|
||||
ParserUtil.checkReturnType(value, scopeBuilder.getType(id));
|
||||
|
||||
ReturnType type = value.returnType();
|
||||
|
||||
return switch(type) {
|
||||
case NUMBER -> new NumAssignmentNode((Returnable<Number>) value, identifier.getPosition(), scopeBuilder.getIndex(id));
|
||||
case STRING -> new StrAssignmentNode((Returnable<String>) value, identifier.getPosition(), scopeBuilder.getIndex(id));
|
||||
case BOOLEAN -> new BoolAssignmentNode((Returnable<Boolean>) value, identifier.getPosition(), scopeBuilder.getIndex(id));
|
||||
default -> throw new ParseException("Illegal type for variable assignment: " + type, value.getPosition());
|
||||
};
|
||||
}
|
||||
|
||||
private Function<?> parseFunction(Tokenizer tokens, boolean fullStatement, Map<String, Returnable.ReturnType> variableMap) {
|
||||
private Function<?> parseFunction(Tokenizer tokens, boolean fullStatement, ScopeBuilder scopeBuilder) {
|
||||
Token identifier = tokens.consume();
|
||||
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
|
||||
|
||||
@ -397,7 +427,7 @@ public class Parser {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); // Second is body begin
|
||||
|
||||
|
||||
List<Returnable<?>> args = getArgs(tokens, variableMap); // Extract arguments, consume the rest.
|
||||
List<Returnable<?>> args = getArgs(tokens, scopeBuilder); // Extract arguments, consume the rest.
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); // Remove body end
|
||||
|
||||
@ -425,11 +455,11 @@ public class Parser {
|
||||
throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent());
|
||||
}
|
||||
|
||||
private List<Returnable<?>> getArgs(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap) {
|
||||
private List<Returnable<?>> getArgs(Tokenizer tokens, ScopeBuilder scopeBuilder) {
|
||||
List<Returnable<?>> args = new ArrayList<>();
|
||||
|
||||
while(!tokens.get().getType().equals(Token.Type.GROUP_END)) {
|
||||
args.add(parseExpression(tokens, true, variableMap));
|
||||
args.add(parseExpression(tokens, true, scopeBuilder));
|
||||
ParserUtil.checkType(tokens.get(), Token.Type.SEPARATOR, Token.Type.GROUP_END);
|
||||
if(tokens.get().getType().equals(Token.Type.SEPARATOR)) tokens.consume();
|
||||
}
|
||||
|
@ -21,23 +21,8 @@ public class Block implements Item<Block.ReturnInfo<?>> {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public ReturnInfo<?> apply(ImplementationArguments implementationArguments) {
|
||||
return apply(implementationArguments, new Scope());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnInfo<?> apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
Scope sub = scope.sub();
|
||||
for(Item<?> item : items) {
|
||||
Object result = item.apply(implementationArguments, sub);
|
||||
if(result instanceof ReturnInfo<?> level) {
|
||||
if(!level.getLevel().equals(ReturnLevel.NONE)) return level;
|
||||
}
|
||||
}
|
||||
return new ReturnInfo<>(ReturnLevel.NONE, null);
|
||||
}
|
||||
|
||||
public ReturnInfo<?> applyNoNewScope(ImplementationArguments implementationArguments, Scope scope) {
|
||||
for(Item<?> item : items) {
|
||||
Object result = item.apply(implementationArguments, scope);
|
||||
if(result instanceof ReturnInfo<?> level) {
|
||||
@ -52,10 +37,6 @@ public class Block implements Item<Block.ReturnInfo<?>> {
|
||||
return position;
|
||||
}
|
||||
|
||||
public List<Item<?>> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public enum ReturnLevel {
|
||||
NONE(false),
|
||||
BREAK(false),
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang;
|
||||
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder;
|
||||
|
||||
|
||||
public class Executable {
|
||||
private final Block script;
|
||||
private final ThreadLocal<Scope> scope;
|
||||
|
||||
public Executable(Block script, ScopeBuilder scopeBuilder) {
|
||||
this.script = script;
|
||||
this.scope = ThreadLocal.withInitial(scopeBuilder::build);
|
||||
}
|
||||
|
||||
public boolean execute(ImplementationArguments arguments) {
|
||||
return script.apply(arguments, scope.get()).getLevel() != Block.ReturnLevel.FAIL;
|
||||
}
|
||||
}
|
@ -1,46 +1,124 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang;
|
||||
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable.ReturnType;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.VariableReferenceNode;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.Variable;
|
||||
|
||||
|
||||
public class Scope {
|
||||
private static final Scope NULL = new Scope() {
|
||||
@Override
|
||||
public Variable<?> get(String id) {
|
||||
throw new IllegalStateException("Cannot get variable from null scope: " + id);
|
||||
private final double[] num;
|
||||
private final boolean[] bool;
|
||||
private final String[] str;
|
||||
|
||||
private Scope(int numSize, int boolSize, int strSize) {
|
||||
this.num = new double[numSize];
|
||||
this.bool = new boolean[boolSize];
|
||||
this.str = new String[strSize];
|
||||
}
|
||||
|
||||
public double getNum(int index) {
|
||||
return num[index];
|
||||
}
|
||||
|
||||
public boolean getBool(int index) {
|
||||
return bool[index];
|
||||
}
|
||||
|
||||
public String getStr(int index) {
|
||||
return str[index];
|
||||
}
|
||||
|
||||
public void setNum(int index, double value) {
|
||||
num[index] = value;
|
||||
}
|
||||
|
||||
public void setBool(int index, boolean value) {
|
||||
bool[index] = value;
|
||||
}
|
||||
|
||||
public void setStr(int index, String value) {
|
||||
str[index] = value;
|
||||
}
|
||||
|
||||
public static final class ScopeBuilder {
|
||||
private int numSize, boolSize, strSize = 0;
|
||||
private final Map<String, Pair<Integer, ReturnType>> indices;
|
||||
|
||||
private ScopeBuilder parent;
|
||||
|
||||
public ScopeBuilder() {
|
||||
this.indices = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String id, Variable<?> variable) {
|
||||
throw new IllegalStateException("Cannot set variable in null scope: " + id);
|
||||
private ScopeBuilder(ScopeBuilder parent) {
|
||||
this.parent = parent;
|
||||
this.numSize = parent.numSize;
|
||||
this.boolSize = parent.boolSize;
|
||||
this.strSize = parent.strSize;
|
||||
this.indices = new HashMap<>(parent.indices);
|
||||
}
|
||||
|
||||
public Scope build() {
|
||||
return new Scope(numSize, boolSize, strSize);
|
||||
}
|
||||
|
||||
public ScopeBuilder sub() {
|
||||
return new ScopeBuilder(this);
|
||||
}
|
||||
|
||||
private String check(String id) {
|
||||
if(indices.containsKey(id)) {
|
||||
throw new IllegalArgumentException("Variable with ID " + id + " already registered.");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
public int num(String id) {
|
||||
int num = numSize;
|
||||
indices.put(check(id), Pair.of(num, ReturnType.NUMBER));
|
||||
numSize++;
|
||||
if(parent != null) {
|
||||
parent.numSize = FastMath.max(parent.numSize, numSize);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public int str(String id) {
|
||||
int str = strSize;
|
||||
indices.put(check(id), Pair.of(str, ReturnType.STRING));
|
||||
strSize++;
|
||||
if(parent != null) {
|
||||
parent.strSize = FastMath.max(parent.strSize, strSize);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public int bool(String id) {
|
||||
int bool = boolSize;
|
||||
indices.put(check(id), Pair.of(bool, ReturnType.BOOLEAN));
|
||||
boolSize++;
|
||||
if(parent != null) {
|
||||
parent.boolSize = FastMath.max(parent.boolSize, boolSize);
|
||||
}
|
||||
return bool;
|
||||
}
|
||||
|
||||
public int getIndex(String id) {
|
||||
return indices.get(id).getLeft();
|
||||
}
|
||||
|
||||
public ReturnType getType(String id) {
|
||||
return indices.get(id).getRight();
|
||||
}
|
||||
|
||||
|
||||
public boolean contains(String id) {
|
||||
return indices.containsKey(id);
|
||||
}
|
||||
};
|
||||
|
||||
private final Scope parent;
|
||||
private final Map<String, Variable<?>> variableMap = new HashMap<>();
|
||||
|
||||
public Scope(Scope parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public Scope() {
|
||||
this.parent = NULL;
|
||||
}
|
||||
|
||||
public Variable<?> get(String id) {
|
||||
Variable<?> var = variableMap.get(id);
|
||||
return var == null ? parent.get(id) : var;
|
||||
}
|
||||
|
||||
public void put(String id, Variable<?> variable) {
|
||||
variableMap.put(id, variable);
|
||||
}
|
||||
|
||||
|
||||
public Scope sub() {
|
||||
return new Scope(this);
|
||||
}
|
||||
}
|
||||
|
@ -33,11 +33,10 @@ public class ForKeyword implements Keyword<Block.ReturnInfo<?>> {
|
||||
|
||||
@Override
|
||||
public Block.ReturnInfo<?> apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
Scope sub = scope.sub();
|
||||
for(initializer.apply(implementationArguments, sub);
|
||||
statement.apply(implementationArguments, sub);
|
||||
incrementer.apply(implementationArguments, sub)) {
|
||||
Block.ReturnInfo<?> level = conditional.applyNoNewScope(implementationArguments, sub);
|
||||
for(initializer.apply(implementationArguments, scope);
|
||||
statement.apply(implementationArguments, scope);
|
||||
incrementer.apply(implementationArguments, scope)) {
|
||||
Block.ReturnInfo<?> level = conditional.apply(implementationArguments, scope);
|
||||
if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break;
|
||||
if(level.getLevel().isReturnFast()) return level;
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike;
|
||||
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
@ -58,23 +60,4 @@ public class IfKeyword implements Keyword<Block.ReturnInfo<?>> {
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.VOID;
|
||||
}
|
||||
|
||||
|
||||
public static class Pair<L, R> {
|
||||
private final L left;
|
||||
private final R right;
|
||||
|
||||
public Pair(L left, R right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public L getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public R getRight() {
|
||||
return right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Item;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class VariableAssignmentNode<T> implements Item<T> {
|
||||
private final Returnable<T> value;
|
||||
private final Position position;
|
||||
private final String identifier;
|
||||
|
||||
public VariableAssignmentNode(Returnable<T> value, String identifier, Position position) {
|
||||
this.value = value;
|
||||
this.identifier = identifier;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public synchronized T apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
T val = value.apply(implementationArguments, scope);
|
||||
((Variable<T>) scope.get(identifier)).setValue(val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Item;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class VariableDeclarationNode<T> implements Item<T> {
|
||||
private final Position position;
|
||||
private final String identifier;
|
||||
private final Returnable<T> value;
|
||||
private final Returnable.ReturnType type;
|
||||
|
||||
public VariableDeclarationNode(Position position, String identifier, Returnable<T> value, Returnable.ReturnType type) {
|
||||
switch(type) {
|
||||
case STRING:
|
||||
case BOOLEAN:
|
||||
case NUMBER:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid variable type: " + type);
|
||||
}
|
||||
this.position = position;
|
||||
this.identifier = identifier;
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
T result = value.apply(implementationArguments, scope);
|
||||
scope.put(identifier, switch(type) {
|
||||
case NUMBER -> new NumberVariable((Number) result, position);
|
||||
case BOOLEAN -> new BooleanVariable((Boolean) result, position);
|
||||
case STRING -> new StringVariable((String) result, position);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + type);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public Returnable.ReturnType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BoolAssignmentNode extends VariableAssignmentNode<Boolean> {
|
||||
public BoolAssignmentNode(Returnable<Boolean> value, Position position, int index) {
|
||||
super(value, position, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
|
||||
boolean val = value.applyBoolean(implementationArguments, scope);
|
||||
scope.setBool(index, val);
|
||||
return val;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.Variable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class NumAssignmentNode extends VariableAssignmentNode<Number> {
|
||||
public NumAssignmentNode(Returnable<Number> value, Position position, int index) {
|
||||
super(value, position, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
||||
double val = value.applyDouble(implementationArguments, scope);
|
||||
scope.setNum(index, val);
|
||||
return val;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class StrAssignmentNode extends VariableAssignmentNode<String> {
|
||||
public StrAssignmentNode(Returnable<String> value, Position position, int index) {
|
||||
super(value, position, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
String val = value.apply(implementationArguments, scope);
|
||||
scope.setStr(index, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Item;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public abstract class VariableAssignmentNode<T> implements Item<T> {
|
||||
protected final Returnable<T> value;
|
||||
private final Position position;
|
||||
protected final int index;
|
||||
|
||||
|
||||
|
||||
public VariableAssignmentNode(Returnable<T> value, Position position, int index) {
|
||||
this.value = value;
|
||||
this.index = index;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BoolVariableReferenceNode extends VariableReferenceNode<Boolean> {
|
||||
public BoolVariableReferenceNode(Position position, ReturnType type, int index) {
|
||||
super(position, type, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return scope.getBool(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return scope.getBool(index);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class NumVariableReferenceNode extends VariableReferenceNode<Number> {
|
||||
public NumVariableReferenceNode(Position position, ReturnType type, int index) {
|
||||
super(position, type, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return scope.getNum(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return scope.getNum(index);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class StrVariableReferenceNode extends VariableReferenceNode<String> {
|
||||
public StrVariableReferenceNode(Position position, ReturnType type, int index) {
|
||||
super(position, type, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return scope.getStr(index);
|
||||
}
|
||||
}
|
@ -5,23 +5,21 @@
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables;
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class VariableReferenceNode implements Returnable<Object> {
|
||||
private final String identifier;
|
||||
public abstract class VariableReferenceNode<T> implements Returnable<T> {
|
||||
private final Position position;
|
||||
private final ReturnType type;
|
||||
protected final int index;
|
||||
|
||||
public VariableReferenceNode(String identifier, Position position, ReturnType type) {
|
||||
this.identifier = identifier;
|
||||
public VariableReferenceNode(Position position, ReturnType type, int index) {
|
||||
this.position = position;
|
||||
this.type = type;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -29,11 +27,6 @@ public class VariableReferenceNode implements Returnable<Object> {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Object apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return scope.get(identifier).getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
@ -7,6 +7,8 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.script;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Executable;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
@ -51,7 +53,7 @@ import com.dfsek.terra.api.world.WritableWorld;
|
||||
|
||||
public class StructureScript implements Structure, Keyed<StructureScript> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(StructureScript.class);
|
||||
private final Block block;
|
||||
private final Executable block;
|
||||
private final RegistryKey id;
|
||||
|
||||
private final String profile;
|
||||
@ -146,7 +148,7 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
|
||||
|
||||
private boolean applyBlock(TerraImplementationArguments arguments) {
|
||||
try {
|
||||
return block.apply(arguments).getLevel() != Block.ReturnLevel.FAIL;
|
||||
return block.execute(arguments);
|
||||
} catch(RuntimeException e) {
|
||||
LOGGER.error("Failed to generate structure at {}", arguments.getOrigin(), e);
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user