Support named constructors in idl-backed code generation

this resolves https://youtrack.jetbrains.com/issue/KT-27361
This commit is contained in:
Shagen Ogandzhanian
2018-12-21 14:13:43 +01:00
parent 68f898153c
commit 6dd69ea3d6
6 changed files with 406 additions and 85 deletions
@@ -647,6 +647,108 @@ public external abstract class HTMLImageElement : HTMLElement, TexImageSource, H
open val y: Int
}
/**
* Exposes the JavaScript [Image](https://developer.mozilla.org/en/docs/Web/API/Image) to Kotlin
*/
public external open class Image(width: Int = definedExternally, height: Int = definedExternally) : HTMLImageElement {
override val children: HTMLCollection
override val firstElementChild: Element?
override val lastElementChild: Element?
override val childElementCount: Int
override val previousElementSibling: Element?
override val nextElementSibling: Element?
override val assignedSlot: HTMLSlotElement?
override val style: CSSStyleDeclaration
override var ongotpointercapture: ((PointerEvent) -> dynamic)?
override var onlostpointercapture: ((PointerEvent) -> dynamic)?
override var onpointerdown: ((PointerEvent) -> dynamic)?
override var onpointermove: ((PointerEvent) -> dynamic)?
override var onpointerup: ((PointerEvent) -> dynamic)?
override var onpointercancel: ((PointerEvent) -> dynamic)?
override var onpointerover: ((PointerEvent) -> dynamic)?
override var onpointerout: ((PointerEvent) -> dynamic)?
override var onpointerenter: ((PointerEvent) -> dynamic)?
override var onpointerleave: ((PointerEvent) -> dynamic)?
override var onabort: ((Event) -> dynamic)?
override var onblur: ((FocusEvent) -> dynamic)?
override var oncancel: ((Event) -> dynamic)?
override var oncanplay: ((Event) -> dynamic)?
override var oncanplaythrough: ((Event) -> dynamic)?
override var onchange: ((Event) -> dynamic)?
override var onclick: ((MouseEvent) -> dynamic)?
override var onclose: ((Event) -> dynamic)?
override var oncontextmenu: ((MouseEvent) -> dynamic)?
override var oncuechange: ((Event) -> dynamic)?
override var ondblclick: ((MouseEvent) -> dynamic)?
override var ondrag: ((DragEvent) -> dynamic)?
override var ondragend: ((DragEvent) -> dynamic)?
override var ondragenter: ((DragEvent) -> dynamic)?
override var ondragexit: ((DragEvent) -> dynamic)?
override var ondragleave: ((DragEvent) -> dynamic)?
override var ondragover: ((DragEvent) -> dynamic)?
override var ondragstart: ((DragEvent) -> dynamic)?
override var ondrop: ((DragEvent) -> dynamic)?
override var ondurationchange: ((Event) -> dynamic)?
override var onemptied: ((Event) -> dynamic)?
override var onended: ((Event) -> dynamic)?
override var onerror: ((dynamic, String, Int, Int, Any?) -> dynamic)?
override var onfocus: ((FocusEvent) -> dynamic)?
override var oninput: ((InputEvent) -> dynamic)?
override var oninvalid: ((Event) -> dynamic)?
override var onkeydown: ((KeyboardEvent) -> dynamic)?
override var onkeypress: ((KeyboardEvent) -> dynamic)?
override var onkeyup: ((KeyboardEvent) -> dynamic)?
override var onload: ((Event) -> dynamic)?
override var onloadeddata: ((Event) -> dynamic)?
override var onloadedmetadata: ((Event) -> dynamic)?
override var onloadend: ((Event) -> dynamic)?
override var onloadstart: ((ProgressEvent) -> dynamic)?
override var onmousedown: ((MouseEvent) -> dynamic)?
override var onmouseenter: ((MouseEvent) -> dynamic)?
override var onmouseleave: ((MouseEvent) -> dynamic)?
override var onmousemove: ((MouseEvent) -> dynamic)?
override var onmouseout: ((MouseEvent) -> dynamic)?
override var onmouseover: ((MouseEvent) -> dynamic)?
override var onmouseup: ((MouseEvent) -> dynamic)?
override var onwheel: ((WheelEvent) -> dynamic)?
override var onpause: ((Event) -> dynamic)?
override var onplay: ((Event) -> dynamic)?
override var onplaying: ((Event) -> dynamic)?
override var onprogress: ((ProgressEvent) -> dynamic)?
override var onratechange: ((Event) -> dynamic)?
override var onreset: ((Event) -> dynamic)?
override var onresize: ((Event) -> dynamic)?
override var onscroll: ((Event) -> dynamic)?
override var onseeked: ((Event) -> dynamic)?
override var onseeking: ((Event) -> dynamic)?
override var onselect: ((Event) -> dynamic)?
override var onshow: ((Event) -> dynamic)?
override var onstalled: ((Event) -> dynamic)?
override var onsubmit: ((Event) -> dynamic)?
override var onsuspend: ((Event) -> dynamic)?
override var ontimeupdate: ((Event) -> dynamic)?
override var ontoggle: ((Event) -> dynamic)?
override var onvolumechange: ((Event) -> dynamic)?
override var onwaiting: ((Event) -> dynamic)?
override var oncopy: ((ClipboardEvent) -> dynamic)?
override var oncut: ((ClipboardEvent) -> dynamic)?
override var onpaste: ((ClipboardEvent) -> dynamic)?
override var contentEditable: String
override val isContentEditable: Boolean
override fun prepend(vararg nodes: dynamic): Unit
override fun append(vararg nodes: dynamic): Unit
override fun querySelector(selectors: String): Element?
override fun querySelectorAll(selectors: String): NodeList
override fun before(vararg nodes: dynamic): Unit
override fun after(vararg nodes: dynamic): Unit
override fun replaceWith(vararg nodes: dynamic): Unit
override fun remove(): Unit
override fun getBoxQuads(options: BoxQuadOptions /* = definedExternally */): Array<DOMQuad>
override fun convertQuadFromNode(quad: dynamic, from: dynamic, options: ConvertCoordinateOptions /* = definedExternally */): DOMQuad
override fun convertRectFromNode(rect: DOMRectReadOnly, from: dynamic, options: ConvertCoordinateOptions /* = definedExternally */): DOMQuad
override fun convertPointFromNode(point: DOMPointInit, from: dynamic, options: ConvertCoordinateOptions /* = definedExternally */): DOMPoint
}
/**
* Exposes the JavaScript [HTMLIFrameElement](https://developer.mozilla.org/en/docs/Web/API/HTMLIFrameElement) to Kotlin
*/
@@ -745,6 +847,105 @@ public external abstract class HTMLVideoElement : HTMLMediaElement, TexImageSour
public external abstract class HTMLAudioElement : HTMLMediaElement {
}
public external open class Audio(src: String = definedExternally) : HTMLAudioElement {
override val children: HTMLCollection
override val firstElementChild: Element?
override val lastElementChild: Element?
override val childElementCount: Int
override val previousElementSibling: Element?
override val nextElementSibling: Element?
override val assignedSlot: HTMLSlotElement?
override val style: CSSStyleDeclaration
override var ongotpointercapture: ((PointerEvent) -> dynamic)?
override var onlostpointercapture: ((PointerEvent) -> dynamic)?
override var onpointerdown: ((PointerEvent) -> dynamic)?
override var onpointermove: ((PointerEvent) -> dynamic)?
override var onpointerup: ((PointerEvent) -> dynamic)?
override var onpointercancel: ((PointerEvent) -> dynamic)?
override var onpointerover: ((PointerEvent) -> dynamic)?
override var onpointerout: ((PointerEvent) -> dynamic)?
override var onpointerenter: ((PointerEvent) -> dynamic)?
override var onpointerleave: ((PointerEvent) -> dynamic)?
override var onabort: ((Event) -> dynamic)?
override var onblur: ((FocusEvent) -> dynamic)?
override var oncancel: ((Event) -> dynamic)?
override var oncanplay: ((Event) -> dynamic)?
override var oncanplaythrough: ((Event) -> dynamic)?
override var onchange: ((Event) -> dynamic)?
override var onclick: ((MouseEvent) -> dynamic)?
override var onclose: ((Event) -> dynamic)?
override var oncontextmenu: ((MouseEvent) -> dynamic)?
override var oncuechange: ((Event) -> dynamic)?
override var ondblclick: ((MouseEvent) -> dynamic)?
override var ondrag: ((DragEvent) -> dynamic)?
override var ondragend: ((DragEvent) -> dynamic)?
override var ondragenter: ((DragEvent) -> dynamic)?
override var ondragexit: ((DragEvent) -> dynamic)?
override var ondragleave: ((DragEvent) -> dynamic)?
override var ondragover: ((DragEvent) -> dynamic)?
override var ondragstart: ((DragEvent) -> dynamic)?
override var ondrop: ((DragEvent) -> dynamic)?
override var ondurationchange: ((Event) -> dynamic)?
override var onemptied: ((Event) -> dynamic)?
override var onended: ((Event) -> dynamic)?
override var onerror: ((dynamic, String, Int, Int, Any?) -> dynamic)?
override var onfocus: ((FocusEvent) -> dynamic)?
override var oninput: ((InputEvent) -> dynamic)?
override var oninvalid: ((Event) -> dynamic)?
override var onkeydown: ((KeyboardEvent) -> dynamic)?
override var onkeypress: ((KeyboardEvent) -> dynamic)?
override var onkeyup: ((KeyboardEvent) -> dynamic)?
override var onload: ((Event) -> dynamic)?
override var onloadeddata: ((Event) -> dynamic)?
override var onloadedmetadata: ((Event) -> dynamic)?
override var onloadend: ((Event) -> dynamic)?
override var onloadstart: ((ProgressEvent) -> dynamic)?
override var onmousedown: ((MouseEvent) -> dynamic)?
override var onmouseenter: ((MouseEvent) -> dynamic)?
override var onmouseleave: ((MouseEvent) -> dynamic)?
override var onmousemove: ((MouseEvent) -> dynamic)?
override var onmouseout: ((MouseEvent) -> dynamic)?
override var onmouseover: ((MouseEvent) -> dynamic)?
override var onmouseup: ((MouseEvent) -> dynamic)?
override var onwheel: ((WheelEvent) -> dynamic)?
override var onpause: ((Event) -> dynamic)?
override var onplay: ((Event) -> dynamic)?
override var onplaying: ((Event) -> dynamic)?
override var onprogress: ((ProgressEvent) -> dynamic)?
override var onratechange: ((Event) -> dynamic)?
override var onreset: ((Event) -> dynamic)?
override var onresize: ((Event) -> dynamic)?
override var onscroll: ((Event) -> dynamic)?
override var onseeked: ((Event) -> dynamic)?
override var onseeking: ((Event) -> dynamic)?
override var onselect: ((Event) -> dynamic)?
override var onshow: ((Event) -> dynamic)?
override var onstalled: ((Event) -> dynamic)?
override var onsubmit: ((Event) -> dynamic)?
override var onsuspend: ((Event) -> dynamic)?
override var ontimeupdate: ((Event) -> dynamic)?
override var ontoggle: ((Event) -> dynamic)?
override var onvolumechange: ((Event) -> dynamic)?
override var onwaiting: ((Event) -> dynamic)?
override var oncopy: ((ClipboardEvent) -> dynamic)?
override var oncut: ((ClipboardEvent) -> dynamic)?
override var onpaste: ((ClipboardEvent) -> dynamic)?
override var contentEditable: String
override val isContentEditable: Boolean
override fun prepend(vararg nodes: dynamic): Unit
override fun append(vararg nodes: dynamic): Unit
override fun querySelector(selectors: String): Element?
override fun querySelectorAll(selectors: String): NodeList
override fun before(vararg nodes: dynamic): Unit
override fun after(vararg nodes: dynamic): Unit
override fun replaceWith(vararg nodes: dynamic): Unit
override fun remove(): Unit
override fun getBoxQuads(options: BoxQuadOptions /* = definedExternally */): Array<DOMQuad>
override fun convertQuadFromNode(quad: dynamic, from: dynamic, options: ConvertCoordinateOptions /* = definedExternally */): DOMQuad
override fun convertRectFromNode(rect: DOMRectReadOnly, from: dynamic, options: ConvertCoordinateOptions /* = definedExternally */): DOMQuad
override fun convertPointFromNode(point: DOMPointInit, from: dynamic, options: ConvertCoordinateOptions /* = definedExternally */): DOMPoint
}
/**
* Exposes the JavaScript [HTMLTrackElement](https://developer.mozilla.org/en/docs/Web/API/HTMLTrackElement) to Kotlin
*/
@@ -1260,6 +1461,108 @@ public external abstract class HTMLOptionElement : HTMLElement, UnionHTMLOptGrou
open val index: Int
}
/**
* Exposes the JavaScript [Option](https://developer.mozilla.org/en/docs/Web/API/Option) to Kotlin
*/
public external open class Option(text: String = definedExternally, value: String = definedExternally, defaultSelected: Boolean = definedExternally, selected: Boolean = definedExternally) : HTMLOptionElement {
override val children: HTMLCollection
override val firstElementChild: Element?
override val lastElementChild: Element?
override val childElementCount: Int
override val previousElementSibling: Element?
override val nextElementSibling: Element?
override val assignedSlot: HTMLSlotElement?
override val style: CSSStyleDeclaration
override var ongotpointercapture: ((PointerEvent) -> dynamic)?
override var onlostpointercapture: ((PointerEvent) -> dynamic)?
override var onpointerdown: ((PointerEvent) -> dynamic)?
override var onpointermove: ((PointerEvent) -> dynamic)?
override var onpointerup: ((PointerEvent) -> dynamic)?
override var onpointercancel: ((PointerEvent) -> dynamic)?
override var onpointerover: ((PointerEvent) -> dynamic)?
override var onpointerout: ((PointerEvent) -> dynamic)?
override var onpointerenter: ((PointerEvent) -> dynamic)?
override var onpointerleave: ((PointerEvent) -> dynamic)?
override var onabort: ((Event) -> dynamic)?
override var onblur: ((FocusEvent) -> dynamic)?
override var oncancel: ((Event) -> dynamic)?
override var oncanplay: ((Event) -> dynamic)?
override var oncanplaythrough: ((Event) -> dynamic)?
override var onchange: ((Event) -> dynamic)?
override var onclick: ((MouseEvent) -> dynamic)?
override var onclose: ((Event) -> dynamic)?
override var oncontextmenu: ((MouseEvent) -> dynamic)?
override var oncuechange: ((Event) -> dynamic)?
override var ondblclick: ((MouseEvent) -> dynamic)?
override var ondrag: ((DragEvent) -> dynamic)?
override var ondragend: ((DragEvent) -> dynamic)?
override var ondragenter: ((DragEvent) -> dynamic)?
override var ondragexit: ((DragEvent) -> dynamic)?
override var ondragleave: ((DragEvent) -> dynamic)?
override var ondragover: ((DragEvent) -> dynamic)?
override var ondragstart: ((DragEvent) -> dynamic)?
override var ondrop: ((DragEvent) -> dynamic)?
override var ondurationchange: ((Event) -> dynamic)?
override var onemptied: ((Event) -> dynamic)?
override var onended: ((Event) -> dynamic)?
override var onerror: ((dynamic, String, Int, Int, Any?) -> dynamic)?
override var onfocus: ((FocusEvent) -> dynamic)?
override var oninput: ((InputEvent) -> dynamic)?
override var oninvalid: ((Event) -> dynamic)?
override var onkeydown: ((KeyboardEvent) -> dynamic)?
override var onkeypress: ((KeyboardEvent) -> dynamic)?
override var onkeyup: ((KeyboardEvent) -> dynamic)?
override var onload: ((Event) -> dynamic)?
override var onloadeddata: ((Event) -> dynamic)?
override var onloadedmetadata: ((Event) -> dynamic)?
override var onloadend: ((Event) -> dynamic)?
override var onloadstart: ((ProgressEvent) -> dynamic)?
override var onmousedown: ((MouseEvent) -> dynamic)?
override var onmouseenter: ((MouseEvent) -> dynamic)?
override var onmouseleave: ((MouseEvent) -> dynamic)?
override var onmousemove: ((MouseEvent) -> dynamic)?
override var onmouseout: ((MouseEvent) -> dynamic)?
override var onmouseover: ((MouseEvent) -> dynamic)?
override var onmouseup: ((MouseEvent) -> dynamic)?
override var onwheel: ((WheelEvent) -> dynamic)?
override var onpause: ((Event) -> dynamic)?
override var onplay: ((Event) -> dynamic)?
override var onplaying: ((Event) -> dynamic)?
override var onprogress: ((ProgressEvent) -> dynamic)?
override var onratechange: ((Event) -> dynamic)?
override var onreset: ((Event) -> dynamic)?
override var onresize: ((Event) -> dynamic)?
override var onscroll: ((Event) -> dynamic)?
override var onseeked: ((Event) -> dynamic)?
override var onseeking: ((Event) -> dynamic)?
override var onselect: ((Event) -> dynamic)?
override var onshow: ((Event) -> dynamic)?
override var onstalled: ((Event) -> dynamic)?
override var onsubmit: ((Event) -> dynamic)?
override var onsuspend: ((Event) -> dynamic)?
override var ontimeupdate: ((Event) -> dynamic)?
override var ontoggle: ((Event) -> dynamic)?
override var onvolumechange: ((Event) -> dynamic)?
override var onwaiting: ((Event) -> dynamic)?
override var oncopy: ((ClipboardEvent) -> dynamic)?
override var oncut: ((ClipboardEvent) -> dynamic)?
override var onpaste: ((ClipboardEvent) -> dynamic)?
override var contentEditable: String
override val isContentEditable: Boolean
override fun prepend(vararg nodes: dynamic): Unit
override fun append(vararg nodes: dynamic): Unit
override fun querySelector(selectors: String): Element?
override fun querySelectorAll(selectors: String): NodeList
override fun before(vararg nodes: dynamic): Unit
override fun after(vararg nodes: dynamic): Unit
override fun replaceWith(vararg nodes: dynamic): Unit
override fun remove(): Unit
override fun getBoxQuads(options: BoxQuadOptions /* = definedExternally */): Array<DOMQuad>
override fun convertQuadFromNode(quad: dynamic, from: dynamic, options: ConvertCoordinateOptions /* = definedExternally */): DOMQuad
override fun convertRectFromNode(rect: DOMRectReadOnly, from: dynamic, options: ConvertCoordinateOptions /* = definedExternally */): DOMQuad
override fun convertPointFromNode(point: DOMPointInit, from: dynamic, options: ConvertCoordinateOptions /* = definedExternally */): DOMPoint
}
/**
* Exposes the JavaScript [HTMLTextAreaElement](https://developer.mozilla.org/en/docs/Web/API/HTMLTextAreaElement) to Kotlin
*/
@@ -85,15 +85,15 @@ val inheritanceExclude = mapOf(
)
val kotlinBuiltinInterfaces = mapOf(
"ItemArrayLike" to GenerateTraitOrClass("ItemArrayLike", "org.w3c.dom", GenerateDefinitionKind.INTERFACE, emptyList(),
memberAttributes = mutableListOf(GenerateAttribute("length", SimpleType("Int", false), null, false, AttributeKind.VAL, false, false, false, false)),
memberFunctions = mutableListOf(GenerateFunction("item", DynamicType, listOf(
"ItemArrayLike" to GenerateClass("ItemArrayLike", "org.w3c.dom", GenerateDefinitionKind.INTERFACE, emptyList(),
memberAttributes = mutableListOf(GenerateAttribute("length", SimpleType("Int", false), null, false, AttributeKind.VAL, false, false, false, false)),
memberFunctions = mutableListOf(GenerateFunction("item", DynamicType, listOf(
GenerateAttribute("index", SimpleType("Int", false), null, false, AttributeKind.ARGUMENT, false, false, false, false)
), NativeGetterOrSetter.NONE, false, false)),
constants = emptyList(),
generateBuilderFunction = false,
primaryConstructor = null,
secondaryConstructors = emptyList()
constants = emptyList(),
generateBuilderFunction = false,
primaryConstructor = null,
secondaryConstructors = emptyList()
)
)
+48 -22
View File
@@ -107,15 +107,23 @@ fun generateAttribute(putNoImpl: Boolean, repository: Repository, attribute: Att
)
}
private fun InterfaceDefinition.isInterface() : Boolean {
return when {
dictionary -> true
extendedAttributes.any { it.call == "NoInterfaceObject" } -> true
callback -> true
else -> false
}
}
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 =
when {
iface.dictionary -> GenerateDefinitionKind.INTERFACE
iface.extendedAttributes.any { it.call == "NoInterfaceObject" } -> GenerateDefinitionKind.INTERFACE
iface.isInterface() -> GenerateDefinitionKind.INTERFACE
constructors.isNotEmpty() || iface.superTypes(repository).any { resolveDefinitionKind(repository, it) == GenerateDefinitionKind.CLASS } -> {
GenerateDefinitionKind.CLASS
}
iface.callback -> GenerateDefinitionKind.INTERFACE
else -> GenerateDefinitionKind.ABSTRACT_CLASS
}
@@ -125,7 +133,7 @@ private fun InterfaceDefinition.mapOperations(repository: Repository) = operatio
private fun Constant.mapConstant(repository : Repository) = GenerateAttribute(name, mapType(repository, type), null, false, AttributeKind.VAL, false, false, true, false)
private val EMPTY_CONSTRUCTOR = ExtendedAttribute(null, "Constructor", emptyList())
fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateTraitOrClass {
fun generateTrait(repository: Repository, iface: InterfaceDefinition): List<GenerateClass> {
val superClasses = iface.superTypes
.mapNotNull { repository.interfaces[it] }
.filter {
@@ -161,19 +169,38 @@ fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateT
ConstructorWithSuperTypeCall(constructorAsFunction, secondaryConstructor)
}
val result = GenerateTraitOrClass(iface.name, iface.namespace, entityKind, (iface.superTypes + extensions.map { it.name }).distinct(),
memberAttributes = iface.mapAttributes(repository).toMutableList(),
memberFunctions = iface.mapOperations(repository).toMutableList(),
constants = (iface.constants.map { it.mapConstant(repository) } + extensions.flatMap { it.constants.map { it.mapConstant(repository) } }.distinct().toList()),
primaryConstructor = primaryConstructorWithCall,
secondaryConstructors = secondaryConstructorsWithCall,
generateBuilderFunction = iface.dictionary
)
val memberAttributes = iface.mapAttributes(repository)
val memberFunctions = iface.mapOperations(repository)
return markAsArrayLikeIfApplicable(result)
val extensionsNames = extensions.map { it.name }
val namedConstructors =
iface.findExtendedAttributes("NamedConstructor").map { namedConstructor ->
GenerateClass(
name = namedConstructor.call,
namespace = iface.namespace,
kind = GenerateDefinitionKind.CLASS,
superTypes = listOf(iface.name) + extensionsNames,
memberAttributes = memberAttributes.toMutableList(),
memberFunctions = memberFunctions.toMutableList(),
constants = emptyList(),
primaryConstructor = ConstructorWithSuperTypeCall(generateConstructorAsFunction(repository, namedConstructor), namedConstructor),
secondaryConstructors = emptyList(),
generateBuilderFunction = false
)
}
return (listOf(GenerateClass(iface.name, iface.namespace, entityKind, (iface.superTypes + extensionsNames).distinct(),
memberAttributes = memberAttributes.toMutableList(),
memberFunctions = memberFunctions.toMutableList(),
constants = (iface.constants.map { it.mapConstant(repository) } + extensions.flatMap { it.constants.map { it.mapConstant(repository) } }.distinct().toList()),
primaryConstructor = primaryConstructorWithCall,
secondaryConstructors = secondaryConstructorsWithCall,
generateBuilderFunction = iface.dictionary
)) + namedConstructors).map(::markAsArrayLikeIfApplicable)
}
fun markAsArrayLikeIfApplicable(iface: GenerateTraitOrClass): GenerateTraitOrClass {
fun markAsArrayLikeIfApplicable(iface: GenerateClass): GenerateClass {
fun isInt(type: Type) = type is SimpleType && type.type == "Int"
val lengthProperty = iface.memberAttributes.singleOrNull { it.name == "length" && isInt(it.type) }
@@ -191,7 +218,7 @@ fun generateConstructorAsFunction(repository: Repository, constructor: ExtendedA
nativeGetterOrSetter = NativeGetterOrSetter.NONE)
fun mapUnionType(it: UnionType) = GenerateTraitOrClass(
fun mapUnionType(it: UnionType) = GenerateClass(
name = it.name,
namespace = it.namespace,
kind = GenerateDefinitionKind.INTERFACE,
@@ -204,12 +231,12 @@ fun mapUnionType(it: UnionType) = GenerateTraitOrClass(
generateBuilderFunction = false
)
fun generateUnionTypeTraits(allUnionTypes: Sequence<UnionType>): Sequence<GenerateTraitOrClass> = allUnionTypes.map(::mapUnionType)
fun generateUnionTypeTraits(allUnionTypes: Sequence<UnionType>): Sequence<GenerateClass> = allUnionTypes.map(::mapUnionType)
fun mapDefinitions(repository: Repository, definitions: Iterable<InterfaceDefinition>) =
definitions.map { generateTrait(repository, it) }
definitions.flatMap { generateTrait(repository, it) }
fun generateUnions(ifaces: List<GenerateTraitOrClass>, typedefs: Iterable<TypedefDefinition>): GenerateUnionTypes {
fun generateUnions(ifaces: List<GenerateClass>, typedefs: Iterable<TypedefDefinition>): GenerateUnionTypes {
val declaredTypes = ifaces.associateBy { it.name }
val anonymousUnionTypes = collectUnionTypes(declaredTypes)
@@ -259,8 +286,7 @@ private fun mapLiteral(literal: String?, expectedType: Type = DynamicType, enums
}
}
private fun specifyType(name: String, type: Type, context: String): Type {
private fun specifyType(name: String, type: Type, context: String): Type {
if ((type is SimpleType) && (type.type == "Event")) {
(eventSpecifierMapper[name] ?: eventSpecifierMapperWithContext[EventMapKey(name, context)])?.let {
@@ -279,7 +305,7 @@ private fun generalizeType(name: String, type: Type, context: String): Type {
return type
}
fun implementInterfaces(declarations: List<GenerateTraitOrClass>) : List<GenerateTraitOrClass> {
fun implementInterfaces(declarations: List<GenerateClass>) : List<GenerateClass> {
val unimplementedMemberMap = getUnimplementedMembers(declarations)
val nonAbstractDeclarations = declarations.filter { it.kind == GenerateDefinitionKind.CLASS }
for (declaration in nonAbstractDeclarations) {
@@ -301,7 +327,7 @@ fun implementInterfaces(declarations: List<GenerateTraitOrClass>) : List<Generat
}
}
private fun getUnimplementedMembers(declarations: List<GenerateTraitOrClass>): Map<String, UnimplementedMembers> {
private fun getUnimplementedMembers(declarations: List<GenerateClass>): Map<String, UnimplementedMembers> {
val declarationMap = declarations.associate { it.name to it }
val unimplementedMemberCache = mutableMapOf<String, UnimplementedMembers>()
+17 -18
View File
@@ -63,7 +63,6 @@ enum class GenerateDefinitionKind {
ABSTRACT_CLASS
}
data class GenerateFunctionCall(val name: String, val arguments: List<String>)
data class GenerateFunction(
val name: String,
val returnType: Type,
@@ -74,17 +73,18 @@ data class GenerateFunction(
)
data class ConstructorWithSuperTypeCall(val constructor: GenerateFunction, val constructorAttribute: ExtendedAttribute)
data class GenerateTraitOrClass(
val name: String,
val namespace: String,
val kind: GenerateDefinitionKind,
val superTypes: List<String>,
val memberAttributes: MutableList<GenerateAttribute>,
val memberFunctions: MutableList<GenerateFunction>,
val constants: List<GenerateAttribute>,
val primaryConstructor: ConstructorWithSuperTypeCall?,
val secondaryConstructors: List<ConstructorWithSuperTypeCall>,
val generateBuilderFunction: Boolean
data class GenerateClass(
val name: String,
val namespace: String,
val kind: GenerateDefinitionKind,
val superTypes: List<String>,
val memberAttributes: MutableList<GenerateAttribute>,
val memberFunctions: MutableList<GenerateFunction>,
val constants: List<GenerateAttribute>,
val primaryConstructor: ConstructorWithSuperTypeCall?,
val secondaryConstructors: List<ConstructorWithSuperTypeCall>,
val generateBuilderFunction: Boolean
)
val GenerateFunction.signature: String
@@ -94,12 +94,11 @@ fun GenerateFunction.dynamicIfUnknownType(allTypes : Set<String>) = standardType
copy(returnType = returnType.dynamicIfUnknownType(allTypes, standardTypes), arguments = arguments.map { it.dynamicIfUnknownType(allTypes, standardTypes) })
}
fun InterfaceDefinition.findExtendedAttributes(name: String) = extendedAttributes.filter { it.call == name }
fun InterfaceDefinition?.hasExtendedAttribute(name: String) = this?.findExtendedAttributes(name)?.isNotEmpty() ?: false
fun InterfaceDefinition.findConstructors() = findExtendedAttributes("Constructor")
fun InterfaceDefinition.findExtendedAttributes(name: String) = extendedAttributes.filter { it.name == name }
fun InterfaceDefinition.findConstructors() = extendedAttributes.filter { it.call == "Constructor" }
data class GenerateUnionTypes(
val typeNamesToUnionsMap: Map<String, List<String>>,
val anonymousUnionsMap: Map<String, GenerateTraitOrClass>,
val typedefsMarkersMap: Map<String, GenerateTraitOrClass>
val typeNamesToUnionsMap: Map<String, List<String>>,
val anonymousUnionsMap: Map<String, GenerateClass>,
val typedefsMarkersMap: Map<String, GenerateClass>
)
+15 -12
View File
@@ -100,8 +100,6 @@ private fun Appendable.renderArgumentsDeclaration(args: List<GenerateAttribute>,
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 Appendable.renderFunctionDeclaration(owner: String, f: GenerateFunction, override: Boolean, commented: Boolean, level: Int = 1) {
indent(commented, level)
@@ -147,7 +145,8 @@ private fun GenerateFunction.isCommented(parent: String) =
private fun GenerateAttribute.isRequiredFunctionArgument(owner: String, functionName: String) = "$owner.$functionName.$name" in requiredArguments
private fun GenerateFunction.fixRequiredArguments(parent: String) = copy(arguments = arguments.map { arg -> arg.copy(initializer = if (arg.isRequiredFunctionArgument(parent, name)) null else arg.initializer) })
fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, enums: List<EnumDefinition>, typeNamesToUnions: Map<String, List<String>>, iface: GenerateTraitOrClass, markerAnnotation: Boolean = false, mdnCache: MDNDocumentationCache? = null) {
fun Appendable.render(allTypes: Map<String, GenerateClass>, enums: List<EnumDefinition>, typeNamesToUnions: Map<String, List<String>>, iface: GenerateClass, markerAnnotation: Boolean = false, mdnCache: MDNDocumentationCache? = null) {
val url = "https://developer.mozilla.org/en/docs/Web/API/${iface.name}"
if (mdnCache?.checkInCache(url) == true) {
appendln("/**")
@@ -182,6 +181,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, enums: List<E
(typeNamesToUnions[iface.name] ?: emptyList()) +
(iface.superTypes.filter { it.substringBefore("<") in kotlinBuiltinInterfaces }) // TODO in theory we have to parse type but for now it is the only place needs it so let's just cut string
if (superTypesWithCalls.isNotEmpty()) {
superTypesWithCalls.joinTo(this, ", ", " : ")
}
@@ -218,6 +218,10 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, enums: List<E
else -> MemberModality.FINAL
}
val skipAttributeDeclaration = modality == MemberModality.OVERRIDE
&& attribute.kindNotChanged(superAttributesByName)
&& (iface.kind == GenerateDefinitionKind.INTERFACE || attribute.hasSuperImplementation(allSuperTypes))
if (attribute.name in superAttributesByName && attribute.signature !in superSignatures) {
System.err.println("Property ${iface.name}.${attribute.name} has different type in super type(s) so will not be generated: ")
for ((superTypeName, attributes) in allSuperTypes.map { it.name to it.memberAttributes.filter { it.name == attribute.name }.distinct() }) {
@@ -225,10 +229,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, enums: List<E
System.err.println(" $superTypeName.${attribute.name}: ${superAttribute.type.render()}")
}
}
} else if (modality == MemberModality.OVERRIDE
&& attribute.kindNotChanged(superAttributesByName)
&& (iface.kind == GenerateDefinitionKind.INTERFACE || attribute.hasSuperImplementation(allSuperTypes))
) {
} else if (skipAttributeDeclaration) {
// then don't generate
} else {
renderAttributeDeclarationAsProperty(attribute,
@@ -239,8 +240,9 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, enums: List<E
)
}
}
val memberFunctions = iface.memberFunctions.filter { (it !in superFunctions || it.override) && !it.static }
.map { it.dynamicIfUnknownType(allTypesAndEnums) }.groupBy { it.signature }.reduceValues(::betterFunction).values
val memberFunctions= iface.memberFunctions.filter {
(it !in superFunctions || it.override) && !it.static
}.map { it.dynamicIfUnknownType(allTypesAndEnums) }.groupBy { it.signature }.reduceValues(::betterFunction).values
fun doRenderFunction(function: GenerateFunction, level: Int = 1) {
renderFunctionDeclaration(
@@ -284,12 +286,12 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, enums: List<E
private fun GenerateAttribute.kindNotChanged(superAttributesByName: Map<String, List<GenerateAttribute>>) = superAttributesByName[name].orEmpty().all { it.kind == kind }
private fun GenerateAttribute.hasSuperImplementation(allSuperTypes: List<GenerateTraitOrClass>) = allSuperTypes.any { st -> st.kind != GenerateDefinitionKind.INTERFACE && st.memberAttributes.any { it.signature == signature } }
private fun GenerateAttribute.hasSuperImplementation(allSuperTypes: List<GenerateClass>) = allSuperTypes.any { st -> st.kind != GenerateDefinitionKind.INTERFACE && st.memberAttributes.any { it.signature == signature } }
private fun GenerateAttribute.hasNoDefaultValue() =
this.initializer == null && (this.type.nullable || this.type == DynamicType) && !this.required
fun Appendable.renderBuilderFunction(dictionary: GenerateTraitOrClass, allSuperTypes: List<GenerateTraitOrClass>, allTypes: Set<String>) {
fun Appendable.renderBuilderFunction(dictionary: GenerateClass, allSuperTypes: List<GenerateClass>, allTypes: Set<String>) {
val fields = (dictionary.memberAttributes + allSuperTypes.flatMap { it.memberAttributes })
.distinctBy { it.signature }
.map { it.copy(kind = AttributeKind.ARGUMENT) }
@@ -397,10 +399,11 @@ fun Appendable.render(enumDefinition: EnumDefinition) {
appendln()
}
fun Appendable.render(namespace: String, ifaces: List<GenerateTraitOrClass>, unions: GenerateUnionTypes, enums: List<EnumDefinition>, mdnCache: MDNDocumentationCache) {
fun Appendable.render(namespace: String, ifaces: List<GenerateClass>, unions: GenerateUnionTypes, enums: List<EnumDefinition>, mdnCache: MDNDocumentationCache) {
val declaredTypes = ifaces.associateBy { it.name }
val allTypes = declaredTypes + unions.anonymousUnionsMap + unions.typedefsMarkersMap
declaredTypes.values.filter { it.namespace == namespace }.forEach {
render(allTypes, enums, unions.typeNamesToUnionsMap, it, mdnCache = mdnCache)
}
@@ -46,14 +46,9 @@ private val typeMapper = mapOf(
)
fun GenerateTraitOrClass.allSuperTypes(all: Map<String, GenerateTraitOrClass>) =
LinkedHashSet<GenerateTraitOrClass>().let { result -> allSuperTypesImpl(listOf(this), all, result); result.toList() }
fun GenerateClass.allSuperTypes(all: Map<String, GenerateClass>) = LinkedHashSet<GenerateClass>().let { result -> allSuperTypesImpl(listOf(this), all, result); result.toList() }
tailrec fun allSuperTypesImpl(
roots: List<GenerateTraitOrClass>,
all: Map<String, GenerateTraitOrClass>,
result: MutableSet<GenerateTraitOrClass>
) {
tailrec fun allSuperTypesImpl(roots: List<GenerateClass>, all: Map<String, GenerateClass>, result: MutableSet<GenerateClass>) {
if (roots.isNotEmpty()) {
allSuperTypesImpl(roots.flatMap { it.superTypes }.map {
all[it] ?: all[it.substringBefore("<")]
@@ -132,27 +127,22 @@ private fun mapTypedef(repository: Repository, type: SimpleType): Type {
private fun GenerateFunction?.allTypes() =
if (this != null) sequenceOf(returnType) + arguments.asSequence().map { it.type } else emptySequence()
internal fun collectUnionTypes(allTypes: Map<String, GenerateTraitOrClass>) =
allTypes.values.asSequence()
.flatMap {
it.secondaryConstructors.asSequence().flatMap { it.constructor.allTypes() } +
internal fun collectUnionTypes(allTypes: Map<String, GenerateClass>) =
allTypes.values.asSequence()
.flatMap {
it.secondaryConstructors.asSequence().flatMap { it.constructor.allTypes() } +
sequenceOf(it.primaryConstructor).filterNotNull().flatMap { it.constructor.allTypes() } +
it.memberAttributes.asSequence().map { it.type } +
it.memberFunctions.asSequence().flatMap { it.allTypes() }
}
.filterIsInstance<UnionType>()
.map { it.dropNullable() }
.filter { it.memberTypes.all { unionMember -> unionMember is SimpleType && unionMember.type in allTypes } }
.distinct()
.map {
it.copy(
namespace = guessPackage(it.memberTypes.filterIsInstance<SimpleType>().map { it.type }, allTypes),
types = it.memberTypes
)
}
it.memberAttributes.asSequence().map { it.type } +
it.memberFunctions.asSequence().flatMap { it.allTypes() }
}
.filterIsInstance<UnionType>()
.map { it.dropNullable() }
.filter { it.memberTypes.all { unionMember -> unionMember is SimpleType && unionMember.type in allTypes } }
.distinct()
.map { it.copy(namespace = guessPackage(it.memberTypes.filterIsInstance<SimpleType>().map { it.type }, allTypes), types = it.memberTypes) }
private fun guessPackage(types: List<String>, allTypes: Map<String, GenerateTraitOrClass>) =
types.map { allTypes[it] }
private fun guessPackage(types : List<String>, allTypes: Map<String, GenerateClass>) =
types.map { allTypes[it] }
.map { it?.namespace }
.filterNotNull()
.filter { it.isNotEmpty() }