peer-at-code-parser-java/src/dev/peerat/parser/java/tree/ValueTree.java
2025-04-27 11:53:33 +02:00

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}";
}
}
}