396 lines
16 KiB
Java
396 lines
16 KiB
Java
package dev.peerat.parser.java.tree;
|
|
|
|
import java.lang.reflect.Field;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.ListIterator;
|
|
import java.util.function.BiConsumer;
|
|
import java.util.function.BiFunction;
|
|
import java.util.function.Consumer;
|
|
|
|
import dev.peerat.parser.Bag;
|
|
import dev.peerat.parser.Token;
|
|
import dev.peerat.parser.TokenType;
|
|
import dev.peerat.parser.java.JavaElement;
|
|
import dev.peerat.parser.java.value.ArrayAccessValue;
|
|
import dev.peerat.parser.java.value.ArrayValue;
|
|
import dev.peerat.parser.java.value.BiValue;
|
|
import dev.peerat.parser.java.value.CastValue;
|
|
import dev.peerat.parser.java.value.InstanceValue;
|
|
import dev.peerat.parser.java.value.LambdaValue;
|
|
import dev.peerat.parser.java.value.LambdaValue.LambdaParameter;
|
|
import dev.peerat.parser.java.value.MethodCallValue;
|
|
import dev.peerat.parser.java.value.ModifierValue;
|
|
import dev.peerat.parser.java.value.StaticValue;
|
|
import dev.peerat.parser.java.value.TriValue;
|
|
import dev.peerat.parser.java.value.Value;
|
|
import dev.peerat.parser.java.value.Value.ValueContainer;
|
|
import dev.peerat.parser.java.value.VariableAccessValue;
|
|
import dev.peerat.parser.state.RedirectStateTree;
|
|
import dev.peerat.parser.state.StateTree;
|
|
import dev.peerat.parser.tree.SyntaxTree;
|
|
import dev.peerat.parser.tree.SyntaxTreeRegistery;
|
|
|
|
public class ValueTree extends SyntaxTree<JavaElement> { //TODO order tree by more used branch ? to not check a whole tree to go on the last branch...
|
|
|
|
public ValueTree(SyntaxTreeRegistery<JavaElement> registery) {
|
|
super(registery);
|
|
this.current = new StateTree<>();
|
|
}
|
|
|
|
@Override
|
|
public void init(){
|
|
StateTree<JavaElement> type = this.registery.getNode(TypeTree.class);
|
|
StateTree<JavaElement> function_container = this.registery.getNode(FunctionContainerTree.class);
|
|
StateTree<JavaElement> class_container = this.registery.getNode(ClassContainerTree.class);
|
|
// VALUE
|
|
StateTree<JavaElement> value = this.current.then((validator) -> {
|
|
validator.getBag().set(new ValueChainBuilder());
|
|
return true;
|
|
});
|
|
StateTree<JavaElement> unary_value = new StateTree<>();
|
|
StateTree<JavaElement> value_operation = new StateTree<>();
|
|
|
|
StateTree<JavaElement> redirectRight = new RedirectStateTree<>(this.current, (global, local) -> {
|
|
global.<ValueChainBuilder>get().right(local.get());
|
|
});
|
|
|
|
//TODO -> Array and dot after a new Instance...event with {}
|
|
StateTree<JavaElement> value_instance = unary_value.equals("new");
|
|
StateTree<JavaElement> value_instance_type = value_instance.redirect(type, (global, local) -> global.set("type", local.get()));
|
|
StateTree<JavaElement> value_instance_params = value_instance_type.equals("(");
|
|
StateTree<JavaElement> value_instance_params_end = value_instance_params.equals(")", (bag, token) -> {
|
|
ValueChainBuilder builder = new ValueChainBuilder();
|
|
List<Value> parameters = bag.get("params");
|
|
builder.rebase(new InstanceValue(bag.get("type"), parameters == null ? new ArrayList<>() : parameters));
|
|
bag.remove("type");
|
|
bag.remove("params");
|
|
bag.set(builder);
|
|
});
|
|
StateTree<JavaElement> value_instance_param = value_instance_params.redirect(this.current, (global, local) -> {
|
|
List<Value> list = global.get("params");
|
|
if(list == null){
|
|
list = new ArrayList<>();
|
|
global.set("params", list);
|
|
}
|
|
list.add(local.get());
|
|
});
|
|
value_instance_param.then(value_instance_params_end);
|
|
value_instance_param.equals(",").then(value_instance_param);
|
|
value_instance_params_end.<JavaElement>end(ValueChainBuilder.build(false));
|
|
value_instance_params_end.equals("{")
|
|
.<JavaElement>end(ValueChainBuilder.build(true)).multiple(class_container)
|
|
.unique((validator) -> validator.validate((token) -> token.getValue().equals("}"))).end();
|
|
|
|
StateTree<JavaElement> value_instance_array = value_instance_type.equals("[");
|
|
StateTree<JavaElement> value_instance_array_value = value_instance_array.redirect(this.current);
|
|
StateTree<JavaElement> value_instance_array_end = value_instance_array_value.equals("]");
|
|
value_instance_array.then(value_instance_array_end);
|
|
value_instance_array_end.end();
|
|
value_instance_array_end.then(value_instance_array);
|
|
|
|
StateTree<JavaElement> value_instance_array_init = value_instance_array_end.equals("{");
|
|
StateTree<JavaElement> value_instance_array_init_value = value_instance_array_init.redirect(this.current, (global, local) -> {
|
|
List<Value> list = global.get("array");
|
|
if(list == null){
|
|
list = new ArrayList<>();
|
|
global.set("array", list);
|
|
}
|
|
list.add(local.get());
|
|
});
|
|
value.equals("{").then(value_instance_array_init_value);
|
|
value_instance_array_init_value.equals(",").then(value_instance_array_init_value);
|
|
StateTree<JavaElement> value_instance_array_value_end = value_instance_array_init_value.equals("}");
|
|
value_instance_array_value_end.end((parent, bag) -> {
|
|
ArrayValue result = new ArrayValue(bag.<List<Value>>get("array").toArray(new Value[0]));
|
|
bag.set(result);
|
|
if(parent instanceof ValueContainer) ((ValueContainer)parent).addValue(result);
|
|
return null;
|
|
});
|
|
|
|
StateTree<JavaElement> value_name = unary_value.then((validator) -> {
|
|
validator.getBag().set(new ValueChainBuilder());
|
|
return true;
|
|
})
|
|
.then((validator) -> validator.validate((token) -> token.getType().equals(TokenType.NAME),
|
|
(bag, token) ->{
|
|
bag.<ValueChainBuilder>get().nameValue(token);
|
|
}));
|
|
value_name.end(ValueChainBuilder.build((builder) -> builder.dot(), false));
|
|
value_name.then(value_operation);
|
|
|
|
value_instance_array_value_end.equals(".", (bag, token) -> { bag.<ValueChainBuilder>get().rebase(new ArrayValue(bag.<List<Value>>get("array").toArray(new Value[0]))); bag.remove("array"); }).then(value_name);
|
|
|
|
unary_value.then((validator) -> {
|
|
validator.getBag().set(new ValueChainBuilder());
|
|
return true;
|
|
}).then((validator) -> validator.validate(
|
|
(token) -> token.getType().equals(TokenType.STRING) || token.getType().equals(TokenType.CHAR),
|
|
(bag, token) -> bag.<ValueChainBuilder>get().constantValue(token)))
|
|
.end(ValueChainBuilder.build((builder) -> builder.buildStatic(), false));
|
|
|
|
value_operation.equals(">", action(">")).then(redirectRight).end(ValueChainBuilder.build((builder) -> builder.buildOperation(), false));
|
|
value_operation.equals("=", action("=")).then(redirectRight).end(ValueChainBuilder.build((builder) -> builder.buildOperation(), false));
|
|
value_operation.equals("<",action("<")).then(redirectRight).end(ValueChainBuilder.build((builder) -> builder.buildOperation(), false));
|
|
value_operation.equals("<",action("<")).equals("<","action","<<").then(redirectRight).end(ValueChainBuilder.build((builder) -> builder.buildOperation(), false));
|
|
value_operation.equals("+",action("+")).then(redirectRight).end(ValueChainBuilder.build((builder) -> builder.buildOperation(), false));
|
|
StateTree<JavaElement> value_operation_bit_and = value_operation.equals("&",action("&"));
|
|
value_operation_bit_and.then(redirectRight).end(ValueChainBuilder.build((builder) -> builder.buildOperation(), false));
|
|
value_operation_bit_and.equals("&",action("&&")).then(redirectRight).end(ValueChainBuilder.build((builder) -> builder.buildOperation(), false));
|
|
StateTree<JavaElement> value_operation_bit_or = value_operation.equals("|",action("|"));
|
|
value_operation_bit_or.then(redirectRight).end(ValueChainBuilder.build((builder) -> builder.buildOperation(), false));
|
|
value_operation_bit_or.equals("|",action("||")).then(redirectRight).end(ValueChainBuilder.build((builder) -> builder.buildOperation(), false));
|
|
|
|
value.equals("!",modifier()).redirect(this.current, (global, local) -> global.<ValueChainBuilder>get().rebase(local.get())).end(ValueChainBuilder.build((builder) -> builder.buildModifier(), false));
|
|
|
|
StateTree<JavaElement> left_value = value.redirect(unary_value, (global, local) -> { if(local.get() instanceof ValueChainBuilder) { global.set(local.get()); global.<ValueChainBuilder>get().extractLambda(); return;} global.<ValueChainBuilder>get().rebase(local.get());});
|
|
left_value.end(ValueChainBuilder.build(true));
|
|
left_value.equals("?")
|
|
.redirect(this.current, (global, local) -> global.set("success", local.get()))
|
|
.equals(":")
|
|
.redirect(this.current, (global, local) -> global.set("fail", local.get()))
|
|
.end((parent, bag) -> {
|
|
bag.set(new TriValue(bag.<ValueChainBuilder>get().base, bag.get("success"), bag.get("fail")));
|
|
if(parent instanceof ValueContainer) ((ValueContainer)parent).addValue(bag.get());
|
|
return null;
|
|
});
|
|
|
|
StateTree<JavaElement> value_array = left_value.equals("[");
|
|
StateTree<JavaElement> value_array_value = value_array.redirect(this.current, (global, local) -> global.<ValueChainBuilder>get().arrayAccess(local.get()));
|
|
StateTree<JavaElement> value_array_end = value_array_value.equals("]");
|
|
value_array_end.end(ValueChainBuilder.build(false));
|
|
value_array_end.then(value_array);
|
|
value_array_end.equals(".", (bag, token) -> bag.<ValueChainBuilder>get().dot()).then(value_name);
|
|
|
|
value_instance_array_value_end.then(value_array);
|
|
|
|
StateTree<JavaElement> operation_call = value_name.equals(".", (bag, token) -> bag.<ValueChainBuilder>get().dot());
|
|
operation_call.then(value_name);
|
|
StateTree<JavaElement> operation_begin = value_name.equals("(", (bag, token) -> bag.<ValueChainBuilder>get().parameter());
|
|
StateTree<JavaElement> operation_end = operation_begin.equals(")", (bag, token) -> bag.<ValueChainBuilder>get().parameter());
|
|
operation_end.then(operation_call);
|
|
operation_end.end(ValueChainBuilder.build((builder) -> builder.buildMethodCall(), false));
|
|
StateTree<JavaElement> operation_value = operation_begin.redirect(this.current, (global, local) -> global.<ValueChainBuilder>get().parameter(local.get()));
|
|
operation_value.then(operation_end);
|
|
operation_value.equals(",")
|
|
.then(operation_value);
|
|
|
|
StateTree<JavaElement> value_parenthesis = unary_value.then((validator) -> {
|
|
validator.getBag().set(new ValueChainBuilder());
|
|
return true;
|
|
}).equals("(");
|
|
StateTree<JavaElement> value_parenthesis_close = value_parenthesis.equals(")");
|
|
|
|
StateTree<JavaElement> value_inside_type = value_parenthesis.redirect(type, (global, local) -> global.set("type", local.get()));
|
|
|
|
StateTree<JavaElement> value_inside = value_parenthesis.redirect(this.current, (global, local) -> {
|
|
if(local.get() instanceof StaticValue){
|
|
Token lambdaVariable = local.<StaticValue>get().getToken();
|
|
Token lambdaType = global.get("type");
|
|
if(lambdaVariable.equals(lambdaType)) lambdaType = null;
|
|
global.<ValueChainBuilder>get().lambda(new LambdaParameter(lambdaType, lambdaVariable));
|
|
global.remove("type");
|
|
return;
|
|
}
|
|
global.set(local.get());
|
|
});
|
|
|
|
StateTree<JavaElement> cast = value_inside_type.equals(")").redirect(this.current, (global, local) -> {
|
|
global.<ValueChainBuilder>get().rebase(new CastValue(global.get("type"), local.get()));
|
|
global.remove("type");
|
|
});
|
|
|
|
|
|
cast.end(ValueChainBuilder.build(false));
|
|
cast.equals(".").then(value_name);
|
|
cast.then(value_array);
|
|
|
|
value_inside_type.then(value_inside);
|
|
StateTree<JavaElement> value_inside_splitter = value_inside.equals(",");
|
|
value_inside_splitter.then(value_inside);
|
|
value_inside_splitter.then(value_inside_type);
|
|
|
|
value_inside.then(value_parenthesis_close);
|
|
value_inside.then(value_operation);
|
|
value_parenthesis_close.end();
|
|
value_parenthesis_close.then(value_operation);
|
|
|
|
StateTree<JavaElement> value_lambda = value_parenthesis_close.then((validator) -> validator.validate((token) -> token.getValue().equals("-")) && validator.validate((token) -> token.getValue().equals(">")));
|
|
value_lambda.equals("{")
|
|
.<JavaElement>end(
|
|
ValueChainBuilder.build((builder) -> builder.buildLambda(), true)
|
|
).multiple(function_container)
|
|
.unique((validator) -> validator.validate((token) -> token.getValue().equals("}"))).end();
|
|
|
|
value_lambda.redirect(unary_value, (global, local) -> {
|
|
global.<ValueChainBuilder>get().buildLambda(local.get());
|
|
}).end(ValueChainBuilder.build(false));
|
|
|
|
}
|
|
|
|
private BiConsumer<Bag, Token> action(String action){
|
|
return (bag, token) -> bag.<ValueChainBuilder>get().action(action);
|
|
}
|
|
|
|
private BiConsumer<Bag, Token> modifier(){
|
|
return (bag, token) -> bag.<ValueChainBuilder>get().modifier(token);
|
|
}
|
|
|
|
private static class ValueChainBuilder{
|
|
|
|
static BiFunction<JavaElement, Bag, JavaElement> build(Consumer<ValueChainBuilder> builder, boolean returnValue){
|
|
return (parent, bag) -> {
|
|
ValueChainBuilder chainBuilder = bag.get();
|
|
builder.accept(chainBuilder);
|
|
chainBuilder.build(parent, bag);
|
|
return returnValue ? bag.get() : null;
|
|
};
|
|
}
|
|
|
|
static BiFunction<JavaElement, Bag, JavaElement> build(boolean returnValue){
|
|
return (parent, bag) -> {
|
|
ValueChainBuilder chainBuilder = bag.get();
|
|
chainBuilder.build(parent, bag);
|
|
return returnValue ? bag.get() : null;
|
|
};
|
|
}
|
|
|
|
//TODO fall back branch problem cause one instance in multiple branch's bag ?
|
|
private Value base;
|
|
|
|
private Token current;
|
|
|
|
private Token modifier;
|
|
|
|
private String action;
|
|
private Value right;
|
|
|
|
private List<Value> parameters;
|
|
|
|
private List<LambdaParameter> lambda;
|
|
|
|
ValueChainBuilder(){
|
|
|
|
}
|
|
|
|
public void rebase(Value base){
|
|
this.base = base;
|
|
}
|
|
|
|
public void nameValue(Token token) {
|
|
this.current = token;
|
|
}
|
|
|
|
public void constantValue(Token token){
|
|
this.current = token;
|
|
}
|
|
|
|
public void action(String action){
|
|
this.action = action;
|
|
}
|
|
|
|
public void right(Value value){
|
|
this.right = value;
|
|
}
|
|
|
|
public void modifier(Token token){
|
|
this.modifier = token;
|
|
}
|
|
|
|
public void dot(){
|
|
if(this.base == null){
|
|
buildStatic();
|
|
this.current = null;
|
|
return;
|
|
}
|
|
if(this.current != null){
|
|
buildVariableAccess();
|
|
this.current = null;
|
|
}
|
|
}
|
|
|
|
public void parameter(Value value){
|
|
this.parameters.add(value);
|
|
}
|
|
|
|
public void parameter(){
|
|
if(this.parameters == null){
|
|
this.parameters = new ArrayList<>();
|
|
return;
|
|
}
|
|
buildMethodCall();
|
|
this.current = null;
|
|
this.parameters = null;
|
|
}
|
|
|
|
public void arrayAccess(Value value){
|
|
this.base = new ArrayAccessValue(this.base, value);
|
|
}
|
|
|
|
public void lambda(LambdaParameter value){
|
|
if(this.lambda == null) this.lambda = new ArrayList<>();
|
|
else{
|
|
LambdaParameter last = this.lambda.get(this.lambda.size()-1);
|
|
if(last.getName().equals(value.getType())) this.lambda.remove(this.lambda.size()-1);
|
|
}
|
|
this.lambda.add(value);
|
|
}
|
|
|
|
public void buildModifier(){
|
|
if(this.base == null) return; //TODO throws exception in this case
|
|
this.base = new ModifierValue(this.modifier, this.base);
|
|
}
|
|
|
|
public void buildStatic(){
|
|
if(this.current == null) return;
|
|
this.base = new StaticValue(this.current);
|
|
}
|
|
|
|
public void buildOperation(){
|
|
this.base = new BiValue(current == null ? base : new StaticValue(current), action, right);
|
|
}
|
|
|
|
public void buildMethodCall(){
|
|
if(this.current == null) return;
|
|
this.base = new MethodCallValue(this.base, null, this.current, this.parameters);
|
|
}
|
|
|
|
public void buildVariableAccess(){
|
|
this.base = new VariableAccessValue(this.base, this.current);
|
|
}
|
|
|
|
public void buildLambda(){
|
|
this.base = new LambdaValue(this.lambda == null ? new ArrayList<>() : this.lambda);
|
|
this.lambda = null;
|
|
}
|
|
|
|
public void buildLambda(Value value){
|
|
this.base = new LambdaValue(this.lambda == null ? new ArrayList<>() : this.lambda, value);
|
|
this.lambda = null;
|
|
}
|
|
|
|
public void extractLambda(){
|
|
this.base = new StaticValue(this.lambda.get(0).getName());
|
|
}
|
|
|
|
public void build(JavaElement parent, Bag bag){
|
|
bag.set(base);
|
|
if(parent instanceof ValueContainer) ((ValueContainer)parent).addValue(base);
|
|
}
|
|
|
|
@Override
|
|
public String toString(){
|
|
String result = "ValueChainBuilder{";
|
|
try{
|
|
for(Field field : getClass().getDeclaredFields()){
|
|
result+="\n\t"+field.getName()+"="+field.get(this);
|
|
}
|
|
}catch(Exception ex){}
|
|
|
|
return result+"\n}";
|
|
}
|
|
}
|
|
|
|
}
|