mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-10-26 14:00:14 +00:00
Add else if and else
This commit is contained in:
1 parent
f6312a01d7
commit
283495832f
5 files changed
+147
-46
No files matched your search
@@ -54,6 +54,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public class Parser {
|
public class Parser {
|
||||||
private final String data;
|
private final String data;
|
||||||
private final Map<String, FunctionBuilder<? extends Function<?>>> functions = new HashMap<>();
|
private final Map<String, FunctionBuilder<? extends Function<?>>> functions = new HashMap<>();
|
||||||
@@ -111,7 +112,6 @@ public class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private Keyword<?> parseLoopLike(TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
private Keyword<?> parseLoopLike(TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||||
|
|
||||||
Token identifier = tokens.consume();
|
Token identifier = tokens.consume();
|
||||||
@@ -119,56 +119,100 @@ public class Parser {
|
|||||||
|
|
||||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
|
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
|
||||||
|
|
||||||
|
switch(identifier.getType()) {
|
||||||
if(identifier.getType().equals(Token.Type.FOR_LOOP)) {
|
case FOR_LOOP:
|
||||||
Token f = tokens.get();
|
return parseForLoop(tokens, variableMap, identifier.getPosition());
|
||||||
ParserUtil.checkType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER);
|
case IF_STATEMENT:
|
||||||
Item<?> initializer;
|
return parseIfStatement(tokens, variableMap, identifier.getPosition());
|
||||||
if(f.isVariableDeclaration()) {
|
case WHILE_LOOP:
|
||||||
Variable<?> forVar = parseVariableDeclaration(tokens, ParserUtil.getVariableReturnType(f));
|
return parseWhileLoop(tokens, variableMap, identifier.getPosition());
|
||||||
ParserUtil.checkType(tokens.consume(), Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
|
default:
|
||||||
Token name = tokens.get();
|
throw new UnsupportedOperationException("Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
|
||||||
|
|
||||||
if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
|
|
||||||
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
|
|
||||||
|
|
||||||
initializer = parseAssignment(forVar, tokens, variableMap);
|
|
||||||
variableMap.put(name.getContent(), forVar);
|
|
||||||
} else initializer = parseExpression(tokens, true, variableMap);
|
|
||||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
|
||||||
Returnable<?> conditional = parseExpression(tokens, true, variableMap);
|
|
||||||
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
|
|
||||||
Variable<?> variable = variableMap.get(token.getContent());
|
|
||||||
incrementer = parseAssignment(variable, tokens, variableMap);
|
|
||||||
} else incrementer = parseFunction(tokens, true, variableMap);
|
|
||||||
|
|
||||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
|
||||||
|
|
||||||
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN);
|
|
||||||
|
|
||||||
return new ForKeyword(parseBlock(tokens, variableMap), initializer, (Returnable<Boolean>) conditional, incrementer, identifier.getPosition());
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WhileKeyword parseWhileLoop(TokenHolder tokens, Map<String, Variable<?>> variableMap, Position start) throws ParseException {
|
||||||
Returnable<?> first = parseExpression(tokens, true, variableMap);
|
Returnable<?> first = parseExpression(tokens, true, variableMap);
|
||||||
ParserUtil.checkReturnType(first, Returnable.ReturnType.BOOLEAN);
|
ParserUtil.checkReturnType(first, Returnable.ReturnType.BOOLEAN);
|
||||||
|
|
||||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||||
|
|
||||||
|
return new WhileKeyword(parseStatementBlock(tokens, variableMap), (Returnable<Boolean>) first, start); // While loop
|
||||||
|
}
|
||||||
|
|
||||||
|
private IfKeyword parseIfStatement(TokenHolder tokens, Map<String, Variable<?>> variableMap, Position start) throws ParseException {
|
||||||
|
Returnable<?> condition = parseExpression(tokens, true, variableMap);
|
||||||
|
ParserUtil.checkReturnType(condition, Returnable.ReturnType.BOOLEAN);
|
||||||
|
|
||||||
|
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||||
|
|
||||||
|
Block elseBlock = null;
|
||||||
|
Block statement = parseStatementBlock(tokens, variableMap);
|
||||||
|
|
||||||
|
List<IfKeyword.Pair<Returnable<Boolean>, Block>> elseIf = new GlueList<>();
|
||||||
|
|
||||||
|
System.out.println(tokens.get());
|
||||||
|
|
||||||
|
while(tokens.get().getType().equals(Token.Type.ELSE)) {
|
||||||
|
tokens.consume(); // Consume else.
|
||||||
|
System.out.println("int: " + tokens.get());
|
||||||
|
if(tokens.get().getType().equals(Token.Type.IF_STATEMENT)) {
|
||||||
|
System.out.println("else if");
|
||||||
|
tokens.consume(); // Consume if.
|
||||||
|
Returnable<?> elseCondition = parseExpression(tokens, true, variableMap);
|
||||||
|
ParserUtil.checkReturnType(elseCondition, Returnable.ReturnType.BOOLEAN);
|
||||||
|
elseIf.add(new IfKeyword.Pair<>((Returnable<Boolean>) elseCondition, parseStatementBlock(tokens, variableMap)));
|
||||||
|
} else {
|
||||||
|
elseBlock = parseStatementBlock(tokens, variableMap);
|
||||||
|
break; // Else must be last.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IfKeyword(statement, (Returnable<Boolean>) condition, elseIf, elseBlock, start); // If statement
|
||||||
|
}
|
||||||
|
|
||||||
|
private Block parseStatementBlock(TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||||
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN);
|
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN);
|
||||||
|
Block block = parseBlock(tokens, variableMap);
|
||||||
|
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_END);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ForKeyword parseForLoop(TokenHolder tokens, Map<String, Variable<?>> variableMap, Position start) throws ParseException {
|
||||||
|
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()) {
|
||||||
|
Variable<?> forVar = parseVariableDeclaration(tokens, ParserUtil.getVariableReturnType(f));
|
||||||
|
ParserUtil.checkType(tokens.consume(), Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
|
||||||
|
Token name = tokens.get();
|
||||||
|
|
||||||
|
if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
|
||||||
|
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
|
||||||
|
|
||||||
|
initializer = parseAssignment(forVar, tokens, variableMap);
|
||||||
|
variableMap.put(name.getContent(), forVar);
|
||||||
|
} else initializer = parseExpression(tokens, true, variableMap);
|
||||||
|
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||||
|
Returnable<?> conditional = parseExpression(tokens, true, variableMap);
|
||||||
|
ParserUtil.checkReturnType(conditional, Returnable.ReturnType.BOOLEAN);
|
||||||
|
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||||
|
|
||||||
if(identifier.getType().equals(Token.Type.IF_STATEMENT))
|
Item<?> incrementer;
|
||||||
return new IfKeyword(parseBlock(tokens, variableMap), (Returnable<Boolean>) first, identifier.getPosition()); // If statement
|
Token token = tokens.get();
|
||||||
else if(identifier.getType().equals(Token.Type.WHILE_LOOP))
|
if(variableMap.containsKey(token.getContent())) { // Assume variable assignment
|
||||||
return new WhileKeyword(parseBlock(tokens, variableMap), (Returnable<Boolean>) first, identifier.getPosition()); // While loop
|
Variable<?> variable = variableMap.get(token.getContent());
|
||||||
else throw new UnsupportedOperationException("Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
|
incrementer = parseAssignment(variable, tokens, variableMap);
|
||||||
|
} else incrementer = parseFunction(tokens, true, variableMap);
|
||||||
|
|
||||||
|
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||||
|
|
||||||
|
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN);
|
||||||
|
Block block = parseBlock(tokens, variableMap);
|
||||||
|
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_END);
|
||||||
|
return new ForKeyword(block, initializer, (Returnable<Boolean>) conditional, incrementer, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private Returnable<?> parseExpression(TokenHolder tokens, boolean full, Map<String, Variable<?>> variableMap) throws ParseException {
|
private Returnable<?> parseExpression(TokenHolder tokens, boolean full, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||||
boolean booleanInverted = false; // Check for boolean not operator
|
boolean booleanInverted = false; // Check for boolean not operator
|
||||||
if(tokens.get().getType().equals(Token.Type.BOOLEAN_NOT)) {
|
if(tokens.get().getType().equals(Token.Type.BOOLEAN_NOT)) {
|
||||||
@@ -244,7 +288,6 @@ public class Parser {
|
|||||||
return assemble(left, right, binaryOperator);
|
return assemble(left, right, binaryOperator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private BinaryOperation<?, ?> assemble(Returnable<?> left, Returnable<?> right, Token binaryOperator) throws ParseException {
|
private BinaryOperation<?, ?> assemble(Returnable<?> left, Returnable<?> right, Token binaryOperator) throws ParseException {
|
||||||
if(binaryOperator.isStrictNumericOperator())
|
if(binaryOperator.isStrictNumericOperator())
|
||||||
ParserUtil.checkArithmeticOperation(left, right, binaryOperator); // Numeric type checking
|
ParserUtil.checkArithmeticOperation(left, right, binaryOperator); // Numeric type checking
|
||||||
@@ -311,6 +354,7 @@ public class Parser {
|
|||||||
|
|
||||||
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc)
|
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc)
|
||||||
parsedItems.add(parseLoopLike(tokens, parsedVariables));
|
parsedItems.add(parseLoopLike(tokens, parsedVariables));
|
||||||
|
continue; // No statement end
|
||||||
} else if(token.isIdentifier()) { // Parse identifiers
|
} else if(token.isIdentifier()) { // Parse identifiers
|
||||||
if(parsedVariables.containsKey(token.getContent())) { // Assume variable assignment
|
if(parsedVariables.containsKey(token.getContent())) { // Assume variable assignment
|
||||||
Variable<?> variable = parsedVariables.get(token.getContent());
|
Variable<?> variable = parsedVariables.get(token.getContent());
|
||||||
@@ -336,12 +380,11 @@ public class Parser {
|
|||||||
else if(token.getType().equals(Token.Type.FAIL)) parsedItems.add(new FailKeyword(tokens.consume().getPosition()));
|
else if(token.getType().equals(Token.Type.FAIL)) parsedItems.add(new FailKeyword(tokens.consume().getPosition()));
|
||||||
else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
|
else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
|
||||||
|
|
||||||
if(tokens.hasNext()) ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END, Token.Type.BLOCK_END);
|
if(tokens.hasNext()) ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||||
}
|
}
|
||||||
return new Block(parsedItems, first.getPosition());
|
return new Block(parsedItems, first.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private Assignment<?> parseAssignment(Variable<?> variable, TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
private Assignment<?> parseAssignment(Variable<?> variable, TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||||
Token name = tokens.get();
|
Token name = tokens.get();
|
||||||
|
|
||||||
@@ -356,7 +399,6 @@ public class Parser {
|
|||||||
return new Assignment<>((Variable<Object>) variable, (Returnable<Object>) expression, name.getPosition());
|
return new Assignment<>((Variable<Object>) variable, (Returnable<Object>) expression, name.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private Function<?> parseFunction(TokenHolder tokens, boolean fullStatement, Map<String, Variable<?>> variableMap) throws ParseException {
|
private Function<?> parseFunction(TokenHolder tokens, boolean fullStatement, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||||
Token identifier = tokens.consume();
|
Token identifier = tokens.consume();
|
||||||
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
|
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
|
||||||
|
|||||||
+34
-1
@@ -6,26 +6,41 @@ import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
|||||||
import com.dfsek.terra.api.structures.structure.Rotation;
|
import com.dfsek.terra.api.structures.structure.Rotation;
|
||||||
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
|
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
|
||||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
public class IfKeyword implements Keyword<Block.ReturnLevel> {
|
public class IfKeyword implements Keyword<Block.ReturnLevel> {
|
||||||
private final Block conditional;
|
private final Block conditional;
|
||||||
private final Returnable<Boolean> statement;
|
private final Returnable<Boolean> statement;
|
||||||
private final Position position;
|
private final Position position;
|
||||||
|
private final List<Pair<Returnable<Boolean>, Block>> elseIf;
|
||||||
|
private final Block elseBlock;
|
||||||
|
|
||||||
public IfKeyword(Block conditional, Returnable<Boolean> statement, Position position) {
|
public IfKeyword(Block conditional, Returnable<Boolean> statement, List<Pair<Returnable<Boolean>, Block>> elseIf, @Nullable Block elseBlock, Position position) {
|
||||||
this.conditional = conditional;
|
this.conditional = conditional;
|
||||||
this.statement = statement;
|
this.statement = statement;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
|
this.elseIf = elseIf;
|
||||||
|
this.elseBlock = elseBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block.ReturnLevel apply(Buffer buffer, Rotation rotation, Random random, int recursions) {
|
public Block.ReturnLevel apply(Buffer buffer, Rotation rotation, Random random, int recursions) {
|
||||||
if(statement.apply(buffer, rotation, random, recursions)) return conditional.apply(buffer, rotation, random, recursions);
|
if(statement.apply(buffer, rotation, random, recursions)) return conditional.apply(buffer, rotation, random, recursions);
|
||||||
|
else {
|
||||||
|
for(Pair<Returnable<Boolean>, Block> pair : elseIf) {
|
||||||
|
if(pair.getLeft().apply(buffer, rotation, random, recursions)) {
|
||||||
|
return pair.getRight().apply(buffer, rotation, random, recursions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(elseBlock != null) return elseBlock.apply(buffer, rotation, random, recursions);
|
||||||
|
}
|
||||||
return Block.ReturnLevel.NONE;
|
return Block.ReturnLevel.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Position getPosition() {
|
public Position getPosition() {
|
||||||
return position;
|
return position;
|
||||||
@@ -35,4 +50,22 @@ public class IfKeyword implements Keyword<Block.ReturnLevel> {
|
|||||||
public ReturnType returnType() {
|
public ReturnType returnType() {
|
||||||
return ReturnType.VOID;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -219,6 +219,10 @@ public class Token {
|
|||||||
/**
|
/**
|
||||||
* For loop initializer token
|
* For loop initializer token
|
||||||
*/
|
*/
|
||||||
FOR_LOOP
|
FOR_LOOP,
|
||||||
|
/**
|
||||||
|
* Else keyword
|
||||||
|
*/
|
||||||
|
ELSE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,6 +131,8 @@ public class Tokenizer {
|
|||||||
|
|
||||||
if(tokenString.equals("if"))
|
if(tokenString.equals("if"))
|
||||||
return new Token(tokenString, Token.Type.IF_STATEMENT, new Position(reader.getLine(), reader.getIndex()));
|
return new Token(tokenString, Token.Type.IF_STATEMENT, new Position(reader.getLine(), reader.getIndex()));
|
||||||
|
if(tokenString.equals("else"))
|
||||||
|
return new Token(tokenString, Token.Type.ELSE, new Position(reader.getLine(), reader.getIndex()));
|
||||||
if(tokenString.equals("while"))
|
if(tokenString.equals("while"))
|
||||||
return new Token(tokenString, Token.Type.WHILE_LOOP, new Position(reader.getLine(), reader.getIndex()));
|
return new Token(tokenString, Token.Type.WHILE_LOOP, new Position(reader.getLine(), reader.getIndex()));
|
||||||
if(tokenString.equals("for"))
|
if(tokenString.equals("for"))
|
||||||
|
|||||||
@@ -27,6 +27,26 @@ while(iterator < 5) {
|
|||||||
test("not after " + 2, iterator);
|
test("not after " + 2, iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(true) {
|
||||||
|
test("true!" + 2, iterator);
|
||||||
|
} else {
|
||||||
|
test("false!" + 2, iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(false) {
|
||||||
|
test("true!" + 2, iterator);
|
||||||
|
} else {
|
||||||
|
test("false!" + 2, iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(false) {
|
||||||
|
test("true again!" + 2, iterator);
|
||||||
|
} else if(true == true) {
|
||||||
|
test("false again!" + 2, iterator);
|
||||||
|
} else {
|
||||||
|
test("not logged!" + 2, iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(true && !(boolean && false) && true) {
|
if(true && !(boolean && false) && true) {
|
||||||
num scopedVar = 2;
|
num scopedVar = 2;
|
||||||
|
|||||||
Reference in new issue
Block a user