JS: when possible, treat WebIDL interfaces as abstract classes, not interfaces

This commit is contained in:
Alexey Andreev
2016-09-30 19:31:21 +03:00
committed by Sergey Mashkov
parent f415050913
commit 9c8b58b8bf
3 changed files with 50 additions and 20 deletions
+14 -6
View File
@@ -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 InterfaceDefinition.superTypes(repository: Repository) = superTypes.map { repository.interfaces[it] }.filterNotNull()
private fun resolveDefinitionKind(repository: Repository, iface: InterfaceDefinition, constructors: List<ExtendedAttribute> = iface.findConstructors()): GenerateDefinitionKind = private fun resolveDefinitionKind(repository: Repository, iface: InterfaceDefinition, constructors: List<ExtendedAttribute> = iface.findConstructors()): GenerateDefinitionKind =
if (constructors.isNotEmpty() || iface.superTypes(repository).any { resolveDefinitionKind(repository, it) == GenerateDefinitionKind.CLASS }) { when {
GenerateDefinitionKind.CLASS constructors.isNotEmpty() || iface.superTypes(repository).any { resolveDefinitionKind(repository, it) == GenerateDefinitionKind.CLASS } -> {
} else { GenerateDefinitionKind.CLASS
GenerateDefinitionKind.TRAIT }
iface.callback -> GenerateDefinitionKind.TRAIT
else -> GenerateDefinitionKind.ABSTRACT_CLASS
} }
private fun InterfaceDefinition.mapAttributes(repository: Repository) = attributes.map { generateAttribute(!dictionary, repository, it) } 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 val superClasses = iface.superTypes
.map { repository.interfaces[it] } .map { repository.interfaces[it] }
.filterNotNull() .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 }}" } assert(superClasses.size <= 1) { "Type ${iface.name} should have one or zero super classes but found ${superClasses.map { it.name }}" }
val superClass = superClasses.singleOrNull() val superClass = superClasses.singleOrNull()
@@ -104,7 +112,7 @@ fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateT
val primaryConstructor = when { val primaryConstructor = when {
declaredConstructors.size == 1 -> declaredConstructors.single() 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() } else -> declaredConstructors.firstOrNull { it.arguments.isEmpty() }
} }
val secondaryConstructors = declaredConstructors.filter { it != primaryConstructor } val secondaryConstructors = declaredConstructors.filter { it != primaryConstructor }
@@ -59,7 +59,8 @@ enum class NativeGetterOrSetter {
enum class GenerateDefinitionKind { enum class GenerateDefinitionKind {
TRAIT, TRAIT,
CLASS CLASS,
ABSTRACT_CLASS
} }
data class GenerateFunctionCall(val name: String, val arguments: List<String>) data class GenerateFunctionCall(val name: String, val arguments: List<String>)
+34 -13
View File
@@ -11,11 +11,17 @@ private fun <O : Appendable> O.indent(commented: Boolean = false, level: Int) {
} }
} }
private fun Appendable.renderAttributeDeclaration(arg: GenerateAttribute, override: Boolean, open: Boolean, omitDefaults: Boolean = false) { private fun Appendable.renderAttributeDeclaration(arg: GenerateAttribute, modality: MemberModality, omitDefaults: Boolean = false) {
when { if (arg.vararg) {
override -> append("override ") append("vararg ")
open -> append("open ") }
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) { 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) indent(commented, level)
renderAttributeDeclaration(arg, override, open, omitDefaults) renderAttributeDeclaration(arg, modality, omitDefaults)
appendln() appendln()
if (arg.getterNoImpl) { if (arg.getterNoImpl) {
@@ -60,7 +66,7 @@ private fun String.replaceKeywords() = if (this in keywords) this + "_" else thi
private fun Appendable.renderArgumentsDeclaration(args: List<GenerateAttribute>, omitDefaults: Boolean = false) = private fun Appendable.renderArgumentsDeclaration(args: List<GenerateAttribute>, omitDefaults: Boolean = false) =
args.joinTo(this, ", ", "(", ")") { 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)})" private fun renderCall(call: GenerateFunctionCall) = "${call.name.replaceKeywords()}(${call.arguments.joinToString(separator = ", ", transform = String::replaceKeywords)})"
@@ -108,6 +114,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
} }
when (iface.kind) { when (iface.kind) {
GenerateDefinitionKind.CLASS -> append("open class ") GenerateDefinitionKind.CLASS -> append("open class ")
GenerateDefinitionKind.ABSTRACT_CLASS -> append("abstract class ")
GenerateDefinitionKind.TRAIT -> append("interface ") GenerateDefinitionKind.TRAIT -> append("interface ")
} }
@@ -154,9 +161,17 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
.filter { it !in superAttributes && !it.static && (it.isVar || (it.isVal && superAttributesByName[it.name]?.hasNoVars() ?: true)) } .filter { it !in superAttributes && !it.static && (it.isVar || (it.isVal && superAttributesByName[it.name]?.hasNoVars() ?: true)) }
.map { it.dynamicIfUnknownType(allTypes.keys) } .map { it.dynamicIfUnknownType(allTypes.keys) }
.groupBy { it.signature }.reduceValues().values.forEach { arg -> .groupBy { it.signature }.reduceValues().values.forEach { arg ->
renderAttributeDeclarationAsProperty(arg, val modality = when {
override = arg.signature in superSignatures, arg.signature in superSignatures -> MemberModality.OVERRIDE
open = iface.kind == GenerateDefinitionKind.CLASS && arg.isVal, 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), commented = arg.isCommented(iface.name),
omitDefaults = iface.kind == GenerateDefinitionKind.TRAIT, omitDefaults = iface.kind == GenerateDefinitionKind.TRAIT,
level = 1 level = 1
@@ -174,10 +189,10 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
indent(false, 1) indent(false, 1)
appendln("companion object {") appendln("companion object {")
iface.constants.forEach { 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 { 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 { staticFunctions.forEach {
renderFunctionDeclaration(it.fixRequiredArguments(iface.name), override = false, level = 2, commented = it.isCommented(iface.name)) 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<GenerateTraitOrClass>, uni
} }
} }
enum class MemberModality {
OPEN,
ABSTRACT,
OVERRIDE,
FINAL
}