mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-06-17 14:21:08 +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.BreakKeyword;
|
||||||
import com.dfsek.terra.api.structures.parser.lang.keywords.ContinueKeyword;
|
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.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.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.BinaryOperation;
|
||||||
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanAndOperation;
|
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanAndOperation;
|
||||||
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanNotOperation;
|
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 {
|
private Keyword<?> parseLoopLike(List<Token> tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||||
|
|
||||||
Token identifier = tokens.remove(0);
|
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);
|
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.GROUP_END);
|
||||||
|
|
||||||
ParserUtil.checkType(tokens.remove(0), Token.Type.BLOCK_BEGIN);
|
ParserUtil.checkType(tokens.remove(0), Token.Type.BLOCK_BEGIN);
|
||||||
|
|
||||||
if(identifier.getType().equals(Token.Type.IF_STATEMENT))
|
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))
|
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());
|
else throw new UnsupportedOperationException("Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +301,8 @@ public class Parser {
|
|||||||
Token token = tokens.get(0);
|
Token token = tokens.get(0);
|
||||||
if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
|
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)
|
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc)
|
||||||
parsedItems.add(parseLoopLike(tokens, parsedVariables));
|
parsedItems.add(parseLoopLike(tokens, parsedVariables));
|
||||||
@@ -279,14 +312,8 @@ public class Parser {
|
|||||||
parsedItems.add(parseAssignment(variable, tokens, parsedVariables));
|
parsedItems.add(parseAssignment(variable, tokens, parsedVariables));
|
||||||
} else parsedItems.add(parseFunction(tokens, true, parsedVariables));
|
} else parsedItems.add(parseFunction(tokens, true, parsedVariables));
|
||||||
} else if(token.isVariableDeclaration()) {
|
} else if(token.isVariableDeclaration()) {
|
||||||
Variable<?> temp;
|
Variable<?> temp = parseVariableDeclaration(tokens, ParserUtil.getVariableReturnType(token));
|
||||||
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);
|
|
||||||
Token name = tokens.get(1);
|
Token name = tokens.get(1);
|
||||||
|
|
||||||
ParserUtil.checkType(name, Token.Type.IDENTIFIER); // Name must be an identifier.
|
ParserUtil.checkType(name, Token.Type.IDENTIFIER); // Name must be an identifier.
|
||||||
|
|
||||||
if(functions.containsKey(name.getContent()) || parsedVariables.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
|
if(functions.containsKey(name.getContent()) || parsedVariables.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
|
||||||
|
|||||||
@@ -46,4 +46,17 @@ public class ParserUtil {
|
|||||||
if(!token.isBinaryOperator())
|
if(!token.isBinaryOperator())
|
||||||
throw new ParseException("Expected binary operator, found " + token.getType() + ": " + token.getPosition());
|
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 {
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+45
@@ -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
-1
@@ -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.Block;
|
||||||
import com.dfsek.terra.api.structures.parser.lang.Keyword;
|
import com.dfsek.terra.api.structures.parser.lang.Keyword;
|
||||||
+2
-2
@@ -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.Block;
|
||||||
import com.dfsek.terra.api.structures.parser.lang.Keyword;
|
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)) {
|
while(statement.apply(buffer, rotation, recursions)) {
|
||||||
Block.ReturnLevel level = conditional.apply(buffer, rotation, recursions);
|
Block.ReturnLevel level = conditional.apply(buffer, rotation, recursions);
|
||||||
if(level.equals(Block.ReturnLevel.BREAK)) break;
|
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;
|
return Block.ReturnLevel.NONE;
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,8 @@ public class Token {
|
|||||||
|
|
||||||
public boolean isLoopLike() {
|
public boolean isLoopLike() {
|
||||||
return type.equals(Type.IF_STATEMENT)
|
return type.equals(Type.IF_STATEMENT)
|
||||||
|| type.equals(Type.WHILE_LOOP);
|
|| type.equals(Type.WHILE_LOOP)
|
||||||
|
|| type.equals(Type.FOR_LOOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isIdentifier() {
|
public boolean isIdentifier() {
|
||||||
@@ -214,6 +215,10 @@ public class Token {
|
|||||||
/**
|
/**
|
||||||
* ID declaration
|
* 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()));
|
return new Token(tokenString, Token.Type.IF_STATEMENT, 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"))
|
||||||
|
return new Token(tokenString, Token.Type.FOR_LOOP, new Position(reader.getLine(), reader.getIndex()));
|
||||||
|
|
||||||
if(tokenString.equals("return"))
|
if(tokenString.equals("return"))
|
||||||
return new Token(tokenString, Token.Type.RETURN, new Position(reader.getLine(), reader.getIndex()));
|
return new Token(tokenString, Token.Type.RETURN, new Position(reader.getLine(), reader.getIndex()));
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ bool truetest = false;
|
|||||||
|
|
||||||
num iterator = 0;
|
num iterator = 0;
|
||||||
|
|
||||||
|
for(num i = 0; i < 5; i = i + 1) {
|
||||||
|
test("i = " + i, iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
while(iterator < 5) {
|
while(iterator < 5) {
|
||||||
test("always, even after " + 2, iterator);
|
test("always, even after " + 2, iterator);
|
||||||
iterator = iterator + 1;
|
iterator = iterator + 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user