mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-08 16:56:07 +00:00
Add for loops
This commit is contained in:
@@ -17,9 +17,10 @@ import com.dfsek.terra.api.structures.parser.lang.functions.builtin.SqrtFunction
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.BreakKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.ContinueKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.FailKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.IfKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.ReturnKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.WhileKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.looplike.ForKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.looplike.IfKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.looplike.WhileKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.BinaryOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanAndOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanNotOperation;
|
||||
@@ -113,21 +114,52 @@ public class Parser {
|
||||
private Keyword<?> parseLoopLike(List<Token> tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||
|
||||
Token identifier = tokens.remove(0);
|
||||
ParserUtil.checkType(identifier, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP);
|
||||
ParserUtil.checkType(identifier, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP);
|
||||
|
||||
ParserUtil.checkType(tokens.remove(0), Token.Type.GROUP_BEGIN);
|
||||
|
||||
Returnable<?> comparator = parseExpression(tokens, true, variableMap);
|
||||
ParserUtil.checkReturnType(comparator, Returnable.ReturnType.BOOLEAN);
|
||||
|
||||
if(identifier.getType().equals(Token.Type.FOR_LOOP)) {
|
||||
Token f = tokens.get(0);
|
||||
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));
|
||||
Token name = tokens.get(1);
|
||||
ParserUtil.checkType(tokens.remove(0), Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
|
||||
initializer = parseAssignment(forVar, tokens, variableMap);
|
||||
variableMap.put(name.getContent(), forVar);
|
||||
} else initializer = parseExpression(tokens, true, variableMap);
|
||||
ParserUtil.checkType(tokens.remove(0), Token.Type.STATEMENT_END);
|
||||
Returnable<?> conditional = parseExpression(tokens, true, variableMap);
|
||||
ParserUtil.checkReturnType(conditional, Returnable.ReturnType.BOOLEAN);
|
||||
ParserUtil.checkType(tokens.remove(0), Token.Type.STATEMENT_END);
|
||||
|
||||
Item<?> incrementer;
|
||||
Token token = tokens.get(0);
|
||||
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.remove(0), Token.Type.GROUP_END);
|
||||
|
||||
ParserUtil.checkType(tokens.remove(0), Token.Type.BLOCK_BEGIN);
|
||||
|
||||
return new ForKeyword(parseBlock(tokens, variableMap), initializer, (Returnable<Boolean>) conditional, incrementer, identifier.getPosition());
|
||||
}
|
||||
|
||||
Returnable<?> first = parseExpression(tokens, true, variableMap);
|
||||
ParserUtil.checkReturnType(first, Returnable.ReturnType.BOOLEAN);
|
||||
|
||||
ParserUtil.checkType(tokens.remove(0), Token.Type.GROUP_END);
|
||||
|
||||
ParserUtil.checkType(tokens.remove(0), Token.Type.BLOCK_BEGIN);
|
||||
|
||||
if(identifier.getType().equals(Token.Type.IF_STATEMENT))
|
||||
return new IfKeyword(parseBlock(tokens, variableMap), (Returnable<Boolean>) comparator, identifier.getPosition()); // If statement
|
||||
return new IfKeyword(parseBlock(tokens, variableMap), (Returnable<Boolean>) first, identifier.getPosition()); // If statement
|
||||
else if(identifier.getType().equals(Token.Type.WHILE_LOOP))
|
||||
return new WhileKeyword(parseBlock(tokens, variableMap), (Returnable<Boolean>) comparator, identifier.getPosition()); // While loop
|
||||
return new WhileKeyword(parseBlock(tokens, variableMap), (Returnable<Boolean>) first, identifier.getPosition()); // While loop
|
||||
else throw new UnsupportedOperationException("Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
|
||||
}
|
||||
|
||||
@@ -269,7 +301,8 @@ public class Parser {
|
||||
Token token = tokens.get(0);
|
||||
if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
|
||||
|
||||
ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL);
|
||||
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, Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL);
|
||||
|
||||
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc)
|
||||
parsedItems.add(parseLoopLike(tokens, parsedVariables));
|
||||
@@ -279,14 +312,8 @@ public class Parser {
|
||||
parsedItems.add(parseAssignment(variable, tokens, parsedVariables));
|
||||
} else parsedItems.add(parseFunction(tokens, true, parsedVariables));
|
||||
} else if(token.isVariableDeclaration()) {
|
||||
Variable<?> temp;
|
||||
if(token.getType().equals(Token.Type.NUMBER_VARIABLE))
|
||||
temp = parseVariableDeclaration(tokens, Returnable.ReturnType.NUMBER);
|
||||
else if(token.getType().equals(Token.Type.STRING_VARIABLE))
|
||||
temp = parseVariableDeclaration(tokens, Returnable.ReturnType.STRING);
|
||||
else temp = parseVariableDeclaration(tokens, Returnable.ReturnType.BOOLEAN);
|
||||
Variable<?> temp = parseVariableDeclaration(tokens, ParserUtil.getVariableReturnType(token));
|
||||
Token name = tokens.get(1);
|
||||
|
||||
ParserUtil.checkType(name, Token.Type.IDENTIFIER); // Name must be an identifier.
|
||||
|
||||
if(functions.containsKey(name.getContent()) || parsedVariables.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
|
||||
|
||||
@@ -46,4 +46,17 @@ public class ParserUtil {
|
||||
if(!token.isBinaryOperator())
|
||||
throw new ParseException("Expected binary operator, found " + token.getType() + ": " + token.getPosition());
|
||||
}
|
||||
|
||||
public static Returnable.ReturnType getVariableReturnType(Token varToken) throws ParseException {
|
||||
switch(varToken.getType()) {
|
||||
case NUMBER_VARIABLE:
|
||||
return Returnable.ReturnType.NUMBER;
|
||||
case STRING_VARIABLE:
|
||||
return Returnable.ReturnType.STRING;
|
||||
case BOOLEAN_VARIABLE:
|
||||
return Returnable.ReturnType.BOOLEAN;
|
||||
default:
|
||||
throw new ParseException("Unexpected token " + varToken.getType() + "; expected variable declaration: " + varToken.getPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,16 @@ public class Block implements Item<Block.ReturnLevel> {
|
||||
}
|
||||
|
||||
public enum ReturnLevel {
|
||||
NONE, BREAK, CONTINUE, RETURN, FAIL
|
||||
NONE(false), BREAK(false), CONTINUE(false), RETURN(true), FAIL(true);
|
||||
|
||||
private final boolean returnFast;
|
||||
|
||||
ReturnLevel(boolean returnFast) {
|
||||
this.returnFast = returnFast;
|
||||
}
|
||||
|
||||
public boolean isReturnFast() {
|
||||
return returnFast;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.keywords.looplike;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.lang.Block;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Item;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Keyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.structure.Rotation;
|
||||
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class ForKeyword implements Keyword<Block.ReturnLevel> {
|
||||
private final Block conditional;
|
||||
private final Item<?> initializer;
|
||||
private final Returnable<Boolean> statement;
|
||||
private final Item<?> incrementer;
|
||||
private final Position position;
|
||||
|
||||
public ForKeyword(Block conditional, Item<?> initializer, Returnable<Boolean> statement, Item<?> incrementer, Position position) {
|
||||
this.conditional = conditional;
|
||||
this.initializer = initializer;
|
||||
this.statement = statement;
|
||||
this.incrementer = incrementer;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block.ReturnLevel apply(Buffer buffer, Rotation rotation, int recursions) {
|
||||
for(initializer.apply(buffer, rotation, recursions); statement.apply(buffer, rotation, recursions); incrementer.apply(buffer, rotation, recursions)) {
|
||||
Block.ReturnLevel level = conditional.apply(buffer, rotation, recursions);
|
||||
if(level.equals(Block.ReturnLevel.BREAK)) break;
|
||||
if(level.isReturnFast()) return level;
|
||||
}
|
||||
return Block.ReturnLevel.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.VOID;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.keywords;
|
||||
package com.dfsek.terra.api.structures.parser.lang.keywords.looplike;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.lang.Block;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Keyword;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.keywords;
|
||||
package com.dfsek.terra.api.structures.parser.lang.keywords.looplike;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.lang.Block;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Keyword;
|
||||
@@ -23,7 +23,7 @@ public class WhileKeyword implements Keyword<Block.ReturnLevel> {
|
||||
while(statement.apply(buffer, rotation, recursions)) {
|
||||
Block.ReturnLevel level = conditional.apply(buffer, rotation, recursions);
|
||||
if(level.equals(Block.ReturnLevel.BREAK)) break;
|
||||
if(level.equals(Block.ReturnLevel.RETURN)) return Block.ReturnLevel.RETURN;
|
||||
if(level.isReturnFast()) return level;
|
||||
}
|
||||
return Block.ReturnLevel.NONE;
|
||||
}
|
||||
@@ -70,7 +70,8 @@ public class Token {
|
||||
|
||||
public boolean isLoopLike() {
|
||||
return type.equals(Type.IF_STATEMENT)
|
||||
|| type.equals(Type.WHILE_LOOP);
|
||||
|| type.equals(Type.WHILE_LOOP)
|
||||
|| type.equals(Type.FOR_LOOP);
|
||||
}
|
||||
|
||||
public boolean isIdentifier() {
|
||||
@@ -214,6 +215,10 @@ public class Token {
|
||||
/**
|
||||
* ID declaration
|
||||
*/
|
||||
ID
|
||||
ID,
|
||||
/**
|
||||
* For loop initializer token
|
||||
*/
|
||||
FOR_LOOP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,8 @@ public class Tokenizer {
|
||||
return new Token(tokenString, Token.Type.IF_STATEMENT, new Position(reader.getLine(), reader.getIndex()));
|
||||
if(tokenString.equals("while"))
|
||||
return new Token(tokenString, Token.Type.WHILE_LOOP, new Position(reader.getLine(), reader.getIndex()));
|
||||
if(tokenString.equals("for"))
|
||||
return new Token(tokenString, Token.Type.FOR_LOOP, new Position(reader.getLine(), reader.getIndex()));
|
||||
|
||||
if(tokenString.equals("return"))
|
||||
return new Token(tokenString, Token.Type.RETURN, new Position(reader.getLine(), reader.getIndex()));
|
||||
|
||||
Reference in New Issue
Block a user