diff --git a/libraries/tools/idl2k/src/main/kotlin/gen.kt b/libraries/tools/idl2k/src/main/kotlin/gen.kt index b8deaf82d0e..c2d48ff5be1 100644 --- a/libraries/tools/idl2k/src/main/kotlin/gen.kt +++ b/libraries/tools/idl2k/src/main/kotlin/gen.kt @@ -77,10 +77,12 @@ fun generateAttribute(putNoImpl: Boolean, repository: Repository, attribute: Att private fun InterfaceDefinition.superTypes(repository: Repository) = superTypes.map { repository.interfaces[it] }.filterNotNull() private fun resolveDefinitionKind(repository: Repository, iface: InterfaceDefinition, constructors: List = iface.findConstructors()): GenerateDefinitionKind = - if (constructors.isNotEmpty() || iface.superTypes(repository).any { resolveDefinitionKind(repository, it) == GenerateDefinitionKind.CLASS }) { - GenerateDefinitionKind.CLASS - } else { - GenerateDefinitionKind.TRAIT + when { + constructors.isNotEmpty() || iface.superTypes(repository).any { resolveDefinitionKind(repository, it) == GenerateDefinitionKind.CLASS } -> { + GenerateDefinitionKind.CLASS + } + iface.callback -> GenerateDefinitionKind.TRAIT + else -> GenerateDefinitionKind.ABSTRACT_CLASS } private fun InterfaceDefinition.mapAttributes(repository: Repository) = attributes.map { generateAttribute(!dictionary, repository, it) } @@ -92,7 +94,13 @@ fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateT val superClasses = iface.superTypes .map { repository.interfaces[it] } .filterNotNull() - .filter { resolveDefinitionKind(repository, it) == GenerateDefinitionKind.CLASS } + .filter { + when (resolveDefinitionKind(repository, it)) { + GenerateDefinitionKind.CLASS, + GenerateDefinitionKind.ABSTRACT_CLASS -> true + else -> false + } + } assert(superClasses.size <= 1) { "Type ${iface.name} should have one or zero super classes but found ${superClasses.map { it.name }}" } val superClass = superClasses.singleOrNull() @@ -104,7 +112,7 @@ fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateT val primaryConstructor = when { declaredConstructors.size == 1 -> declaredConstructors.single() - declaredConstructors.isEmpty() && entityKind == GenerateDefinitionKind.CLASS -> EMPTY_CONSTRUCTOR + declaredConstructors.isEmpty() && (entityKind == GenerateDefinitionKind.CLASS || entityKind == GenerateDefinitionKind.ABSTRACT_CLASS) -> EMPTY_CONSTRUCTOR else -> declaredConstructors.firstOrNull { it.arguments.isEmpty() } } val secondaryConstructors = declaredConstructors.filter { it != primaryConstructor } diff --git a/libraries/tools/idl2k/src/main/kotlin/model.kt b/libraries/tools/idl2k/src/main/kotlin/model.kt index 1f2e1a04609..e4310c5e6f2 100644 --- a/libraries/tools/idl2k/src/main/kotlin/model.kt +++ b/libraries/tools/idl2k/src/main/kotlin/model.kt @@ -59,7 +59,8 @@ enum class NativeGetterOrSetter { enum class GenerateDefinitionKind { TRAIT, - CLASS + CLASS, + ABSTRACT_CLASS } data class GenerateFunctionCall(val name: String, val arguments: List) diff --git a/libraries/tools/idl2k/src/main/kotlin/render.kt b/libraries/tools/idl2k/src/main/kotlin/render.kt index 897e5a424e1..2e70c97024f 100644 --- a/libraries/tools/idl2k/src/main/kotlin/render.kt +++ b/libraries/tools/idl2k/src/main/kotlin/render.kt @@ -11,11 +11,17 @@ private fun O.indent(commented: Boolean = false, level: Int) { } } -private fun Appendable.renderAttributeDeclaration(arg: GenerateAttribute, override: Boolean, open: Boolean, omitDefaults: Boolean = false) { - when { - override -> append("override ") - open -> append("open ") - arg.vararg -> append("vararg ") +private fun Appendable.renderAttributeDeclaration(arg: GenerateAttribute, modality: MemberModality, omitDefaults: Boolean = false) { + if (arg.vararg) { + append("vararg ") + } + else { + when (modality) { + MemberModality.OVERRIDE -> append("override ") + MemberModality.ABSTRACT -> append("abstract ") + MemberModality.OPEN -> append("open ") + MemberModality.FINAL -> {} + } } append(when(arg.kind) { @@ -32,10 +38,10 @@ private fun Appendable.renderAttributeDeclaration(arg: GenerateAttribute, overri } } -private fun Appendable.renderAttributeDeclarationAsProperty(arg: GenerateAttribute, override: Boolean, open: Boolean, commented: Boolean, level: Int, omitDefaults: Boolean = false) { +private fun Appendable.renderAttributeDeclarationAsProperty(arg: GenerateAttribute, modality: MemberModality, commented: Boolean, level: Int, omitDefaults: Boolean = false) { indent(commented, level) - renderAttributeDeclaration(arg, override, open, omitDefaults) + renderAttributeDeclaration(arg, modality, omitDefaults) appendln() if (arg.getterNoImpl) { @@ -60,7 +66,7 @@ private fun String.replaceKeywords() = if (this in keywords) this + "_" else thi private fun Appendable.renderArgumentsDeclaration(args: List, omitDefaults: Boolean = false) = args.joinTo(this, ", ", "(", ")") { - StringBuilder().apply { renderAttributeDeclaration(it, it.override, false, omitDefaults) } + StringBuilder().apply { renderAttributeDeclaration(it, if (it.override) MemberModality.OVERRIDE else MemberModality.FINAL, omitDefaults) } } private fun renderCall(call: GenerateFunctionCall) = "${call.name.replaceKeywords()}(${call.arguments.joinToString(separator = ", ", transform = String::replaceKeywords)})" @@ -108,6 +114,7 @@ fun Appendable.render(allTypes: Map, typeNamesToUn } when (iface.kind) { GenerateDefinitionKind.CLASS -> append("open class ") + GenerateDefinitionKind.ABSTRACT_CLASS -> append("abstract class ") GenerateDefinitionKind.TRAIT -> append("interface ") } @@ -154,9 +161,17 @@ fun Appendable.render(allTypes: Map, typeNamesToUn .filter { it !in superAttributes && !it.static && (it.isVar || (it.isVal && superAttributesByName[it.name]?.hasNoVars() ?: true)) } .map { it.dynamicIfUnknownType(allTypes.keys) } .groupBy { it.signature }.reduceValues().values.forEach { arg -> - renderAttributeDeclarationAsProperty(arg, - override = arg.signature in superSignatures, - open = iface.kind == GenerateDefinitionKind.CLASS && arg.isVal, + val modality = when { + arg.signature in superSignatures -> MemberModality.OVERRIDE + iface.kind == GenerateDefinitionKind.CLASS && arg.isVal -> MemberModality.OPEN + iface.kind == GenerateDefinitionKind.ABSTRACT_CLASS -> when { + arg.initializer != null || arg.getterSetterNoImpl -> MemberModality.OPEN + else -> MemberModality.ABSTRACT + } + else -> MemberModality.FINAL + } + renderAttributeDeclarationAsProperty(arg, + modality = modality, commented = arg.isCommented(iface.name), omitDefaults = iface.kind == GenerateDefinitionKind.TRAIT, level = 1 @@ -174,10 +189,10 @@ fun Appendable.render(allTypes: Map, typeNamesToUn indent(false, 1) appendln("companion object {") iface.constants.forEach { - renderAttributeDeclarationAsProperty(it, override = false, open = false, level = 2, commented = it.isCommented(iface.name)) + renderAttributeDeclarationAsProperty(it, MemberModality.FINAL, level = 2, commented = it.isCommented(iface.name)) } staticAttributes.forEach { - renderAttributeDeclarationAsProperty(it, override = false, open = false, level = 2, commented = it.isCommented(iface.name)) + renderAttributeDeclarationAsProperty(it, MemberModality.FINAL, level = 2, commented = it.isCommented(iface.name)) } staticFunctions.forEach { renderFunctionDeclaration(it.fixRequiredArguments(iface.name), override = false, level = 2, commented = it.isCommented(iface.name)) @@ -252,3 +267,9 @@ fun Appendable.render(namespace: String, ifaces: List, uni } } +enum class MemberModality { + OPEN, + ABSTRACT, + OVERRIDE, + FINAL +}