mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-04 23:06:05 +00:00
more parsing reworks
This commit is contained in:
@@ -1,12 +0,0 @@
|
||||
package com.dfsek.terra.api.structures.parser;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Function;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface FunctionBuilder<T extends Function<?>> {
|
||||
T build(List<String> argumentList) throws ParseException;
|
||||
|
||||
int getArguments();
|
||||
}
|
||||
@@ -3,14 +3,14 @@ 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.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.Returnable;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
|
||||
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.parser.lang.operations.BooleanNotOperation;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
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;
|
||||
@@ -22,7 +22,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Parser {
|
||||
private final String data;
|
||||
@@ -54,7 +53,7 @@ public class Parser {
|
||||
for(Token t : tokens) {
|
||||
if(t.getType().equals(Token.Type.BLOCK_BEGIN)) blockLevel++;
|
||||
else if(t.getType().equals(Token.Type.BLOCK_END)) blockLevel--;
|
||||
if(blockLevel < 0) throw new ParseException("Dangling closing brace: " + t.getStart());
|
||||
if(blockLevel < 0) throw new ParseException("Dangling closing brace: " + t.getPosition());
|
||||
}
|
||||
if(blockLevel != 0) throw new ParseException("Dangling opening brace");
|
||||
|
||||
@@ -62,52 +61,67 @@ public class Parser {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Keyword<?> parseKeyword(List<Token> tokens) throws ParseException {
|
||||
|
||||
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());
|
||||
throw new ParseException("No such keyword " + identifier.getContent() + ": " + identifier.getPosition());
|
||||
Keyword<?> k = null;
|
||||
if(identifier.getContent().equals("if")) {
|
||||
|
||||
checkType(tokens.remove(0), Token.Type.BODY_BEGIN);
|
||||
|
||||
Executable<?> left = parseExpression(tokens);
|
||||
|
||||
Statement statement = null;
|
||||
Token comparator = tokens.remove(0);
|
||||
checkType(comparator, Token.Type.BOOLEAN_OPERATOR);
|
||||
|
||||
Executable<?> right = parseExpression(tokens);
|
||||
Returnable<?> comparator = parseExpression(tokens);
|
||||
checkReturnType(comparator, Returnable.ReturnType.BOOLEAN);
|
||||
|
||||
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);
|
||||
k = new IfKeyword(parseBlock(tokens), (Returnable<Boolean>) comparator, identifier.getPosition());
|
||||
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
private Executable<?> parseExpression(List<Token> tokens) throws ParseException {
|
||||
@SuppressWarnings("unchecked")
|
||||
private Returnable<?> parseExpression(List<Token> tokens) throws ParseException {
|
||||
System.out.println(tokens.get(0));
|
||||
Token first = tokens.get(0);
|
||||
checkType(first, Token.Type.IDENTIFIER, Token.Type.BOOLEAN, Token.Type.STRING, Token.Type.NUMBER, Token.Type.BOOLEAN_NOT);
|
||||
|
||||
boolean not = false;
|
||||
if(first.getType().equals(Token.Type.BOOLEAN_NOT)) {
|
||||
not = true;
|
||||
tokens.remove(0);
|
||||
}
|
||||
|
||||
Returnable<?> expression;
|
||||
if(tokens.get(0).isConstant()) {
|
||||
return new ConstantExpression<>(tokens.remove(0).getContent());
|
||||
} else return parseFunction(tokens, false);
|
||||
Object constant;
|
||||
Position position = tokens.get(0).getPosition();
|
||||
if(tokens.get(0).getType().equals(Token.Type.BOOLEAN)) constant = Boolean.parseBoolean(tokens.remove(0).getContent());
|
||||
else constant = tokens.remove(0).getContent();
|
||||
expression = new ConstantExpression<>(constant, position);
|
||||
} else expression = parseFunction(tokens, false);
|
||||
|
||||
if(not) {
|
||||
checkReturnType(expression, Returnable.ReturnType.BOOLEAN);
|
||||
return new BooleanNotOperation((Returnable<Boolean>) expression, expression.getPosition());
|
||||
} else return expression;
|
||||
}
|
||||
|
||||
private Block parseBlock(List<Token> tokens) throws ParseException {
|
||||
List<Item<?>> parsedItems = new GlueList<>();
|
||||
Token first = tokens.get(0);
|
||||
|
||||
checkType(tokens.get(0), Token.Type.IDENTIFIER, Token.Type.KEYWORD);
|
||||
main:
|
||||
while(tokens.size() > 0) {
|
||||
Token token = tokens.get(0);
|
||||
System.out.println(token);
|
||||
checkType(token, Token.Type.IDENTIFIER, Token.Type.KEYWORD, Token.Type.BLOCK_END);
|
||||
switch(token.getType()) {
|
||||
case KEYWORD:
|
||||
@@ -125,7 +139,7 @@ public class Parser {
|
||||
break main;
|
||||
}
|
||||
}
|
||||
return new Block(parsedItems);
|
||||
return new Block(parsedItems, first.getPosition());
|
||||
}
|
||||
|
||||
private Function<?> parseFunction(List<Token> tokens, boolean fullStatement) throws ParseException {
|
||||
@@ -133,46 +147,42 @@ public class Parser {
|
||||
checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
|
||||
|
||||
if(!functions.containsKey(identifier.getContent()))
|
||||
throw new ParseException("No such function " + identifier.getContent() + ": " + identifier.getStart());
|
||||
throw new ParseException("No such function " + identifier.getContent() + ": " + identifier.getPosition());
|
||||
|
||||
checkType(tokens.remove(0), Token.Type.BODY_BEGIN); // Second is body begin
|
||||
|
||||
|
||||
List<Token> args = getArgs(tokens); // Extract arguments, consume the rest.
|
||||
List<Returnable<?>> args = getArgs(tokens); // Extract arguments, consume the rest.
|
||||
|
||||
tokens.remove(0); // Remove body end
|
||||
|
||||
if(fullStatement) checkType(tokens.get(0), Token.Type.STATEMENT_END);
|
||||
|
||||
List<String> arg = args.stream().map(Token::getContent).collect(Collectors.toList());
|
||||
|
||||
FunctionBuilder<?> builder = functions.get(identifier.getContent());
|
||||
if(arg.size() != builder.getArguments() && builder.getArguments() != -1)
|
||||
throw new ParseException("Expected " + builder.getArguments() + " arguments, found " + arg.size() + ": " + identifier.getStart());
|
||||
return functions.get(identifier.getContent()).build(arg);
|
||||
if(args.size() != builder.getArguments() && builder.getArguments() != -1)
|
||||
throw new ParseException("Expected " + builder.getArguments() + " arguments, found " + args.size() + ": " + identifier.getPosition());
|
||||
return functions.get(identifier.getContent()).build(args, identifier.getPosition());
|
||||
}
|
||||
|
||||
private List<Token> getArgs(List<Token> functionBuilder) throws ParseException {
|
||||
List<Token> args = new GlueList<>();
|
||||
boolean expectingSeparator = false;
|
||||
|
||||
while(!functionBuilder.get(0).getType().equals(Token.Type.BODY_END)) {
|
||||
Token current = functionBuilder.remove(0);
|
||||
if(expectingSeparator) {
|
||||
checkType(current, Token.Type.SEPARATOR);
|
||||
expectingSeparator = false;
|
||||
} else {
|
||||
if(!allowedArguments.contains(current.getType()))
|
||||
throw new ParseException("Token type " + current.getType() + " not allowed in arguments: " + current.getStart());
|
||||
args.add(current);
|
||||
expectingSeparator = true;
|
||||
}
|
||||
private List<Returnable<?>> getArgs(List<Token> tokens) throws ParseException {
|
||||
List<Returnable<?>> args = new GlueList<>();
|
||||
|
||||
while(!tokens.get(0).getType().equals(Token.Type.BODY_END)) {
|
||||
args.add(parseExpression(tokens));
|
||||
checkType(tokens.get(0), Token.Type.SEPARATOR, Token.Type.BODY_END);
|
||||
if(tokens.get(0).getType().equals(Token.Type.SEPARATOR)) tokens.remove(0);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
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());
|
||||
throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType() + ": " + token.getPosition());
|
||||
}
|
||||
|
||||
private void checkReturnType(Returnable<?> returnable, Returnable.ReturnType... types) throws ParseException {
|
||||
for(Returnable.ReturnType type : types) if(returnable.returnType().equals(type)) return;
|
||||
throw new ParseException("Expected " + Arrays.toString(types) + " but found " + returnable.returnType() + ": " + returnable.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,17 @@ package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Block implements Item<Void> {
|
||||
private final List<Item<?>> items;
|
||||
private final Position position;
|
||||
|
||||
public Block(List<Item<?>> items) {
|
||||
public Block(List<Item<?>> items, Position position) {
|
||||
this.items = items;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public List<Item<?>> getItems() {
|
||||
@@ -27,4 +30,9 @@ public class Block implements Item<Void> {
|
||||
items.forEach(item -> item.apply(location, chunk));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,15 @@ package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class ConstantExpression<T> implements Executable<T> {
|
||||
public class ConstantExpression<T> implements Returnable<T> {
|
||||
private final T constant;
|
||||
private final Position position;
|
||||
|
||||
public ConstantExpression(T constant) {
|
||||
public ConstantExpression(T constant, Position position) {
|
||||
this.constant = constant;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -21,6 +24,15 @@ public class ConstantExpression<T> implements Executable<T> {
|
||||
return constant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public T getConstant() {
|
||||
return constant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
if(constant instanceof String) return ReturnType.STRING;
|
||||
|
||||
@@ -3,18 +3,21 @@ package com.dfsek.terra.api.structures.parser.lang;
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.BinaryOperation;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class Expression<T> implements Executable<T> {
|
||||
public class Expression<T> implements Returnable<T> {
|
||||
private final ReturnType type;
|
||||
private final Executable<T> left;
|
||||
private final Executable<T> right;
|
||||
private final Returnable<T> left;
|
||||
private final Returnable<T> right;
|
||||
private final BinaryOperation<T> operation;
|
||||
private final Position position;
|
||||
|
||||
public Expression(ReturnType type, Executable<T> left, Executable<T> right, BinaryOperation<T> operation) {
|
||||
public Expression(ReturnType type, Returnable<T> left, Returnable<T> right, BinaryOperation<T> operation, Position position) {
|
||||
this.type = type;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.operation = operation;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -31,4 +34,9 @@ public class Expression<T> implements Executable<T> {
|
||||
public T apply(Location location, Chunk chunk) {
|
||||
return operation.apply(left.apply(location, chunk), right.apply(location, chunk));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
public interface Function<T> extends Executable<T> {
|
||||
String name();
|
||||
}
|
||||
@@ -2,9 +2,12 @@ package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public interface Item<T> {
|
||||
T apply(Location location);
|
||||
|
||||
T apply(Location location, Chunk chunk);
|
||||
|
||||
Position getPosition();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
public interface Keyword<T> extends Executable<T> {
|
||||
public interface Keyword<T> extends Returnable<T> {
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
public interface Executable<T> extends Item<T> {
|
||||
public interface Returnable<T> extends Item<T> {
|
||||
ReturnType returnType();
|
||||
|
||||
enum ReturnType {
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.functions;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
|
||||
public interface Function<T> extends Returnable<T> {
|
||||
String name();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.functions;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface FunctionBuilder<T extends Function<?>> {
|
||||
T build(List<Returnable<?>> argumentList, Position position) throws ParseException;
|
||||
|
||||
int getArguments();
|
||||
}
|
||||
@@ -4,15 +4,18 @@ import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
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.Statement;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class IfKeyword implements Keyword<Void> {
|
||||
private final Block conditional;
|
||||
private final Statement statement;
|
||||
private final Returnable<Boolean> statement;
|
||||
private final Position position;
|
||||
|
||||
public IfKeyword(Block conditional, Statement statement) {
|
||||
public IfKeyword(Block conditional, Returnable<Boolean> statement, Position position) {
|
||||
this.conditional = conditional;
|
||||
this.statement = statement;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -27,6 +30,11 @@ public class IfKeyword implements Keyword<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.VOID;
|
||||
|
||||
@@ -3,8 +3,15 @@ package com.dfsek.terra.api.structures.parser.lang.keywords;
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Keyword;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class ReturnKeyword implements Keyword<Void> {
|
||||
private final Position position;
|
||||
|
||||
public ReturnKeyword(Position position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void apply(Location location) {
|
||||
return null;
|
||||
@@ -15,6 +22,11 @@ public class ReturnKeyword implements Keyword<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.VOID;
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.operations;
|
||||
|
||||
public interface BinaryOperation<T> {
|
||||
T apply(T left, T right);
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public abstract class BinaryOperation<T> implements Returnable<T> {
|
||||
private final Returnable<T> left;
|
||||
private final Returnable<T> right;
|
||||
private final Position start;
|
||||
|
||||
protected BinaryOperation(Returnable<T> left, Returnable<T> right, Position start) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public abstract T apply(T left, T right);
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(Location location) {
|
||||
return apply(left.apply(location), right.apply(location));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(Location location, Chunk chunk) {
|
||||
return apply(left.apply(location, chunk), right.apply(location, chunk));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class BooleanNotOperation extends UnaryOperation<Boolean> {
|
||||
public BooleanNotOperation(Returnable<Boolean> input, Position position) {
|
||||
super(input, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(Boolean input) {
|
||||
return !input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.BOOLEAN;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,20 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.operations;
|
||||
|
||||
public class ConcatenationOperation implements BinaryOperation<Object> {
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class ConcatenationOperation extends BinaryOperation<Object> {
|
||||
protected ConcatenationOperation(Returnable<Object> left, Returnable<Object> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(Object left, Object right) {
|
||||
return left.toString() + right.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.STRING;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class MultiplicationOperation extends BinaryOperation<Number> {
|
||||
protected MultiplicationOperation(Returnable<Number> left, Returnable<Number> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number apply(Number left, Number right) {
|
||||
return left.doubleValue() * right.doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.NUMBER;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,20 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.operations;
|
||||
|
||||
public class NumberAdditionOperation implements BinaryOperation<Number> {
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class NumberAdditionOperation extends BinaryOperation<Number> {
|
||||
protected NumberAdditionOperation(Returnable<Number> left, Returnable<Number> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number apply(Number left, Number right) {
|
||||
return left.doubleValue() + right.doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public abstract class UnaryOperation<T> implements Returnable<T> {
|
||||
private final Returnable<T> input;
|
||||
private final Position position;
|
||||
|
||||
protected UnaryOperation(Returnable<T> input, Position position) {
|
||||
this.input = input;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public abstract T apply(T input);
|
||||
|
||||
@Override
|
||||
public T apply(Location location) {
|
||||
return apply(input.apply(location));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(Location location, Chunk chunk) {
|
||||
return apply(input.apply(location, chunk));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,17 @@ 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;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class EqualsStatement implements Statement {
|
||||
private final Item<?> left;
|
||||
private final Item<?> right;
|
||||
private final Position position;
|
||||
|
||||
public EqualsStatement(Item<?> left, Item<?> right) {
|
||||
public EqualsStatement(Item<?> left, Item<?> right, Position position) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -23,4 +26,9 @@ public class EqualsStatement implements Statement {
|
||||
public Boolean apply(Location location, Chunk chunk) {
|
||||
return left.apply(location, chunk).equals(right.apply(location, chunk));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,17 @@ 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;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class GreaterThanStatement<T extends Comparable<T>> implements Statement {
|
||||
private final Item<T> left;
|
||||
private final Item<T> right;
|
||||
private final Position position;
|
||||
|
||||
public GreaterThanStatement(Item<T> left, Item<T> right) {
|
||||
public GreaterThanStatement(Item<T> left, Item<T> right, Position position) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -23,4 +26,9 @@ public class GreaterThanStatement<T extends Comparable<T>> implements Statement
|
||||
public Boolean apply(Location location, Chunk chunk) {
|
||||
return left.apply(location).compareTo(right.apply(location)) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,17 @@ 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;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class NotEqualsStatement implements Statement {
|
||||
private final Item<?> left;
|
||||
private final Item<?> right;
|
||||
private final Position position;
|
||||
|
||||
public NotEqualsStatement(Item<?> left, Item<?> right) {
|
||||
public NotEqualsStatement(Item<?> left, Item<?> right, Position position) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -23,4 +26,9 @@ public class NotEqualsStatement implements Statement {
|
||||
public Boolean apply(Location location, Chunk chunk) {
|
||||
return !left.apply(location, chunk).equals(right.apply(location, chunk));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.dfsek.terra.api.structures.script.builders;
|
||||
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.structures.parser.FunctionBuilder;
|
||||
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.api.structures.script.functions.BlockFunction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BlockFunctionBuilder implements FunctionBuilder<BlockFunction> {
|
||||
private final TerraPlugin main;
|
||||
|
||||
public BlockFunctionBuilder(TerraPlugin main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockFunction build(List<String> argumentList) throws ParseException {
|
||||
return new BlockFunction(Integer.parseInt(argumentList.get(0)), Integer.parseInt(argumentList.get(1)), Integer.parseInt(argumentList.get(2)), main.getWorldHandle().createBlockData(argumentList.get(3)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArguments() {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.dfsek.terra.api.structures.script.builders;
|
||||
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.structures.parser.FunctionBuilder;
|
||||
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.api.structures.script.functions.CheckFunction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SpawnCheckBuilder implements FunctionBuilder<CheckFunction> {
|
||||
private final TerraPlugin main;
|
||||
|
||||
public SpawnCheckBuilder(TerraPlugin main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CheckFunction build(List<String> argumentList) throws ParseException {
|
||||
return new CheckFunction(main, Integer.parseInt(argumentList.get(0)), Integer.parseInt(argumentList.get(1)), Integer.parseInt(argumentList.get(2)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArguments() {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,24 @@
|
||||
package com.dfsek.terra.api.structures.script.functions;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Function;
|
||||
import com.dfsek.terra.api.structures.parser.lang.ConstantExpression;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class BlockFunction implements Function<Void> {
|
||||
private final BlockData data;
|
||||
private final int x, y, z;
|
||||
private final Returnable<Integer> x, y, z;
|
||||
private final Position position;
|
||||
|
||||
public BlockFunction(int x, int y, int z, BlockData data) {
|
||||
this.data = data;
|
||||
public BlockFunction(Returnable<Integer> x, Returnable<Integer> y, Returnable<Integer> z, Returnable<String> data, TerraPlugin main, Position position) {
|
||||
this.position = position;
|
||||
if(!(data instanceof ConstantExpression)) throw new IllegalArgumentException("Block data must be constant.");
|
||||
|
||||
this.data = main.getWorldHandle().createBlockData(((ConstantExpression<String>) data).getConstant());
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
@@ -23,7 +31,7 @@ public class BlockFunction implements Function<Void> {
|
||||
|
||||
@Override
|
||||
public Void apply(Location location) {
|
||||
location.clone().add(x, y, z).getBlock().setBlockData(data, false);
|
||||
location.clone().add(x.apply(location), y.apply(location), z.apply(location)).getBlock().setBlockData(data, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -33,6 +41,11 @@ public class BlockFunction implements Function<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.VOID;
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
package com.dfsek.terra.api.structures.script.functions;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Function;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
import com.dfsek.terra.api.structures.world.LandCheck;
|
||||
import com.dfsek.terra.api.structures.world.OceanCheck;
|
||||
|
||||
public class CheckFunction implements Function<String> {
|
||||
private final TerraPlugin main;
|
||||
private final int x, y, z;
|
||||
private final Returnable<Integer> x, y, z;
|
||||
private final Position position;
|
||||
|
||||
public CheckFunction(TerraPlugin main, int x, int y, int z) {
|
||||
public CheckFunction(TerraPlugin main, Returnable<Integer> x, Returnable<Integer> y, Returnable<Integer> z, Position position) {
|
||||
this.main = main;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -23,22 +29,32 @@ public class CheckFunction implements Function<String> {
|
||||
return "check";
|
||||
}
|
||||
|
||||
private Vector3 getVector(Location location, Chunk chunk) {
|
||||
return chunk == null ? new Vector3(x.apply(location) + location.getBlockX(), y.apply(location) + location.getBlockY(), z.apply(location) + location.getBlockZ())
|
||||
: new Vector3(x.apply(location, chunk) + location.getBlockX(), y.apply(location, chunk) + location.getBlockY(), z.apply(location, chunk) + location.getBlockZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(Location location) {
|
||||
if(new LandCheck(location.getWorld(), main).check(location.getBlockX() + x, location.getBlockY() + y, location.getBlockZ() + z))
|
||||
return apply(getVector(location, null), location.getWorld());
|
||||
}
|
||||
|
||||
private String apply(Vector3 vector, World world) {
|
||||
if(new LandCheck(world, main).check(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()))
|
||||
return "LAND";
|
||||
if(new OceanCheck(location.getWorld(), main).check(location.getBlockX() + x, location.getBlockY() + y, location.getBlockZ() + z))
|
||||
if(new OceanCheck(world, main).check(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()))
|
||||
return "OCEAN";
|
||||
return "AIR";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(Location location, Chunk chunk) {
|
||||
if(new LandCheck(location.getWorld(), main).check(location.getBlockX() + x, location.getBlockY() + y, location.getBlockZ() + z))
|
||||
return "LAND";
|
||||
if(new OceanCheck(location.getWorld(), main).check(location.getBlockX() + x, location.getBlockY() + y, location.getBlockZ() + z))
|
||||
return "OCEAN";
|
||||
return "AIR";
|
||||
return apply(getVector(location, chunk), location.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,7 +19,7 @@ public class Token {
|
||||
return content;
|
||||
}
|
||||
|
||||
public Position getStart() {
|
||||
public Position getPosition() {
|
||||
return start;
|
||||
}
|
||||
|
||||
@@ -89,6 +89,22 @@ public class Token {
|
||||
/**
|
||||
* Addition/concatenation operator
|
||||
*/
|
||||
ADDITION_OPERATOR
|
||||
ADDITION_OPERATOR,
|
||||
/**
|
||||
* Subtraction operator
|
||||
*/
|
||||
SUBTRACTION_OPERATOR,
|
||||
/**
|
||||
* Multiplication operator
|
||||
*/
|
||||
MULTIPLICATION_OPERATOR,
|
||||
/**
|
||||
* Division operator
|
||||
*/
|
||||
DIVISION_OPERATOR,
|
||||
/**
|
||||
* Boolean not operator
|
||||
*/
|
||||
BOOLEAN_NOT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import java.util.Set;
|
||||
public class Tokenizer {
|
||||
private final Lookahead reader;
|
||||
|
||||
private final Set<Character> syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', ',', '\\', '=', '{', '}', '+'); // Reserved chars
|
||||
private final Set<Character> syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', ',', '\\', '=', '{', '}', '+', '-', '*', '/', '>', '<', '!'); // Reserved chars
|
||||
private final Set<String> keywords = Sets.newHashSet("if", "return");
|
||||
|
||||
|
||||
@@ -36,10 +36,21 @@ public class Tokenizer {
|
||||
return new Token("true", Token.Type.BOOLEAN, new Position(reader.getLine(), reader.getIndex()));
|
||||
if(reader.matches("false", true))
|
||||
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(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(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();
|
||||
@@ -84,6 +95,14 @@ public class Tokenizer {
|
||||
return new Token(reader.consume().toString(), Token.Type.ASSIGNMENT, new Position(reader.getLine(), reader.getIndex()));
|
||||
if(reader.current().is('+'))
|
||||
return new Token(reader.consume().toString(), Token.Type.ADDITION_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
|
||||
if(reader.current().is('-'))
|
||||
return new Token(reader.consume().toString(), Token.Type.SUBTRACTION_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
|
||||
if(reader.current().is('*'))
|
||||
return new Token(reader.consume().toString(), Token.Type.MULTIPLICATION_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
|
||||
if(reader.current().is('/'))
|
||||
return new Token(reader.consume().toString(), Token.Type.DIVISION_OPERATOR, new Position(reader.getLine(), reader.getIndex()));
|
||||
if(reader.current().is('!'))
|
||||
return new Token(reader.consume().toString(), Token.Type.BOOLEAN_NOT, new Position(reader.getLine(), reader.getIndex()));
|
||||
|
||||
StringBuilder token = new StringBuilder();
|
||||
while(!reader.current().isEOF() && !isSyntaxSignificant(reader.current().getCharacter())) {
|
||||
|
||||
@@ -2,11 +2,13 @@ package structure;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.structures.parser.FunctionBuilder;
|
||||
import com.dfsek.terra.api.structures.parser.Parser;
|
||||
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
|
||||
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.Returnable;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -20,8 +22,8 @@ public class ParserTest {
|
||||
|
||||
parser.addFunction("test", new FunctionBuilder<Test1>() {
|
||||
@Override
|
||||
public Test1 build(List<String> argumentList) throws ParseException {
|
||||
return new Test1(argumentList.get(0), Double.parseDouble(argumentList.get(1)));
|
||||
public Test1 build(List<Returnable<?>> argumentList, Position position) throws ParseException {
|
||||
return new Test1(argumentList.get(0).apply(new Location(null, 0, 0, 0)).toString(), Double.parseDouble(argumentList.get(1).apply(new Location(null, 0, 0, 0)).toString()), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,10 +43,12 @@ public class ParserTest {
|
||||
private static class Test1 implements Function<Void> {
|
||||
private final String a;
|
||||
private final double b;
|
||||
private final Position position;
|
||||
|
||||
public Test1(String a, double b) {
|
||||
public Test1(String a, double b, Position position) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public String getA() {
|
||||
@@ -65,6 +69,11 @@ public class ParserTest {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return null;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
test("hello", 2);
|
||||
|
||||
if(test("fsdfsdf", 3) == 2) {
|
||||
if("true") {
|
||||
test("fdsgdf", 3.4);
|
||||
if(test("fsdfsdf", 3) == 2) {
|
||||
test("fdsgdf", 3.4);
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.structures.parser.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.script.builders.BlockFunctionBuilder;
|
||||
import com.dfsek.terra.api.structures.script.builders.SpawnCheckBuilder;
|
||||
import com.dfsek.terra.bukkit.BukkitWorld;
|
||||
import com.dfsek.terra.bukkit.command.DebugCommand;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -39,8 +37,6 @@ public class LoadRawCommand extends LoadCommand implements DebugCommand {
|
||||
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String s, @NotNull String[] args) {
|
||||
try {
|
||||
Parser parser = new Parser(IOUtils.toString(new FileInputStream(new File(getMain().getDataFolder(), "test.tesf"))));
|
||||
parser.addFunction("block", new BlockFunctionBuilder(getMain()));
|
||||
parser.addFunction("check", new SpawnCheckBuilder(getMain()));
|
||||
Block main = parser.parse();
|
||||
main.apply(new Location(new BukkitWorld(sender.getWorld()), sender.getLocation().getX(), sender.getLocation().getY(), sender.getLocation().getZ()));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user