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 { //TODO order tree by more used branch ? to not check a whole tree to go on the last branch... public ValueTree(SyntaxTreeRegistery registery) { super(registery); this.current = new StateTree<>(); } @Override public void init(){ StateTree type = this.registery.getNode(TypeTree.class); StateTree function_container = this.registery.getNode(FunctionContainerTree.class); StateTree class_container = this.registery.getNode(ClassContainerTree.class); // VALUE StateTree value = this.current.then((validator) -> { validator.getBag().set(new ValueChainBuilder()); return true; }); StateTree unary_value = new StateTree<>(); StateTree value_operation = new StateTree<>(); StateTree redirectRight = new RedirectStateTree<>(this.current, (global, local) -> { global.get().right(local.get()); }); //TODO -> Array and dot after a new Instance...event with {} StateTree value_instance = unary_value.equals("new"); StateTree value_instance_type = value_instance.redirect(type, (global, local) -> global.set("type", local.get())); StateTree value_instance_params = value_instance_type.equals("("); StateTree value_instance_params_end = value_instance_params.equals(")", (bag, token) -> { ValueChainBuilder builder = new ValueChainBuilder(); List 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 value_instance_param = value_instance_params.redirect(this.current, (global, local) -> { List 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.end(ValueChainBuilder.build(false)); value_instance_params_end.equals("{") .end(ValueChainBuilder.build(true)).multiple(class_container) .unique((validator) -> validator.validate((token) -> token.getValue().equals("}"))).end(); StateTree value_instance_array = value_instance_type.equals("["); StateTree value_instance_array_value = value_instance_array.redirect(this.current); StateTree 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 value_instance_array_init = value_instance_array_end.equals("{"); StateTree value_instance_array_init_value = value_instance_array_init.redirect(this.current, (global, local) -> { List 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 value_instance_array_value_end = value_instance_array_init_value.equals("}"); value_instance_array_value_end.end((parent, bag) -> { ArrayValue result = new ArrayValue(bag.>get("array").toArray(new Value[0])); bag.set(result); if(parent instanceof ValueContainer) ((ValueContainer)parent).addValue(result); return null; }); StateTree 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.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.get().rebase(new ArrayValue(bag.>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.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 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 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.get().rebase(local.get())).end(ValueChainBuilder.build((builder) -> builder.buildModifier(), false)); StateTree left_value = value.redirect(unary_value, (global, local) -> { if(local.get() instanceof ValueChainBuilder) { global.set(local.get()); global.get().extractLambda(); return;} global.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.get().base, bag.get("success"), bag.get("fail"))); if(parent instanceof ValueContainer) ((ValueContainer)parent).addValue(bag.get()); return null; }); StateTree value_array = left_value.equals("["); StateTree value_array_value = value_array.redirect(this.current, (global, local) -> global.get().arrayAccess(local.get())); StateTree 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.get().dot()).then(value_name); value_instance_array_value_end.then(value_array); StateTree operation_call = value_name.equals(".", (bag, token) -> bag.get().dot()); operation_call.then(value_name); StateTree operation_begin = value_name.equals("(", (bag, token) -> bag.get().parameter()); StateTree operation_end = operation_begin.equals(")", (bag, token) -> bag.get().parameter()); operation_end.then(operation_call); operation_end.end(ValueChainBuilder.build((builder) -> builder.buildMethodCall(), false)); StateTree operation_value = operation_begin.redirect(this.current, (global, local) -> global.get().parameter(local.get())); operation_value.then(operation_end); operation_value.equals(",") .then(operation_value); StateTree value_parenthesis = unary_value.then((validator) -> { validator.getBag().set(new ValueChainBuilder()); return true; }).equals("("); StateTree value_parenthesis_close = value_parenthesis.equals(")"); StateTree value_inside_type = value_parenthesis.redirect(type, (global, local) -> global.set("type", local.get())); StateTree value_inside = value_parenthesis.redirect(this.current, (global, local) -> { if(local.get() instanceof StaticValue){ Token lambdaVariable = local.get().getToken(); Token lambdaType = global.get("type"); if(lambdaVariable.equals(lambdaType)) lambdaType = null; global.get().lambda(new LambdaParameter(lambdaType, lambdaVariable)); global.remove("type"); return; } global.set(local.get()); }); StateTree cast = value_inside_type.equals(")").redirect(this.current, (global, local) -> { global.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 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 value_lambda = value_parenthesis_close.then((validator) -> validator.validate((token) -> token.getValue().equals("-")) && validator.validate((token) -> token.getValue().equals(">"))); value_lambda.equals("{") .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.get().buildLambda(local.get()); }).end(ValueChainBuilder.build(false)); } private BiConsumer action(String action){ return (bag, token) -> bag.get().action(action); } private BiConsumer modifier(){ return (bag, token) -> bag.get().modifier(token); } private static class ValueChainBuilder{ static BiFunction build(Consumer builder, boolean returnValue){ return (parent, bag) -> { ValueChainBuilder chainBuilder = bag.get(); builder.accept(chainBuilder); chainBuilder.build(parent, bag); return returnValue ? bag.get() : null; }; } static BiFunction 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 parameters; private List 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}"; } } }