package org.zwobble.couscous.ast; import java.util.Optional; import java.util.function.Function; import com.google.common.collect.ImmutableList; import static org.zwobble.couscous.ast.FormalArgumentNode.formalArg; import static org.zwobble.couscous.ast.VariableDeclaration.var; public class ClassNodeBuilder { private final TypeName name; private final ImmutableList.Builder fields; private Optional constructor; private final ImmutableList.Builder methods; public ClassNodeBuilder(String name) { this.name = TypeName.of(name); this.fields = ImmutableList.builder(); this.constructor = Optional.empty(); this.methods = ImmutableList.builder(); } public ClassNodeBuilder field(String name, TypeName type) { this.fields.add(FieldDeclarationNode.field(name, type)); return this; } public ClassNodeBuilder constructor(Function, MethodBuilder> build) { this.constructor = Optional.of(build.apply(constructorBuilder()).build()); return this; } private MethodBuilder constructorBuilder() { return new MethodBuilder(builder -> ConstructorNode.constructor( builder.arguments.build(), builder.statements.build())); } public ClassNodeBuilder method(MethodNode method) { this.methods.add(method); return this; } public ClassNodeBuilder staticMethod(String name, Function, MethodBuilder> build) { return method(name, true, build); } public ClassNodeBuilder method(String name, Function, MethodBuilder> build) { return method(name, false, build); } public ClassNodeBuilder method(String name, boolean isStatic, Function, MethodBuilder> build) { this.methods.add(build.apply(methodBuilder(name, isStatic)).build()); return this; } private MethodBuilder methodBuilder(String name, boolean isStatic) { return new MethodBuilder(builder -> MethodNode.builder() .isStatic(isStatic) .name(name) .arguments(builder.arguments.build()) .body(builder.statements.build()) .build()); } public ClassNode build() { return new ClassNode( name, fields.build(), constructor.orElse(constructorBuilder().build()), methods.build()); } public class MethodBuilder { private final Function, T> build; private final ImmutableList.Builder arguments; private final ImmutableList.Builder statements; public MethodBuilder(Function, T> build) { this.build = build; this.arguments = ImmutableList.builder(); this.statements = ImmutableList.builder(); } public ThisReferenceNode thisReference() { return ThisReferenceNode.thisReference(name); } public MethodBuilder argument(String id, String name, TypeName type) { arguments.add(formalArg(var(id, name, type))); return this; } public MethodBuilder argument(FormalArgumentNode argument) { arguments.add(argument); return this; } public MethodBuilder statement(StatementNode statement) { statements.add(statement); return this; } public T build() { return this.build.apply(this); } } }