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(TypeName name) { this.name = name; this.fields = ImmutableList.builder(); this.constructor = Optional.empty(); this.methods = ImmutableList.builder(); } public ClassNodeBuilder(String name) { this(TypeName.of(name)); } public ClassNodeBuilder field(String name, TypeName type) { return field(FieldDeclarationNode.field(name, type)); } public ClassNodeBuilder field(FieldDeclarationNode field) { this.fields.add(field); return this; } public ClassNodeBuilder constructor(ConstructorNode constructor) { this.constructor = Optional.of(constructor); return this; } public ClassNodeBuilder constructor(Function, MethodBuilder> build) { return constructor(build.apply(constructorBuilder()).build()); } 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(name) .isStatic(isStatic) .annotations(builder.annotations.build()) .arguments(builder.arguments.build()) .body(builder.statements.build()) .build()); } public ClassNode build() { return ClassNode.declareClass( name, fields.build(), constructor.orElse(ConstructorNode.DEFAULT), methods.build()); } public class MethodBuilder { private final Function, T> build; private final ImmutableList.Builder annotations; private final ImmutableList.Builder arguments; private final ImmutableList.Builder statements; public MethodBuilder(Function, T> build) { this.build = build; this.annotations = ImmutableList.builder(); this.arguments = ImmutableList.builder(); this.statements = ImmutableList.builder(); } public MethodBuilder annotation(TypeName type) { annotations.add(AnnotationNode.annotation(type)); return this; } 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); } } }