mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-23 00:29:51 +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.exceptions.ParseException;
|
||||||
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.ConstantExpression;
|
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.Function;
|
||||||
import com.dfsek.terra.api.structures.parser.lang.Item;
|
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.Keyword;
|
||||||
import com.dfsek.terra.api.structures.parser.lang.Statement;
|
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.keywords.IfKeyword;
|
||||||
import com.dfsek.terra.api.structures.parser.lang.statements.EqualsStatement;
|
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.Token;
|
||||||
import com.dfsek.terra.api.structures.tokenizer.Tokenizer;
|
import com.dfsek.terra.api.structures.tokenizer.Tokenizer;
|
||||||
import com.dfsek.terra.api.structures.tokenizer.exceptions.TokenizerException;
|
import com.dfsek.terra.api.structures.tokenizer.exceptions.TokenizerException;
|
||||||
import com.dfsek.terra.api.util.GlueList;
|
import com.dfsek.terra.api.util.GlueList;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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);
|
Token identifier = tokens.remove(0);
|
||||||
checkType(identifier, Token.Type.IDENTIFIER);
|
checkType(identifier, Token.Type.KEYWORD);
|
||||||
if(!keywords.contains(identifier.getContent()))
|
if(!keywords.contains(identifier.getContent()))
|
||||||
throw new ParseException("No such keyword " + identifier.getContent() + ": " + identifier.getStart());
|
throw new ParseException("No such keyword " + identifier.getContent() + ": " + identifier.getStart());
|
||||||
Keyword<?> k = null;
|
Keyword<?> k = null;
|
||||||
if(identifier.getContent().equals("if")) {
|
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;
|
Statement statement = null;
|
||||||
Token comparator = functionAndArguments.remove(0);
|
Token comparator = tokens.remove(0);
|
||||||
checkType(comparator, Token.Type.BOOLEAN_OPERATOR);
|
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("==")) {
|
if(comparator.getContent().equals("==")) {
|
||||||
statement = new EqualsStatement(left, right);
|
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);
|
k = new IfKeyword(parseBlock(tokens), statement);
|
||||||
|
|
||||||
}
|
}
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Expression<?> parseExpression(List<Token> tokens) throws ParseException {
|
private Executable<?> parseExpression(List<Token> tokens) throws ParseException {
|
||||||
if(tokens.get(0).isConstant()) {
|
if(tokens.get(0).isConstant()) {
|
||||||
return new ConstantExpression(tokens.remove(0).getContent());
|
return new ConstantExpression(tokens.remove(0).getContent());
|
||||||
} else return parseFunction(tokens, false);
|
} else return parseFunction(tokens, false);
|
||||||
@@ -98,18 +104,25 @@ public class Parser {
|
|||||||
|
|
||||||
private Block parseBlock(List<Token> tokens) throws ParseException {
|
private Block parseBlock(List<Token> tokens) throws ParseException {
|
||||||
List<Item<?>> parsedItems = new GlueList<>();
|
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) {
|
while(tokens.size() > 0) {
|
||||||
Token token = tokens.remove(0);
|
Token token = tokens.get(0);
|
||||||
if(token.getType().equals(Token.Type.BLOCK_END)) break;
|
checkType(token, Token.Type.IDENTIFIER, Token.Type.KEYWORD, Token.Type.BLOCK_END);
|
||||||
functionArgs.add(token);
|
switch(token.getType()) {
|
||||||
if(token.getType().equals(Token.Type.STATEMENT_END)) {
|
case KEYWORD:
|
||||||
parsedItems.add(parseFunction(functionArgs, true));
|
parsedItems.add(parseKeyword(tokens));
|
||||||
functionArgs.clear();
|
if(tokens.isEmpty()) break;
|
||||||
} else if(token.getType().equals(Token.Type.BLOCK_BEGIN)) {
|
checkType(tokens.get(0), Token.Type.IDENTIFIER, Token.Type.KEYWORD, Token.Type.BLOCK_END);
|
||||||
parsedItems.add(parseKeyword(tokens, functionArgs));
|
break;
|
||||||
functionArgs.clear();
|
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);
|
return new Block(parsedItems);
|
||||||
@@ -129,7 +142,7 @@ public class Parser {
|
|||||||
|
|
||||||
functionAndArguments.remove(0); // Remove body end
|
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());
|
List<String> arg = args.stream().map(Token::getContent).collect(Collectors.toList());
|
||||||
|
|
||||||
@@ -158,8 +171,8 @@ public class Parser {
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkType(Token token, Token.Type expected) throws ParseException {
|
private void checkType(Token token, Token.Type... expected) throws ParseException {
|
||||||
if(!token.getType().equals(expected))
|
for(Token.Type type : expected) if(token.getType().equals(type)) return;
|
||||||
throw new ParseException("Expected " + expected + " but found " + token.getType() + ": " + token.getStart());
|
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.math.vector.Location;
|
||||||
import com.dfsek.terra.api.platform.world.Chunk;
|
import com.dfsek.terra.api.platform.world.Chunk;
|
||||||
|
|
||||||
public class ConstantExpression implements Expression<Object> {
|
public class ConstantExpression implements Executable<Object> {
|
||||||
private final Object constant;
|
private final Object constant;
|
||||||
|
|
||||||
public ConstantExpression(Object constant) {
|
public ConstantExpression(Object constant) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.dfsek.terra.api.structures.parser.lang;
|
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;
|
package com.dfsek.terra.api.structures.parser.lang;
|
||||||
|
|
||||||
public interface Function<T> extends Expression<T> {
|
public interface Function<T> extends Executable<T> {
|
||||||
|
|
||||||
String name();
|
String name();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.dfsek.terra.api.structures.parser.lang;
|
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
|
* Function identifier or language keyword
|
||||||
*/
|
*/
|
||||||
IDENTIFIER,
|
IDENTIFIER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Language keyword
|
||||||
|
*/
|
||||||
|
KEYWORD,
|
||||||
/**
|
/**
|
||||||
* Numeric literal
|
* Numeric literal
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import java.util.Set;
|
|||||||
public class Tokenizer {
|
public class Tokenizer {
|
||||||
private final Lookahead reader;
|
private final Lookahead reader;
|
||||||
|
|
||||||
private final Set<Character> syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', ',', '\\', '=', // Currently used chars
|
private final Set<Character> syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', ',', '\\', '=', '{', '}', '+'); // Reserved chars
|
||||||
'{', '}'); // Reserved chars
|
private final Set<String> keywords = Sets.newHashSet("if", "return");
|
||||||
|
|
||||||
|
|
||||||
public Tokenizer(String data) {
|
public Tokenizer(String data) {
|
||||||
@@ -38,6 +38,8 @@ public class Tokenizer {
|
|||||||
return new Token("false", Token.Type.BOOLEAN, new Position(reader.getLine(), reader.getIndex()));
|
return new Token("false", Token.Type.BOOLEAN, new Position(reader.getLine(), reader.getIndex()));
|
||||||
if(reader.matches("==", true))
|
if(reader.matches("==", true))
|
||||||
return new Token("==", Token.Type.BOOLEAN_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
|
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()) {
|
if(isNumberStart()) {
|
||||||
StringBuilder num = new StringBuilder();
|
StringBuilder num = new StringBuilder();
|
||||||
@@ -90,7 +92,7 @@ public class Tokenizer {
|
|||||||
String tokenString = token.toString();
|
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() {
|
private boolean isNumberLike() {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import java.util.List;
|
|||||||
public class ParserTest {
|
public class ParserTest {
|
||||||
@Test
|
@Test
|
||||||
public void parse() throws IOException, ParseException {
|
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>() {
|
parser.addFunction("test", new FunctionBuilder<Test1>() {
|
||||||
@Override
|
@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