mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-02-16 10:30:42 +00:00
parse things in a less dumb way
This commit is contained in:
@@ -3,19 +3,21 @@ package com.dfsek.terra.api.structures.parser;
|
||||
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Block;
|
||||
import com.dfsek.terra.api.structures.parser.lang.ConstantExpression;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Expression;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Executable;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Function;
|
||||
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.Statement;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.IfKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.statements.EqualsStatement;
|
||||
import com.dfsek.terra.api.structures.parser.lang.statements.NotEqualsStatement;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Token;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Tokenizer;
|
||||
import com.dfsek.terra.api.structures.tokenizer.exceptions.TokenizerException;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -60,37 +62,41 @@ public class Parser {
|
||||
}
|
||||
|
||||
|
||||
private Keyword<?> parseKeyword(List<Token> tokens, List<Token> functionAndArguments) throws ParseException {
|
||||
private Keyword<?> parseKeyword(List<Token> tokens) throws ParseException {
|
||||
|
||||
Token identifier = functionAndArguments.remove(0);
|
||||
checkType(identifier, Token.Type.IDENTIFIER);
|
||||
Token identifier = tokens.remove(0);
|
||||
checkType(identifier, Token.Type.KEYWORD);
|
||||
if(!keywords.contains(identifier.getContent()))
|
||||
throw new ParseException("No such keyword " + identifier.getContent() + ": " + identifier.getStart());
|
||||
Keyword<?> k = null;
|
||||
if(identifier.getContent().equals("if")) {
|
||||
|
||||
checkType(functionAndArguments.remove(0), Token.Type.BODY_BEGIN);
|
||||
checkType(tokens.remove(0), Token.Type.BODY_BEGIN);
|
||||
|
||||
Expression<?> left = parseExpression(functionAndArguments);
|
||||
Executable<?> left = parseExpression(tokens);
|
||||
|
||||
Statement statement = null;
|
||||
Token comparator = functionAndArguments.remove(0);
|
||||
Token comparator = tokens.remove(0);
|
||||
checkType(comparator, Token.Type.BOOLEAN_OPERATOR);
|
||||
|
||||
Expression<?> right = parseExpression(functionAndArguments);
|
||||
Executable<?> right = parseExpression(tokens);
|
||||
|
||||
checkType(functionAndArguments.remove(0), Token.Type.BODY_END);
|
||||
checkType(tokens.remove(0), Token.Type.BODY_END);
|
||||
if(comparator.getContent().equals("==")) {
|
||||
statement = new EqualsStatement(left, right);
|
||||
} else if(comparator.getContent().equals("!=")) {
|
||||
statement = new NotEqualsStatement(left, right);
|
||||
}
|
||||
|
||||
checkType(tokens.remove(0), Token.Type.BLOCK_BEGIN);
|
||||
|
||||
k = new IfKeyword(parseBlock(tokens), statement);
|
||||
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
private Expression<?> parseExpression(List<Token> tokens) throws ParseException {
|
||||
private Executable<?> parseExpression(List<Token> tokens) throws ParseException {
|
||||
if(tokens.get(0).isConstant()) {
|
||||
return new ConstantExpression(tokens.remove(0).getContent());
|
||||
} else return parseFunction(tokens, false);
|
||||
@@ -98,18 +104,25 @@ public class Parser {
|
||||
|
||||
private Block parseBlock(List<Token> tokens) throws ParseException {
|
||||
List<Item<?>> parsedItems = new GlueList<>();
|
||||
List<Token> functionArgs = new GlueList<>();
|
||||
|
||||
checkType(tokens.get(0), Token.Type.IDENTIFIER, Token.Type.KEYWORD);
|
||||
main:
|
||||
while(tokens.size() > 0) {
|
||||
Token token = tokens.remove(0);
|
||||
if(token.getType().equals(Token.Type.BLOCK_END)) break;
|
||||
functionArgs.add(token);
|
||||
if(token.getType().equals(Token.Type.STATEMENT_END)) {
|
||||
parsedItems.add(parseFunction(functionArgs, true));
|
||||
functionArgs.clear();
|
||||
} else if(token.getType().equals(Token.Type.BLOCK_BEGIN)) {
|
||||
parsedItems.add(parseKeyword(tokens, functionArgs));
|
||||
functionArgs.clear();
|
||||
Token token = tokens.get(0);
|
||||
checkType(token, Token.Type.IDENTIFIER, Token.Type.KEYWORD, Token.Type.BLOCK_END);
|
||||
switch(token.getType()) {
|
||||
case KEYWORD:
|
||||
parsedItems.add(parseKeyword(tokens));
|
||||
if(tokens.isEmpty()) break;
|
||||
checkType(tokens.get(0), Token.Type.IDENTIFIER, Token.Type.KEYWORD, Token.Type.BLOCK_END);
|
||||
break;
|
||||
case IDENTIFIER:
|
||||
parsedItems.add(parseFunction(tokens, true));
|
||||
if(tokens.isEmpty()) break;
|
||||
checkType(tokens.remove(0), Token.Type.STATEMENT_END, Token.Type.BLOCK_END);
|
||||
break;
|
||||
case BLOCK_END:
|
||||
tokens.remove(0);
|
||||
break main;
|
||||
}
|
||||
}
|
||||
return new Block(parsedItems);
|
||||
@@ -129,7 +142,7 @@ public class Parser {
|
||||
|
||||
functionAndArguments.remove(0); // Remove body end
|
||||
|
||||
if(fullStatement) checkType(functionAndArguments.remove(0), Token.Type.STATEMENT_END);
|
||||
if(fullStatement) checkType(functionAndArguments.get(0), Token.Type.STATEMENT_END);
|
||||
|
||||
List<String> arg = args.stream().map(Token::getContent).collect(Collectors.toList());
|
||||
|
||||
@@ -158,8 +171,8 @@ public class Parser {
|
||||
return args;
|
||||
}
|
||||
|
||||
private void checkType(Token token, Token.Type expected) throws ParseException {
|
||||
if(!token.getType().equals(expected))
|
||||
throw new ParseException("Expected " + expected + " but found " + token.getType() + ": " + token.getStart());
|
||||
private void checkType(Token token, Token.Type... expected) throws ParseException {
|
||||
for(Token.Type type : expected) if(token.getType().equals(type)) return;
|
||||
throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType() + ": " + token.getStart());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.dfsek.terra.api.structures.parser.lang;
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
|
||||
public class ConstantExpression implements Expression<Object> {
|
||||
public class ConstantExpression implements Executable<Object> {
|
||||
private final Object constant;
|
||||
|
||||
public ConstantExpression(Object constant) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
public interface Expression<T> extends Item<T> {
|
||||
public interface Executable<T> extends Item<T> {
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
public interface Function<T> extends Expression<T> {
|
||||
|
||||
public interface Function<T> extends Executable<T> {
|
||||
String name();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
public interface Keyword<T> extends Expression<T> {
|
||||
public interface Keyword<T> extends Executable<T> {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.statements;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Item;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Statement;
|
||||
|
||||
public class NotEqualsStatement implements Statement {
|
||||
private final Item<?> left;
|
||||
private final Item<?> right;
|
||||
|
||||
public NotEqualsStatement(Item<?> left, Item<?> right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(Location location) {
|
||||
System.out.println(left.apply(location));
|
||||
System.out.println(right.apply(location));
|
||||
return !left.apply(location).equals(right.apply(location));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(Location location, Chunk chunk) {
|
||||
return left.apply(location, chunk).equals(right.apply(location, chunk));
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,11 @@ public class Token {
|
||||
* Function identifier or language keyword
|
||||
*/
|
||||
IDENTIFIER,
|
||||
|
||||
/**
|
||||
* Language keyword
|
||||
*/
|
||||
KEYWORD,
|
||||
/**
|
||||
* Numeric literal
|
||||
*/
|
||||
|
||||
@@ -11,8 +11,8 @@ import java.util.Set;
|
||||
public class Tokenizer {
|
||||
private final Lookahead reader;
|
||||
|
||||
private final Set<Character> syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', ',', '\\', '=', // Currently used chars
|
||||
'{', '}'); // Reserved chars
|
||||
private final Set<Character> syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', ',', '\\', '=', '{', '}', '+'); // Reserved chars
|
||||
private final Set<String> keywords = Sets.newHashSet("if", "return");
|
||||
|
||||
|
||||
public Tokenizer(String data) {
|
||||
@@ -38,6 +38,8 @@ public class Tokenizer {
|
||||
return new Token("false", Token.Type.BOOLEAN, new Position(reader.getLine(), reader.getIndex()));
|
||||
if(reader.matches("==", true))
|
||||
return new Token("==", Token.Type.BOOLEAN_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
|
||||
if(reader.matches("!=", true))
|
||||
return new Token("!=", Token.Type.BOOLEAN_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
|
||||
|
||||
if(isNumberStart()) {
|
||||
StringBuilder num = new StringBuilder();
|
||||
@@ -90,7 +92,7 @@ public class Tokenizer {
|
||||
String tokenString = token.toString();
|
||||
|
||||
|
||||
return new Token(tokenString, Token.Type.IDENTIFIER, new Position(reader.getLine(), reader.getIndex()));
|
||||
return new Token(tokenString, keywords.contains(tokenString) ? Token.Type.KEYWORD : Token.Type.IDENTIFIER, new Position(reader.getLine(), reader.getIndex()));
|
||||
}
|
||||
|
||||
private boolean isNumberLike() {
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.List;
|
||||
public class ParserTest {
|
||||
@Test
|
||||
public void parse() throws IOException, ParseException {
|
||||
Parser parser = new Parser(IOUtils.toString(getClass().getResourceAsStream("/target/server/plugins/Terra/test.tesf")));
|
||||
Parser parser = new Parser(IOUtils.toString(getClass().getResourceAsStream("/test.tesf")));
|
||||
|
||||
parser.addFunction("test", new FunctionBuilder<Test1>() {
|
||||
@Override
|
||||
|
||||
8
common/src/test/resources/test.tesf
Normal file
8
common/src/test/resources/test.tesf
Normal file
@@ -0,0 +1,8 @@
|
||||
test("hello", 2);
|
||||
|
||||
if(test("fsdfsdf", 3) == 2) {
|
||||
test("fdsgdf", 3.4);
|
||||
if(test("fsdfsdf", 3) == 2) {
|
||||
test("fdsgdf", 3.4);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user