Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise typedef handling and generation #77

Merged
merged 15 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/kotlin/net/theevilreaper/dartpoet/DartFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class DartFile internal constructor(
internal val libImport = DirectiveOrdering.sortDirectives<LibraryDirective>(LibraryDirective::class, directives)
internal val exportDirectives = DirectiveOrdering.sortDirectives<ExportDirective>(ExportDirective::class, directives)
internal val relativeImports = DirectiveOrdering.sortDirectives<RelativeDirective>(RelativeDirective::class, directives)

internal val typeDefs = builder.typeDefs.toImmutableList()
internal val hasTypeDefs = typeDefs.isNotEmpty()

init {
check(name.trim().isNotEmpty()) { "The name of a class can't be empty (ONLY SPACES ARE NOT ALLOWED" }
if (libImport.isNotEmpty()) {
Expand Down
20 changes: 20 additions & 0 deletions src/main/kotlin/net/theevilreaper/dartpoet/DartFileBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import net.theevilreaper.dartpoet.clazz.ClassSpec
import net.theevilreaper.dartpoet.code.CodeBlock
import net.theevilreaper.dartpoet.extension.ExtensionSpec
import net.theevilreaper.dartpoet.directive.Directive
import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec
import net.theevilreaper.dartpoet.property.consts.ConstantPropertySpec
import net.theevilreaper.dartpoet.property.PropertySpec
import net.theevilreaper.dartpoet.util.DEFAULT_INDENT
Expand All @@ -20,6 +21,7 @@ class DartFileBuilder(
internal val annotations: MutableList<AnnotationSpec> = mutableListOf()
internal val extensionStack: MutableList<ExtensionSpec> = mutableListOf()
internal val constants: MutableSet<ConstantPropertySpec> = mutableSetOf()
internal val typeDefs: MutableList<TypeDefSpec> = mutableListOf()
internal var indent = DEFAULT_INDENT

/**
Expand Down Expand Up @@ -71,6 +73,24 @@ class DartFileBuilder(
this.extensionStack += extensions
}

/**
* Add a type definition to the file builder.
* @param typeDef the type definition to add
* @return the current instance of [DartFileBuilder]
*/
fun typeDef(typeDef: TypeDefSpec) = apply {
this.typeDefs += typeDef
}

/**
* Add an array of type definitions to the file builder.
* @param typeDef the type definitions to add
* @return the current instance of [DartFileBuilder]
*/
fun typeDef(vararg typeDef: TypeDefSpec) = apply {
this.typeDefs += typeDef
}

fun type(dartFileSpec: ClassSpec) = apply {
this.specTypes += dartFileSpec
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import net.theevilreaper.dartpoet.function.FunctionSpec
import net.theevilreaper.dartpoet.meta.SpecData
import net.theevilreaper.dartpoet.meta.SpecMethods
import net.theevilreaper.dartpoet.function.constructor.ConstructorSpec
import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec
import net.theevilreaper.dartpoet.property.PropertySpec
import net.theevilreaper.dartpoet.property.consts.ConstantPropertySpec
import net.theevilreaper.dartpoet.type.TypeName
Expand All @@ -32,6 +33,7 @@ class ClassBuilder internal constructor(
internal val functionStack: MutableList<FunctionSpec> = mutableListOf()
internal val enumPropertyStack: MutableList<EnumPropertySpec> = mutableListOf()
internal val constantStack: MutableSet<ConstantPropertySpec> = mutableSetOf()
internal val typedefs: MutableList<TypeDefSpec> = mutableListOf()
internal var superClass: TypeName? = null
internal var inheritKeyWord: InheritKeyword? = null
internal var endWithNewLine = false
Expand All @@ -53,6 +55,14 @@ class ClassBuilder internal constructor(
this.constantStack += constants
}

fun typedef(typeDefSpec: TypeDefSpec) = apply {
this.typedefs += typeDefSpec
}

fun typedef(vararg typeDefSpec: TypeDefSpec) = apply {
this.typedefs += typeDefSpec
}

/**
* Add a [EnumPropertySpec] to the spec.
* @param enumPropertySpec the property to add
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ class ClassSpec internal constructor(
internal val superClass = builder.superClass
internal val inheritKeyWord = builder.inheritKeyWord
internal val classModifiers = modifiers.filter { it != WITH }.toImmutableSet()
internal val functions = builder.functionStack.filter { !it.isTypeDef }.toImmutableSet()
internal val typeDefs = builder.typedefs.toImmutableList()
internal val functions = builder.functionStack.toImmutableSet()
internal val properties = builder.propertyStack.toImmutableSet()
internal val constructors = builder.constructorStack.toImmutableSet()
internal val typeDefStack = builder.functionStack.filter { it.isTypeDef }.toImmutableSet()
internal val enumPropertyStack = builder.enumPropertyStack.toImmutableList()
internal var constantStack = builder.constantStack.toImmutableSet()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import net.theevilreaper.dartpoet.extension.ExtensionSpec
import net.theevilreaper.dartpoet.function.FunctionSpec
import net.theevilreaper.dartpoet.function.constructor.ConstructorSpec
import net.theevilreaper.dartpoet.directive.Directive
import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec
import net.theevilreaper.dartpoet.property.consts.ConstantPropertySpec
import net.theevilreaper.dartpoet.parameter.ParameterSpec
import net.theevilreaper.dartpoet.property.PropertySpec
Expand Down Expand Up @@ -199,6 +200,20 @@ fun Set<ConstantPropertySpec>.emitConstants(
}
}

fun List<TypeDefSpec>.emitTypeDefs(
codeWriter: CodeWriter,
emitBlock: (TypeDefSpec) -> Unit = { it.write(codeWriter) }
) = with(codeWriter) {
val emitNewLines = size > 1
forEachIndexed { index, typeDefSpec ->
if (index > 0 && emitNewLines) {
emit(NEW_LINE)
}
emitBlock(typeDefSpec)
}
emit(NEW_LINE)
}

fun Set<PropertySpec>.emitProperties(
codeWriter: CodeWriter,
forceNewLines: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ internal class ClassWriter : Writeable<ClassSpec> {
writeAnonymousClass(spec, writer)
return
}
spec.typeDefStack.emitFunctions(writer)

if (spec.typeDefStack.isNotEmpty()) {
writer.emit(NEW_LINE)
}

spec.annotations.emitAnnotations(writer, inLineAnnotations = false)
writeClassHeader(spec, writer)
Expand Down Expand Up @@ -100,13 +95,8 @@ internal class ClassWriter : Writeable<ClassSpec> {
}

private fun writeAnonymousClass(spec: ClassSpec, writer: CodeWriter) {
spec.typeDefStack.emitFunctions(writer) {
it.write(writer)
}

spec.functions.emitFunctions(writer) {
it.write(writer)
}
spec.typeDefs.emitTypeDefs(writer)
spec.functions.emitFunctions(writer)

if (spec.endsWithNewLine) {
writer.emit(NEW_LINE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ internal class DartFileWriter : Writeable<DartFile>, DocumentationAppender {
writer.emit(NEW_LINE)
}

if (spec.hasTypeDefs) {
spec.typeDefs.emitTypeDefs(writer)
}

if (spec.types.isNotEmpty()) {
spec.types.forEach {
classWriter.write(it, writer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,8 @@ internal class FunctionWriter : Writeable<FunctionSpec> {
if (spec.hasDocs) {
spec.docs.forEach { writer.emitDoc(it) }
}
if (spec.isTypeDef) {
writeTypeDef(spec, writer)
return
}

if (!spec.isTypeDef && spec.annotation.isNotEmpty()) {
if (spec.annotation.isNotEmpty()) {
spec.annotation.forEach { it.write(writer) }
writer.emit(NEW_LINE)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package net.theevilreaper.dartpoet.code.writer

import net.theevilreaper.dartpoet.DartModifier
import net.theevilreaper.dartpoet.code.CodeWriter
import net.theevilreaper.dartpoet.code.Writeable
import net.theevilreaper.dartpoet.code.emitParameters
import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec
import net.theevilreaper.dartpoet.util.SEMICOLON

class TypeDefWriter : Writeable<TypeDefSpec> {
override fun write(spec: TypeDefSpec, writer: CodeWriter) {
writer.emit("${DartModifier.TYPEDEF.identifier}·${spec.typeDefName}")
if (spec.typeCasts.isNotEmpty()) {
val typesAsString = spec.typeCasts.joinToString(separator = ",·") { it.toString() }
writer.emitCode("<%L>", typesAsString)
}
writer.emit("·=·")
writer.emitCode("%T", spec.returnType)

if (spec.name != null) {
writer.emitCode("·%L", spec.name)
}

if (spec.hasParameters) {
writer.emit("(")
spec.parameters.emitParameters(writer, forceNewLines = false, emitBrackets = false, emitSpace = spec.parameters.size > 1)
writer.emit(")")
}
writer.emit(SEMICOLON)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class FunctionBuilder internal constructor(
internal var async: Boolean = false
internal var returnType: TypeName? = null
internal val body: CodeBlock.Builder = CodeBlock.builder()
internal var typedef: Boolean = false
internal var typeCast: TypeName? = null
internal var setter: Boolean = false
internal var getter: Boolean = false
Expand Down Expand Up @@ -94,14 +93,6 @@ class FunctionBuilder internal constructor(
*/
fun typeCast(cast: KClass<*>) = apply { this.typeCast = cast.asTypeName() }

/**
* If the function should be generated as typedef definition.
* @param typeDef true for a typedef
*/
fun typedef(typeDef: Boolean) = apply {
this.typedef = typeDef
}

fun addCode(format: String, vararg args: Any?) = apply {
body.add(format, *args)
}
Expand Down Expand Up @@ -180,12 +171,6 @@ class FunctionBuilder internal constructor(
* @return the created instance
*/
fun build(): FunctionSpec {
// Remove typedef keyword from the list to prevent problems
if (specData.modifiers.contains(DartModifier.TYPEDEF)) {
typedef(true)
specData.modifiers.remove(DartModifier.TYPEDEF)
}

return FunctionSpec(this)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import net.theevilreaper.dartpoet.util.toImmutableSet
class FunctionSpec(
builder: FunctionBuilder
) {

internal val name = builder.name
internal val returnType: TypeName? = builder.returnType
internal val body: CodeBlock = builder.body.build()
Expand All @@ -33,8 +32,7 @@ class FunctionSpec(
internal var modifiers: Set<DartModifier> = builder.specData.modifiers.also {
hasAllowedModifiers(it, ALLOWED_FUNCTION_MODIFIERS, "function")
}.filter { it != DartModifier.PRIVATE && it != DartModifier.PUBLIC }.toImmutableSet()
internal val isPrivate = builder.specData.modifiers.contains(DartModifier.PRIVATE)
internal val isTypeDef = builder.typedef
internal val isPrivate = builder.specData.modifiers.remove(DartModifier.PRIVATE)
internal val typeCast = builder.typeCast
internal val asSetter = builder.setter
internal val isGetter = builder.getter
Expand All @@ -49,7 +47,6 @@ class FunctionSpec(
}

init {
//check(!isTypeDef && annotation.isNotEmpty()) { "A typedef can't have annotations" }
require(name.trim().isNotEmpty()) { "The name of a function can't be empty" }
require(body.isEmpty() || !modifiers.contains(DartModifier.ABSTRACT)) { "An abstract method can't have a body" }

Expand Down Expand Up @@ -89,7 +86,6 @@ class FunctionSpec(
builder.modifiers(*this.modifiers.toTypedArray())
builder.parameters.addAll(this.parameters)
builder.async = this.isAsync
builder.typedef = this.isTypeDef
builder.typeCast = this.typeCast
builder.setter = this.asSetter
builder.getter = this.isGetter
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package net.theevilreaper.dartpoet.function.typedef

import net.theevilreaper.dartpoet.parameter.ParameterSpec
import net.theevilreaper.dartpoet.type.ClassName
import net.theevilreaper.dartpoet.type.TypeName
import net.theevilreaper.dartpoet.type.asTypeName
import kotlin.reflect.KClass

/**
* The builder is used to create a type definition with a specific name and optional type cast.
* After the construction the builder maps the data into a [TypeDefSpec] object.
*
* @property typeDefName the name of the type definition.
* @property typeCasts optional array of type-cast for the type definition.
*/
class TypeDefBuilder internal constructor(
val typeDefName: String,
vararg val typeCasts: TypeName? = emptyArray()
) {
/**
* The name of the type definition.
*/
var name: String? = null

/**
* The return type of the type definition.
*/
var returnType: TypeName? = null

/**
* List of parameters associated with the type definition.
*/
val parameters: MutableList<ParameterSpec> = mutableListOf()

/**
* Sets the name of the type definition.
*
* @param name the name of the type definition.
* @return the current instance of [TypeDefBuilder].
*/
fun name(name: String) = apply {
this.name = name
}

/**
* Adds a parameter to the list of parameters.
*
* @param parameterSpec the parameter specification.
* @return the current instance of [TypeDefBuilder].
*/
fun parameter(parameterSpec: ParameterSpec) = apply {
this.parameters += parameterSpec
}

/**
* Adds multiple parameters to the list of parameters.
*
* @param parameterSpecs the parameter specifications.
* @return the current instance of [TypeDefBuilder].
*/
fun parameters(vararg parameterSpecs: ParameterSpec) = apply {
this.parameters += parameterSpecs
}

/**
* Sets the return type of the type definition.
*
* @param typeName the return type as a [TypeName].
* @return the current instance of [TypeDefBuilder].
*/
fun returns(typeName: TypeName) = apply {
this.returnType = typeName
}

/**
* Sets the return type of the type definition.
*
* @param typeName the return type as a [ClassName].
* @return the current instance of [TypeDefBuilder].
*/
fun returns(typeName: ClassName) = apply {
this.returnType = typeName
}

/**
* Sets the return type of the type definition using a [KClass].
*
* @param typeName the return type as a [KClass].
* @return the current instance of [TypeDefBuilder].
*/
fun returns(typeName: KClass<*>) = apply {
this.returnType = typeName.asTypeName()
}

/**
* Builds and returns an instance of [TypeDefSpec] based on the configuration.
*
* @return an instance of [TypeDefSpec].
*/
fun build(): TypeDefSpec {
return TypeDefSpec(this)
}
}
Loading