mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-06-18 06:40:55 +00:00
Add basic user defined function support
This commit is contained in:
+122
-45
@@ -21,8 +21,8 @@ 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.ConstantExpression;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.NumericConstant;
|
import com.dfsek.terra.addons.terrascript.parser.lang.constants.NumericConstant;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.StringConstant;
|
import com.dfsek.terra.addons.terrascript.parser.lang.constants.StringConstant;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.functions.UserDefinedFunctionBuilder;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.BreakKeyword;
|
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.BreakKeyword;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.ContinueKeyword;
|
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.ContinueKeyword;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.FailKeyword;
|
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.FailKeyword;
|
||||||
@@ -77,17 +77,17 @@ public class Parser {
|
|||||||
* @throws ParseException If parsing fails.
|
* @throws ParseException If parsing fails.
|
||||||
*/
|
*/
|
||||||
public Executable parse(ScopeBuilder scopeBuilder) {
|
public Executable parse(ScopeBuilder scopeBuilder) {
|
||||||
return new Executable(parseBlock(new Tokenizer(source), scopeBuilder), scopeBuilder);
|
return new Executable(parseBlock(new Tokenizer(source), scopeBuilder, ReturnType.VOID), scopeBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WhileKeyword parseWhileLoop(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
private WhileKeyword parseWhileLoop(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
||||||
SourcePosition start = tokenizer.consume().getPosition();
|
SourcePosition start = tokenizer.consume().getPosition();
|
||||||
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_BEGIN);
|
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_BEGIN);
|
||||||
scopeBuilder = scopeBuilder.subInLoop();
|
scopeBuilder = scopeBuilder.innerLoopScope();
|
||||||
Expression<?> condition = parseExpression(tokenizer, true, scopeBuilder);
|
Expression<?> condition = parseExpression(tokenizer, true, scopeBuilder);
|
||||||
ParserUtil.ensureReturnType(condition, Expression.ReturnType.BOOLEAN);
|
ParserUtil.ensureReturnType(condition, Expression.ReturnType.BOOLEAN);
|
||||||
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
|
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
|
||||||
return new WhileKeyword(parseStatementBlock(tokenizer, scopeBuilder), (Expression<Boolean>) condition, start); // While loop
|
return new WhileKeyword(parseStatementBlock(tokenizer, scopeBuilder, ReturnType.VOID), (Expression<Boolean>) condition, start); // While loop
|
||||||
}
|
}
|
||||||
|
|
||||||
private IfKeyword parseIfStatement(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
private IfKeyword parseIfStatement(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
||||||
@@ -99,7 +99,7 @@ public class Parser {
|
|||||||
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
|
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
|
||||||
|
|
||||||
Block elseBlock = null;
|
Block elseBlock = null;
|
||||||
Block statement = parseStatementBlock(tokenizer, scopeBuilder);
|
Block statement = parseStatementBlock(tokenizer, scopeBuilder, ReturnType.VOID);
|
||||||
|
|
||||||
List<Pair<Expression<Boolean>, Block>> elseIf = new ArrayList<>();
|
List<Pair<Expression<Boolean>, Block>> elseIf = new ArrayList<>();
|
||||||
|
|
||||||
@@ -109,9 +109,9 @@ public class Parser {
|
|||||||
tokenizer.consume(); // Consume if.
|
tokenizer.consume(); // Consume if.
|
||||||
Expression<?> elseCondition = parseExpression(tokenizer, true, scopeBuilder);
|
Expression<?> elseCondition = parseExpression(tokenizer, true, scopeBuilder);
|
||||||
ParserUtil.ensureReturnType(elseCondition, Expression.ReturnType.BOOLEAN);
|
ParserUtil.ensureReturnType(elseCondition, Expression.ReturnType.BOOLEAN);
|
||||||
elseIf.add(Pair.of((Expression<Boolean>) elseCondition, parseStatementBlock(tokenizer, scopeBuilder)));
|
elseIf.add(Pair.of((Expression<Boolean>) elseCondition, parseStatementBlock(tokenizer, scopeBuilder, ReturnType.VOID)));
|
||||||
} else {
|
} else {
|
||||||
elseBlock = parseStatementBlock(tokenizer, scopeBuilder);
|
elseBlock = parseStatementBlock(tokenizer, scopeBuilder, ReturnType.VOID);
|
||||||
break; // Else must be last.
|
break; // Else must be last.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,29 +119,29 @@ public class Parser {
|
|||||||
return new IfKeyword(statement, (Expression<Boolean>) condition, elseIf, elseBlock, start); // If statement
|
return new IfKeyword(statement, (Expression<Boolean>) condition, elseIf, elseBlock, start); // If statement
|
||||||
}
|
}
|
||||||
|
|
||||||
private Block parseStatementBlock(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
private Block parseStatementBlock(Tokenizer tokenizer, ScopeBuilder scopeBuilder, ReturnType blockReturnType) {
|
||||||
if(tokenizer.current().isType(Token.Type.BLOCK_BEGIN)) {
|
if(tokenizer.current().isType(Token.Type.BLOCK_BEGIN)) {
|
||||||
ParserUtil.ensureType(tokenizer.consume(), Token.Type.BLOCK_BEGIN);
|
ParserUtil.ensureType(tokenizer.consume(), Token.Type.BLOCK_BEGIN);
|
||||||
Block block = parseBlock(tokenizer, scopeBuilder);
|
Block block = parseBlock(tokenizer, scopeBuilder, blockReturnType);
|
||||||
ParserUtil.ensureType(tokenizer.consume(), Token.Type.BLOCK_END);
|
ParserUtil.ensureType(tokenizer.consume(), Token.Type.BLOCK_END);
|
||||||
return block;
|
return block;
|
||||||
} else {
|
} else {
|
||||||
SourcePosition position = tokenizer.current().getPosition();
|
SourcePosition position = tokenizer.current().getPosition();
|
||||||
return new Block(Collections.singletonList(parseStatement(tokenizer, scopeBuilder)), position);
|
return new Block(Collections.singletonList(parseStatement(tokenizer, scopeBuilder)), position, blockReturnType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ForKeyword parseForLoop(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
private ForKeyword parseForLoop(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
||||||
SourcePosition start = tokenizer.consume().getPosition();
|
SourcePosition start = tokenizer.consume().getPosition();
|
||||||
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_BEGIN);
|
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_BEGIN);
|
||||||
scopeBuilder = scopeBuilder.subInLoop(); // new scope
|
scopeBuilder = scopeBuilder.innerLoopScope(); // new scope
|
||||||
Token f = tokenizer.current();
|
Token f = tokenizer.current();
|
||||||
ParserUtil.ensureType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER);
|
ParserUtil.ensureType(f, Token.Type.TYPE_NUMBER, Token.Type.TYPE_STRING, Token.Type.TYPE_BOOLEAN, Token.Type.IDENTIFIER);
|
||||||
Expression<?> initializer;
|
Expression<?> initializer;
|
||||||
if(f.isVariableDeclaration()) {
|
if(f.isVariableDeclaration()) {
|
||||||
VariableAssignmentNode<?> forVar = parseVariableDeclaration(tokenizer, scopeBuilder);
|
Expression<?> forVar = parseDeclaration(tokenizer, scopeBuilder);
|
||||||
Token name = tokenizer.current();
|
Token name = tokenizer.current();
|
||||||
if(scopeBuilder.containsKey(name.getContent()) || scopeBuilder.contains(name.getContent()))
|
if(scopeBuilder.containsFunction(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);
|
||||||
@@ -158,7 +158,7 @@ public class Parser {
|
|||||||
|
|
||||||
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
|
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
|
||||||
|
|
||||||
return new ForKeyword(parseStatementBlock(tokenizer, scopeBuilder), initializer, (Expression<Boolean>) conditional, incrementer,
|
return new ForKeyword(parseStatementBlock(tokenizer, scopeBuilder, ReturnType.VOID), initializer, (Expression<Boolean>) conditional, incrementer,
|
||||||
start);
|
start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,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(scopeBuilder.containsKey(id.getContent()))
|
if(scopeBuilder.containsFunction(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);
|
||||||
@@ -196,7 +196,7 @@ public class Parser {
|
|||||||
default -> throw new ParseException("Illegal type for variable reference: " + varType, id.getPosition());
|
default -> throw new ParseException("Illegal type for variable reference: " + varType, id.getPosition());
|
||||||
};
|
};
|
||||||
|
|
||||||
} else throw new ParseException("Unexpected token \" " + id.getContent() + "\"", id.getPosition());
|
} else throw new ParseException("Unexpected token \"" + id.getContent() + "\"", id.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(booleanInverted) { // Invert operation if boolean not detected
|
if(booleanInverted) { // Invert operation if boolean not detected
|
||||||
@@ -292,48 +292,115 @@ public class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private VariableAssignmentNode<?> parseVariableDeclaration(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
private Expression<?> parseDeclaration(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
||||||
Token type = tokenizer.consume();
|
Token type = tokenizer.consume();
|
||||||
ParserUtil.ensureType(type, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
|
|
||||||
|
|
||||||
Expression.ReturnType returnType = ParserUtil.getVariableReturnType(type);
|
|
||||||
|
|
||||||
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(scopeBuilder.containsKey(identifier.getContent()) || scopeBuilder.contains(identifier.getContent()))
|
|
||||||
|
Token declarationType = tokenizer.consume();
|
||||||
|
ParserUtil.ensureType(declarationType, Token.Type.ASSIGNMENT, Token.Type.GROUP_BEGIN);
|
||||||
|
|
||||||
|
return switch(declarationType.getType()) {
|
||||||
|
case ASSIGNMENT -> parseVariableDeclaration(tokenizer, scopeBuilder, type, identifier);
|
||||||
|
case GROUP_BEGIN -> parseFunctionDeclaration(tokenizer, scopeBuilder, type, identifier);
|
||||||
|
default -> throw new ParseException("Illegal type for declaration: " + type, declarationType.getPosition());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Expression<?> parseVariableDeclaration(Tokenizer tokenizer, ScopeBuilder scopeBuilder, Token type, Token identifier) {
|
||||||
|
ParserUtil.ensureType(type, Token.Type.TYPE_STRING, Token.Type.TYPE_BOOLEAN, Token.Type.TYPE_NUMBER);
|
||||||
|
|
||||||
|
if(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);
|
|
||||||
|
|
||||||
Expression<?> value = parseExpression(tokenizer, true, scopeBuilder);
|
Expression<?> value = parseExpression(tokenizer, true, scopeBuilder);
|
||||||
ParserUtil.ensureReturnType(value, returnType);
|
ParserUtil.ensureReturnType(value, ParserUtil.getVariableReturnType(type));
|
||||||
|
|
||||||
String id = identifier.getContent();
|
|
||||||
|
|
||||||
|
String variableName = identifier.getContent();
|
||||||
return switch(value.returnType()) {
|
return switch(value.returnType()) {
|
||||||
case NUMBER -> new NumAssignmentNode((Expression<Number>) value, identifier.getPosition(), scopeBuilder.num(id));
|
case NUMBER -> new NumAssignmentNode((Expression<Number>) value, identifier.getPosition(), scopeBuilder.declareNum(variableName));
|
||||||
case STRING -> new StrAssignmentNode((Expression<String>) value, identifier.getPosition(), scopeBuilder.str(id));
|
case STRING -> new StrAssignmentNode((Expression<String>) value, identifier.getPosition(), scopeBuilder.declareStr(variableName));
|
||||||
case BOOLEAN -> new BoolAssignmentNode((Expression<Boolean>) value, identifier.getPosition(), scopeBuilder.bool(id));
|
case BOOLEAN -> new BoolAssignmentNode((Expression<Boolean>) value, identifier.getPosition(), scopeBuilder.declareBool(variableName));
|
||||||
default -> throw new ParseException("Illegal type for variable declaration: " + type, value.getPosition());
|
default -> throw new ParseException("Illegal type for variable declaration: " + type, value.getPosition());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Block parseBlock(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
private Expression<?> parseFunctionDeclaration(Tokenizer tokenizer, ScopeBuilder scopeBuilder, Token type, Token identifier) {
|
||||||
|
ParserUtil.ensureType(type, Token.Type.TYPE_STRING, Token.Type.TYPE_BOOLEAN, Token.Type.TYPE_NUMBER, Token.Type.TYPE_VOID);
|
||||||
|
|
||||||
|
if(scopeBuilder.contains(identifier.getContent()))
|
||||||
|
throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition());
|
||||||
|
|
||||||
|
ReturnType returnType = ParserUtil.getVariableReturnType(type);
|
||||||
|
|
||||||
|
ScopeBuilder functionBodyScope = scopeBuilder.functionScope();
|
||||||
|
|
||||||
|
// Declare argument names into function body scope
|
||||||
|
List<Pair<Integer, ReturnType>> argumentInfo = getFunctionArgumentsDeclaration(tokenizer).stream().map(arg -> Pair.of(switch(arg.getRight()) {
|
||||||
|
case NUMBER -> functionBodyScope.declareNum(arg.getLeft());
|
||||||
|
case BOOLEAN -> functionBodyScope.declareBool(arg.getLeft());
|
||||||
|
case STRING -> functionBodyScope.declareStr(arg.getLeft());
|
||||||
|
default -> throw new IllegalArgumentException("Unsupported argument type: " + arg.getRight());
|
||||||
|
}, arg.getRight())).toList();
|
||||||
|
|
||||||
|
Block body = parseStatementBlock(tokenizer, functionBodyScope, returnType);
|
||||||
|
|
||||||
|
FunctionBuilder<?> functionBuilder = new UserDefinedFunctionBuilder<>(returnType, argumentInfo, body, functionBodyScope);
|
||||||
|
|
||||||
|
scopeBuilder.registerFunction(identifier.getContent(), functionBuilder);
|
||||||
|
return Expression.NOOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Pair<String, ReturnType>> getFunctionArgumentsDeclaration(Tokenizer tokenizer) {
|
||||||
|
List<Pair<String, ReturnType>> arguments = new ArrayList<>();
|
||||||
|
while (tokenizer.current().getType() != Token.Type.GROUP_END) {
|
||||||
|
// Parse argument type
|
||||||
|
Token typeToken = tokenizer.consume();
|
||||||
|
ParserUtil.ensureType(typeToken, Token.Type.TYPE_BOOLEAN, Token.Type.TYPE_STRING, Token.Type.TYPE_NUMBER);
|
||||||
|
ReturnType argType = ParserUtil.getVariableReturnType(typeToken);
|
||||||
|
|
||||||
|
// Parse argument name
|
||||||
|
Token identifierToken = tokenizer.consume();
|
||||||
|
ParserUtil.ensureType(identifierToken, Token.Type.IDENTIFIER);
|
||||||
|
String argName = identifierToken.getContent();
|
||||||
|
|
||||||
|
arguments.add(Pair.of(argName, argType));
|
||||||
|
|
||||||
|
// Consume separator if present, trailing separators are allowed
|
||||||
|
if (tokenizer.current().isType(Token.Type.SEPARATOR)) tokenizer.consume();
|
||||||
|
}
|
||||||
|
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Block parseBlock(Tokenizer tokenizer, ScopeBuilder scopeBuilder, ReturnType blockReturnType) {
|
||||||
List<Expression<?>> expressions = new ArrayList<>();
|
List<Expression<?>> expressions = new ArrayList<>();
|
||||||
scopeBuilder = scopeBuilder.sub();
|
scopeBuilder = scopeBuilder.innerScope();
|
||||||
SourcePosition startPosition = tokenizer.current().getPosition();
|
SourcePosition startPosition = tokenizer.current().getPosition();
|
||||||
|
|
||||||
|
boolean hasReturn = false;
|
||||||
|
|
||||||
// Parse each statement
|
// Parse each statement
|
||||||
while(tokenizer.hasNext()) {
|
while(tokenizer.hasNext()) {
|
||||||
Token token = tokenizer.current();
|
Token token = tokenizer.current();
|
||||||
if(token.isType(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
|
if(token.isType(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
|
||||||
Expression<?> expression = parseStatement(tokenizer, scopeBuilder);
|
Expression<?> expression = parseStatement(tokenizer, scopeBuilder);
|
||||||
if(expression != Function.NULL) {
|
if(expression != Expression.NOOP) {
|
||||||
expressions.add(expression);
|
expressions.add(expression);
|
||||||
}
|
}
|
||||||
|
if(expression instanceof ReturnKeyword returnKeyword) {
|
||||||
|
hasReturn = true;
|
||||||
|
if (returnKeyword.dataReturnType() != blockReturnType)
|
||||||
|
throw new ParseException("Invalid return type, expected " + blockReturnType + ", found " + returnKeyword.dataReturnType(), expression.getPosition());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Block(expressions, startPosition);
|
if (blockReturnType != ReturnType.VOID && !hasReturn)
|
||||||
|
throw new ParseException("Block does not contain a return statement, must return type " + blockReturnType, startPosition);
|
||||||
|
|
||||||
|
return new Block(expressions, startPosition, blockReturnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Expression<?> parseStatement(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
private Expression<?> parseStatement(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
||||||
@@ -341,10 +408,10 @@ public class Parser {
|
|||||||
|
|
||||||
// Include BREAK and CONTINUE as valid token types if scope is within a loop
|
// Include BREAK and CONTINUE as valid token types if scope is within a loop
|
||||||
if(scopeBuilder.isInLoop()) ParserUtil.ensureType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
|
if(scopeBuilder.isInLoop()) ParserUtil.ensureType(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,
|
Token.Type.TYPE_NUMBER, Token.Type.TYPE_STRING, Token.Type.TYPE_BOOLEAN, Token.Type.TYPE_VOID,
|
||||||
Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL);
|
Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL);
|
||||||
else ParserUtil.ensureType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
|
else ParserUtil.ensureType(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, Token.Type.RETURN,
|
Token.Type.TYPE_NUMBER, Token.Type.TYPE_STRING, Token.Type.TYPE_BOOLEAN, Token.Type.TYPE_VOID, Token.Type.RETURN,
|
||||||
Token.Type.FAIL);
|
Token.Type.FAIL);
|
||||||
|
|
||||||
Expression<?> expression = switch(token.getType()) {
|
Expression<?> expression = switch(token.getType()) {
|
||||||
@@ -355,17 +422,27 @@ public class Parser {
|
|||||||
if(scopeBuilder.contains(token.getContent())) yield parseAssignment(tokenizer, scopeBuilder); // Assume variable assignment
|
if(scopeBuilder.contains(token.getContent())) yield parseAssignment(tokenizer, scopeBuilder); // Assume variable assignment
|
||||||
else yield parseFunctionInvocation(tokenizer, true, scopeBuilder);
|
else yield parseFunctionInvocation(tokenizer, true, scopeBuilder);
|
||||||
}
|
}
|
||||||
case NUMBER_VARIABLE, STRING_VARIABLE, BOOLEAN_VARIABLE -> parseVariableDeclaration(tokenizer, scopeBuilder);
|
case TYPE_NUMBER, TYPE_STRING, TYPE_BOOLEAN, TYPE_VOID -> parseDeclaration(tokenizer, scopeBuilder);
|
||||||
case RETURN -> new ReturnKeyword(tokenizer.consume().getPosition());
|
case RETURN -> parseReturn(tokenizer, scopeBuilder);
|
||||||
case BREAK -> new BreakKeyword(tokenizer.consume().getPosition());
|
case BREAK -> new BreakKeyword(tokenizer.consume().getPosition());
|
||||||
case CONTINUE -> new ContinueKeyword(tokenizer.consume().getPosition());
|
case CONTINUE -> new ContinueKeyword(tokenizer.consume().getPosition());
|
||||||
case FAIL -> new FailKeyword(tokenizer.consume().getPosition());
|
case FAIL -> new FailKeyword(tokenizer.consume().getPosition());
|
||||||
default -> throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
|
default -> throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
|
||||||
};
|
};
|
||||||
if(!token.isControlStructure()) ParserUtil.ensureType(tokenizer.consume(), Token.Type.STATEMENT_END);
|
if(!token.isControlStructure() && expression != Expression.NOOP) ParserUtil.ensureType(tokenizer.consume(), Token.Type.STATEMENT_END);
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReturnKeyword parseReturn(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
||||||
|
Token returnToken = tokenizer.consume();
|
||||||
|
ParserUtil.ensureType(returnToken, Token.Type.RETURN);
|
||||||
|
Expression<?> data = null;
|
||||||
|
if (!tokenizer.current().isType(Token.Type.STATEMENT_END)) {
|
||||||
|
data = parseExpression(tokenizer, true, scopeBuilder);
|
||||||
|
}
|
||||||
|
return new ReturnKeyword(data, returnToken.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
private VariableAssignmentNode<?> parseAssignment(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
private VariableAssignmentNode<?> parseAssignment(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
|
||||||
Token identifier = tokenizer.consume();
|
Token identifier = tokenizer.consume();
|
||||||
|
|
||||||
@@ -389,12 +466,12 @@ public class Parser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Function<?> parseFunctionInvocation(Tokenizer tokenizer, boolean fullStatement, ScopeBuilder scopeBuilder) {
|
private Expression<?> parseFunctionInvocation(Tokenizer tokenizer, boolean fullStatement, ScopeBuilder scopeBuilder) {
|
||||||
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(!scopeBuilder.containsKey(identifier.getContent()))
|
if(!scopeBuilder.containsFunction(identifier.getContent()))
|
||||||
throw new ParseException("No such function \"" + identifier.getContent() + "\"", identifier.getPosition());
|
throw new ParseException("Function \"" + identifier.getContent() + "\" is not defined in this scope", 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
|
||||||
|
|
||||||
@@ -405,11 +482,11 @@ public class Parser {
|
|||||||
if(fullStatement) ParserUtil.ensureType(tokenizer.current(), Token.Type.STATEMENT_END);
|
if(fullStatement) ParserUtil.ensureType(tokenizer.current(), Token.Type.STATEMENT_END);
|
||||||
|
|
||||||
if(ignoredFunctions.contains(identifier.getContent())) {
|
if(ignoredFunctions.contains(identifier.getContent())) {
|
||||||
return Function.NULL;
|
return Expression.NOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(scopeBuilder.containsKey(identifier.getContent())) {
|
if(scopeBuilder.containsFunction(identifier.getContent())) {
|
||||||
FunctionBuilder<?> builder = scopeBuilder.get(identifier.getContent());
|
FunctionBuilder<?> builder = scopeBuilder.getFunction(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());
|
||||||
|
|||||||
+7
-6
@@ -78,9 +78,9 @@ public class ParserUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void checkVarType(Token token, Expression.ReturnType returnType) {
|
public static void checkVarType(Token token, Expression.ReturnType returnType) {
|
||||||
if(returnType.equals(Expression.ReturnType.STRING) && token.getType().equals(Token.Type.STRING_VARIABLE)) return;
|
if(returnType.equals(Expression.ReturnType.STRING) && token.getType().equals(Token.Type.TYPE_STRING)) return;
|
||||||
if(returnType.equals(Expression.ReturnType.NUMBER) && token.getType().equals(Token.Type.NUMBER_VARIABLE)) return;
|
if(returnType.equals(Expression.ReturnType.NUMBER) && token.getType().equals(Token.Type.TYPE_NUMBER)) return;
|
||||||
if(returnType.equals(Expression.ReturnType.BOOLEAN) && token.getType().equals(Token.Type.BOOLEAN_VARIABLE)) return;
|
if(returnType.equals(Expression.ReturnType.BOOLEAN) && token.getType().equals(Token.Type.TYPE_BOOLEAN)) return;
|
||||||
throw new ParseException("Type mismatch, cannot convert from " + returnType + " to " + token.getType(), token.getPosition());
|
throw new ParseException("Type mismatch, cannot convert from " + returnType + " to " + token.getType(), token.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,9 +98,10 @@ public class ParserUtil {
|
|||||||
|
|
||||||
public static Expression.ReturnType getVariableReturnType(Token varToken) {
|
public static Expression.ReturnType getVariableReturnType(Token varToken) {
|
||||||
return switch(varToken.getType()) {
|
return switch(varToken.getType()) {
|
||||||
case NUMBER_VARIABLE -> Expression.ReturnType.NUMBER;
|
case TYPE_NUMBER -> Expression.ReturnType.NUMBER;
|
||||||
case STRING_VARIABLE -> Expression.ReturnType.STRING;
|
case TYPE_STRING -> Expression.ReturnType.STRING;
|
||||||
case BOOLEAN_VARIABLE -> Expression.ReturnType.BOOLEAN;
|
case TYPE_BOOLEAN -> Expression.ReturnType.BOOLEAN;
|
||||||
|
case TYPE_VOID -> Expression.ReturnType.VOID;
|
||||||
default -> throw new ParseException("Unexpected token " + varToken.getType() + "; expected variable declaration",
|
default -> throw new ParseException("Unexpected token " + varToken.getType() + "; expected variable declaration",
|
||||||
varToken.getPosition());
|
varToken.getPosition());
|
||||||
};
|
};
|
||||||
|
|||||||
+14
-26
@@ -9,33 +9,36 @@ package com.dfsek.terra.addons.terrascript.parser.lang;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.ReturnInfo;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||||
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
||||||
|
|
||||||
|
|
||||||
public class Block implements Expression<ReturnInfo<?>> {
|
public class Block implements Expression<EvaluationInfo<?>> {
|
||||||
private final List<Expression<?>> items;
|
private final List<Expression<?>> items;
|
||||||
private final SourcePosition position;
|
private final SourcePosition position;
|
||||||
|
private final ReturnType returnType;
|
||||||
|
|
||||||
public Block(List<Expression<?>> items, SourcePosition position) {
|
public Block(List<Expression<?>> items, SourcePosition position, ReturnType returnType) {
|
||||||
this.items = items;
|
this.items = items;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
|
this.returnType = returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReturnType returnType() {
|
public ReturnType returnType() {
|
||||||
return ReturnType.VOID;
|
return returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
for(Expression<?> item : items) {
|
for(Expression<?> item : items) {
|
||||||
Object result = item.evaluate(implementationArguments, scope);
|
Object result = item.evaluate(implementationArguments, scope);
|
||||||
if(result instanceof ReturnInfo<?> level) {
|
if(result instanceof EvaluationInfo<?> evalInfo) {
|
||||||
if(!level.getLevel().equals(ReturnLevel.NONE)) return level;
|
if(!evalInfo.level().equals(EvaluationLevel.NONE)) return evalInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ReturnInfo<>(ReturnLevel.NONE, null);
|
return new EvaluationInfo<>(EvaluationLevel.NONE, Expression.NOOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -43,7 +46,7 @@ public class Block implements Expression<ReturnInfo<?>> {
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ReturnLevel {
|
public enum EvaluationLevel {
|
||||||
NONE(false),
|
NONE(false),
|
||||||
BREAK(false),
|
BREAK(false),
|
||||||
CONTINUE(false),
|
CONTINUE(false),
|
||||||
@@ -52,7 +55,7 @@ public class Block implements Expression<ReturnInfo<?>> {
|
|||||||
|
|
||||||
private final boolean returnFast;
|
private final boolean returnFast;
|
||||||
|
|
||||||
ReturnLevel(boolean returnFast) {
|
EvaluationLevel(boolean returnFast) {
|
||||||
this.returnFast = returnFast;
|
this.returnFast = returnFast;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,21 +65,6 @@ public class Block implements Expression<ReturnInfo<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class ReturnInfo<T> {
|
public record EvaluationInfo<T extends Expression<?>>(EvaluationLevel level, T data) {
|
||||||
private final ReturnLevel level;
|
|
||||||
private final T data;
|
|
||||||
|
|
||||||
public ReturnInfo(ReturnLevel level, T data) {
|
|
||||||
this.level = level;
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReturnLevel getLevel() {
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getData() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -14,6 +14,6 @@ public class Executable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean execute(ImplementationArguments arguments) {
|
public boolean execute(ImplementationArguments arguments) {
|
||||||
return script.evaluate(arguments, scope.get()).getLevel() != Block.ReturnLevel.FAIL;
|
return script.evaluate(arguments, scope.get()).level() != Block.EvaluationLevel.FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
@@ -25,6 +25,23 @@ public interface Expression<T> {
|
|||||||
|
|
||||||
SourcePosition getPosition();
|
SourcePosition getPosition();
|
||||||
|
|
||||||
|
Expression<Void> NOOP = new Expression<>() {
|
||||||
|
@Override
|
||||||
|
public ReturnType returnType() {
|
||||||
|
return ReturnType.VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourcePosition getPosition() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
enum ReturnType {
|
enum ReturnType {
|
||||||
NUMBER(true),
|
NUMBER(true),
|
||||||
STRING(true),
|
STRING(true),
|
||||||
|
|||||||
+14
-8
@@ -1,7 +1,6 @@
|
|||||||
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.Function;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||||
|
|
||||||
@@ -73,26 +72,33 @@ public class Scope {
|
|||||||
this.inLoop = inLoop;
|
this.inLoop = inLoop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ScopeBuilder(Map<String, FunctionBuilder<? extends Function<?>>> functions) {
|
||||||
|
this.functions = new HashMap<>(functions);
|
||||||
|
this.indices = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
public Scope build() {
|
public Scope build() {
|
||||||
return new Scope(numSize, boolSize, strSize);
|
return new Scope(numSize, boolSize, strSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScopeBuilder sub() {
|
public ScopeBuilder innerScope() {
|
||||||
return new ScopeBuilder(this, inLoop);
|
return new ScopeBuilder(this, inLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScopeBuilder subInLoop() { return new ScopeBuilder(this, true); }
|
public ScopeBuilder innerLoopScope() { return new ScopeBuilder(this, true); }
|
||||||
|
|
||||||
|
public ScopeBuilder functionScope() { return new ScopeBuilder(functions); }
|
||||||
|
|
||||||
public ScopeBuilder registerFunction(String name, FunctionBuilder<? extends Function<?>> functionBuilder) {
|
public ScopeBuilder registerFunction(String name, FunctionBuilder<? extends Function<?>> functionBuilder) {
|
||||||
functions.put(name, functionBuilder);
|
functions.put(name, functionBuilder);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsKey(String functionName) {
|
public boolean containsFunction(String functionName) {
|
||||||
return functions.containsKey(functionName);
|
return functions.containsKey(functionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FunctionBuilder<?> get(String functionName) {
|
public FunctionBuilder<?> getFunction(String functionName) {
|
||||||
return functions.get(functionName);
|
return functions.get(functionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +113,7 @@ public class Scope {
|
|||||||
return inLoop;
|
return inLoop;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int num(String id) {
|
public int declareNum(String id) {
|
||||||
int num = numSize;
|
int num = numSize;
|
||||||
indices.put(check(id), Pair.of(num, ReturnType.NUMBER));
|
indices.put(check(id), Pair.of(num, ReturnType.NUMBER));
|
||||||
numSize++;
|
numSize++;
|
||||||
@@ -115,7 +121,7 @@ public class Scope {
|
|||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int str(String id) {
|
public int declareStr(String id) {
|
||||||
int str = strSize;
|
int str = strSize;
|
||||||
indices.put(check(id), Pair.of(str, ReturnType.STRING));
|
indices.put(check(id), Pair.of(str, ReturnType.STRING));
|
||||||
strSize++;
|
strSize++;
|
||||||
@@ -123,7 +129,7 @@ public class Scope {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int bool(String id) {
|
public int declareBool(String id) {
|
||||||
int bool = boolSize;
|
int bool = boolSize;
|
||||||
indices.put(check(id), Pair.of(bool, ReturnType.BOOLEAN));
|
indices.put(check(id), Pair.of(bool, ReturnType.BOOLEAN));
|
||||||
boolSize++;
|
boolSize++;
|
||||||
|
|||||||
-18
@@ -10,26 +10,8 @@ package com.dfsek.terra.addons.terrascript.parser.lang.functions;
|
|||||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||||
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
|
||||||
|
|
||||||
|
|
||||||
public interface Function<T> extends Expression<T> {
|
public interface Function<T> extends Expression<T> {
|
||||||
Function<?> NULL = new Function<>() {
|
|
||||||
@Override
|
|
||||||
public ReturnType returnType() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SourcePosition getPosition() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
|
|||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package com.dfsek.terra.addons.terrascript.parser.lang.functions;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Expression.ReturnType;
|
||||||
|
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||||
|
|
||||||
|
|
||||||
|
public record FunctionSignature(ReturnType returnType, Pair<String, ReturnType>[] arguments) {
|
||||||
|
}
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
package com.dfsek.terra.addons.terrascript.parser.lang.functions;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Expression.ReturnType;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder;
|
||||||
|
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
||||||
|
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public class UserDefinedFunctionBuilder<T extends Function<?>> implements FunctionBuilder<T> {
|
||||||
|
|
||||||
|
private final ReturnType returnType;
|
||||||
|
private final List<Pair<Integer, ReturnType>> argumentInfo;
|
||||||
|
private final ScopeBuilder bodyScopeBuilder;
|
||||||
|
private final Block body;
|
||||||
|
|
||||||
|
public UserDefinedFunctionBuilder(ReturnType returnType, List<Pair<Integer, ReturnType>> argumentInfo, Block body, ScopeBuilder functionBodyScope) {
|
||||||
|
this.returnType = returnType;
|
||||||
|
this.bodyScopeBuilder = functionBodyScope;
|
||||||
|
this.body = body;
|
||||||
|
this.argumentInfo = argumentInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return (T) new Function() {
|
||||||
|
|
||||||
|
private final ThreadLocal<Scope> threadLocalScope = ThreadLocal.withInitial(bodyScopeBuilder::build);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReturnType returnType() {
|
||||||
|
return returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
|
Scope bodyScope = threadLocalScope.get();
|
||||||
|
// Pass arguments into scope of function body
|
||||||
|
for (int i = 0; i < argumentList.size(); i++) {
|
||||||
|
Pair<Integer, ReturnType> argInfo = argumentInfo.get(i);
|
||||||
|
Expression<?> argExpression = argumentList.get(i);
|
||||||
|
switch(argInfo.getRight()) {
|
||||||
|
case NUMBER -> bodyScope.setNum(argInfo.getLeft(), argExpression.applyDouble(implementationArguments, scope));
|
||||||
|
case BOOLEAN -> bodyScope.setBool(argInfo.getLeft(), argExpression.applyBoolean(implementationArguments, scope));
|
||||||
|
case STRING -> bodyScope.setStr(argInfo.getLeft(), (String) argExpression.evaluate(implementationArguments, scope));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return body.evaluate(implementationArguments, bodyScope).data().evaluate(implementationArguments, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourcePosition getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int argNumber() {
|
||||||
|
return argumentInfo.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReturnType getArgument(int position) {
|
||||||
|
return argumentInfo.get(position).getRight();
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-4
@@ -7,14 +7,15 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
||||||
|
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||||
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
||||||
|
|
||||||
|
|
||||||
public class BreakKeyword implements Keyword<Block.ReturnInfo<?>> {
|
public class BreakKeyword implements Keyword<EvaluationInfo<?>> {
|
||||||
private final SourcePosition position;
|
private final SourcePosition position;
|
||||||
|
|
||||||
public BreakKeyword(SourcePosition position) {
|
public BreakKeyword(SourcePosition position) {
|
||||||
@@ -22,8 +23,8 @@ public class BreakKeyword implements Keyword<Block.ReturnInfo<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
return new Block.ReturnInfo<>(Block.ReturnLevel.BREAK, null);
|
return new EvaluationInfo<>(EvaluationLevel.BREAK, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+5
-4
@@ -7,14 +7,15 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
||||||
|
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||||
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
||||||
|
|
||||||
|
|
||||||
public class ContinueKeyword implements Keyword<Block.ReturnInfo<?>> {
|
public class ContinueKeyword implements Keyword<EvaluationInfo<?>> {
|
||||||
private final SourcePosition position;
|
private final SourcePosition position;
|
||||||
|
|
||||||
public ContinueKeyword(SourcePosition position) {
|
public ContinueKeyword(SourcePosition position) {
|
||||||
@@ -22,8 +23,8 @@ public class ContinueKeyword implements Keyword<Block.ReturnInfo<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
return new Block.ReturnInfo<>(Block.ReturnLevel.CONTINUE, null);
|
return new EvaluationInfo<>(EvaluationLevel.CONTINUE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+5
-4
@@ -7,14 +7,15 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
||||||
|
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||||
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
||||||
|
|
||||||
|
|
||||||
public class FailKeyword implements Keyword<Block.ReturnInfo<?>> {
|
public class FailKeyword implements Keyword<EvaluationInfo<?>> {
|
||||||
private final SourcePosition position;
|
private final SourcePosition position;
|
||||||
|
|
||||||
public FailKeyword(SourcePosition position) {
|
public FailKeyword(SourcePosition position) {
|
||||||
@@ -22,8 +23,8 @@ public class FailKeyword implements Keyword<Block.ReturnInfo<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
return new Block.ReturnInfo<>(Block.ReturnLevel.FAIL, null);
|
return new EvaluationInfo<>(EvaluationLevel.FAIL, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+20
-5
@@ -7,23 +7,30 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
||||||
|
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||||
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class ReturnKeyword implements Keyword<Block.ReturnInfo<?>> {
|
|
||||||
|
public class ReturnKeyword implements Keyword<EvaluationInfo<?>> {
|
||||||
private final SourcePosition position;
|
private final SourcePosition position;
|
||||||
|
|
||||||
public ReturnKeyword(SourcePosition position) {
|
private final Expression<?> data;
|
||||||
|
|
||||||
|
public ReturnKeyword(@Nullable Expression<?> data, SourcePosition position) {
|
||||||
|
this.data = data;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
return new Block.ReturnInfo<>(Block.ReturnLevel.RETURN, null);
|
return new EvaluationInfo<>(EvaluationLevel.RETURN, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -35,4 +42,12 @@ public class ReturnKeyword implements Keyword<Block.ReturnInfo<?>> {
|
|||||||
public ReturnType returnType() {
|
public ReturnType returnType() {
|
||||||
return ReturnType.VOID;
|
return ReturnType.VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReturnType dataReturnType() {
|
||||||
|
if(data != null) {
|
||||||
|
return data.returnType();
|
||||||
|
} else {
|
||||||
|
return ReturnType.VOID;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-6
@@ -8,6 +8,7 @@
|
|||||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike;
|
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike;
|
||||||
|
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||||
@@ -15,7 +16,7 @@ import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
|||||||
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
||||||
|
|
||||||
|
|
||||||
public class ForKeyword implements Keyword<Block.ReturnInfo<?>> {
|
public class ForKeyword implements Keyword<Block.EvaluationInfo<?>> {
|
||||||
private final Block conditional;
|
private final Block conditional;
|
||||||
private final Expression<?> initializer;
|
private final Expression<?> initializer;
|
||||||
private final Expression<Boolean> statement;
|
private final Expression<Boolean> statement;
|
||||||
@@ -31,15 +32,15 @@ public class ForKeyword implements Keyword<Block.ReturnInfo<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
public Block.EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
for(initializer.evaluate(implementationArguments, scope);
|
for(initializer.evaluate(implementationArguments, scope);
|
||||||
statement.evaluate(implementationArguments, scope);
|
statement.evaluate(implementationArguments, scope);
|
||||||
incrementer.evaluate(implementationArguments, scope)) {
|
incrementer.evaluate(implementationArguments, scope)) {
|
||||||
Block.ReturnInfo<?> level = conditional.evaluate(implementationArguments, scope);
|
Block.EvaluationInfo<?> level = conditional.evaluate(implementationArguments, scope);
|
||||||
if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break;
|
if(level.level().equals(EvaluationLevel.BREAK)) break;
|
||||||
if(level.getLevel().isReturnFast()) return level;
|
if(level.level().isReturnFast()) return level;
|
||||||
}
|
}
|
||||||
return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null);
|
return new Block.EvaluationInfo<>(EvaluationLevel.NONE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+5
-3
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike;
|
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -20,7 +22,7 @@ import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
|||||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||||
|
|
||||||
|
|
||||||
public class IfKeyword implements Keyword<Block.ReturnInfo<?>> {
|
public class IfKeyword implements Keyword<Block.EvaluationInfo<?>> {
|
||||||
private final Block conditional;
|
private final Block conditional;
|
||||||
private final Expression<Boolean> statement;
|
private final Expression<Boolean> statement;
|
||||||
private final SourcePosition position;
|
private final SourcePosition position;
|
||||||
@@ -37,7 +39,7 @@ public class IfKeyword implements Keyword<Block.ReturnInfo<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
public Block.EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
if(statement.evaluate(implementationArguments, scope)) return conditional.evaluate(implementationArguments, scope);
|
if(statement.evaluate(implementationArguments, scope)) return conditional.evaluate(implementationArguments, scope);
|
||||||
else {
|
else {
|
||||||
for(Pair<Expression<Boolean>, Block> pair : elseIf) {
|
for(Pair<Expression<Boolean>, Block> pair : elseIf) {
|
||||||
@@ -47,7 +49,7 @@ public class IfKeyword implements Keyword<Block.ReturnInfo<?>> {
|
|||||||
}
|
}
|
||||||
if(elseBlock != null) return elseBlock.evaluate(implementationArguments, scope);
|
if(elseBlock != null) return elseBlock.evaluate(implementationArguments, scope);
|
||||||
}
|
}
|
||||||
return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null);
|
return new Block.EvaluationInfo<>(EvaluationLevel.NONE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+8
-6
@@ -8,6 +8,8 @@
|
|||||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike;
|
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike;
|
||||||
|
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||||
|
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||||
@@ -15,7 +17,7 @@ import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
|||||||
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
|
||||||
|
|
||||||
|
|
||||||
public class WhileKeyword implements Keyword<Block.ReturnInfo<?>> {
|
public class WhileKeyword implements Keyword<EvaluationInfo<?>> {
|
||||||
private final Block conditional;
|
private final Block conditional;
|
||||||
private final Expression<Boolean> statement;
|
private final Expression<Boolean> statement;
|
||||||
private final SourcePosition position;
|
private final SourcePosition position;
|
||||||
@@ -27,13 +29,13 @@ public class WhileKeyword implements Keyword<Block.ReturnInfo<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||||
while(statement.evaluate(implementationArguments, scope)) {
|
while(statement.evaluate(implementationArguments, scope)) {
|
||||||
Block.ReturnInfo<?> level = conditional.evaluate(implementationArguments, scope);
|
EvaluationInfo<?> level = conditional.evaluate(implementationArguments, scope);
|
||||||
if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break;
|
if(level.level().equals(EvaluationLevel.BREAK)) break;
|
||||||
if(level.getLevel().isReturnFast()) return level;
|
if(level.level().isReturnFast()) return level;
|
||||||
}
|
}
|
||||||
return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null);
|
return new EvaluationInfo<>(EvaluationLevel.NONE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+10
-6
@@ -76,9 +76,9 @@ public class Token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVariableDeclaration() {
|
public boolean isVariableDeclaration() {
|
||||||
return type.equals(Type.STRING_VARIABLE)
|
return type.equals(Type.TYPE_STRING)
|
||||||
|| type.equals(Type.BOOLEAN_VARIABLE)
|
|| type.equals(Type.TYPE_BOOLEAN)
|
||||||
|| type.equals(Type.NUMBER_VARIABLE);
|
|| type.equals(Type.TYPE_NUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isControlStructure() {
|
public boolean isControlStructure() {
|
||||||
@@ -192,15 +192,19 @@ public class Token {
|
|||||||
/**
|
/**
|
||||||
* Numeric variable declaration
|
* Numeric variable declaration
|
||||||
*/
|
*/
|
||||||
NUMBER_VARIABLE,
|
TYPE_NUMBER,
|
||||||
/**
|
/**
|
||||||
* String variable declaration
|
* String variable declaration
|
||||||
*/
|
*/
|
||||||
STRING_VARIABLE,
|
TYPE_STRING,
|
||||||
/**
|
/**
|
||||||
* Boolean variable declaration
|
* Boolean variable declaration
|
||||||
*/
|
*/
|
||||||
BOOLEAN_VARIABLE,
|
TYPE_BOOLEAN,
|
||||||
|
/**
|
||||||
|
* Void type declaration
|
||||||
|
*/
|
||||||
|
TYPE_VOID,
|
||||||
/**
|
/**
|
||||||
* If statement declaration
|
* If statement declaration
|
||||||
*/
|
*/
|
||||||
|
|||||||
+5
-3
@@ -182,11 +182,13 @@ public class Tokenizer {
|
|||||||
return new Token(tokenString, Token.Type.BOOLEAN, reader.getPosition());
|
return new Token(tokenString, Token.Type.BOOLEAN, reader.getPosition());
|
||||||
|
|
||||||
if(tokenString.equals("num"))
|
if(tokenString.equals("num"))
|
||||||
return new Token(tokenString, Token.Type.NUMBER_VARIABLE, reader.getPosition());
|
return new Token(tokenString, Token.Type.TYPE_NUMBER, reader.getPosition());
|
||||||
if(tokenString.equals("str"))
|
if(tokenString.equals("str"))
|
||||||
return new Token(tokenString, Token.Type.STRING_VARIABLE, reader.getPosition());
|
return new Token(tokenString, Token.Type.TYPE_STRING, reader.getPosition());
|
||||||
if(tokenString.equals("bool"))
|
if(tokenString.equals("bool"))
|
||||||
return new Token(tokenString, Token.Type.BOOLEAN_VARIABLE, reader.getPosition());
|
return new Token(tokenString, Token.Type.TYPE_BOOLEAN, reader.getPosition());
|
||||||
|
if(tokenString.equals("void"))
|
||||||
|
return new Token(tokenString, Token.Type.TYPE_VOID, reader.getPosition());
|
||||||
|
|
||||||
if(tokenString.equals("if"))
|
if(tokenString.equals("if"))
|
||||||
return new Token(tokenString, Token.Type.IF_STATEMENT, reader.getPosition());
|
return new Token(tokenString, Token.Type.IF_STATEMENT, reader.getPosition());
|
||||||
|
|||||||
Reference in New Issue
Block a user