JS better typedefs and union-types support
This commit is contained in:
committed by
Sergey Mashkov
parent
e487825237
commit
374dcd56f2
+674
-148
File diff suppressed because it is too large
Load Diff
@@ -103,6 +103,7 @@ interfaceMember
|
||||
| readWriteAttribute
|
||||
| readWriteMaplike
|
||||
| readWriteSetlike
|
||||
| typedef
|
||||
;
|
||||
|
||||
dictionary
|
||||
|
||||
@@ -61,7 +61,11 @@ private fun handleSpecialTypes(repository: Repository, type: String): String {
|
||||
} else if (type.startsWith("sequence")) {
|
||||
return "Any" // TODO how do we handle sequences?
|
||||
} else if (type in repository.typeDefs) {
|
||||
return "dynamic"
|
||||
val typedef = repository.typeDefs[type]!!
|
||||
|
||||
return if (!typedef.types.startsWith("Union<")) mapType(repository, typedef.types)
|
||||
else if (splitUnionType(typedef.types).size() == 1) mapType(repository, splitUnionType(typedef.types).first())
|
||||
else typedef.name
|
||||
} else if (type in repository.enums) {
|
||||
return "String"
|
||||
} else if (type.endsWith("Callback")) {
|
||||
|
||||
@@ -89,7 +89,7 @@ fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateT
|
||||
return GenerateTraitOrClass(iface.name, entityType, iface.superTypes,
|
||||
memberAttributes = (iface.mapAttributes(repository) + extensions.flatMap { it.mapAttributes(repository) }).distinct().toList(),
|
||||
memberFunctions = (iface.mapOperations(repository) + extensions.flatMap { it.mapOperations(repository) }).distinct().toList(),
|
||||
constnats = iface.constants.map {it.mapConstant(repository)},
|
||||
constnats = (iface.constants.map {it.mapConstant(repository)} + extensions.flatMap { it.constants.map {it.mapConstant(repository)} }.distinct().toList()),
|
||||
constructor = constructorFunction,
|
||||
superConstructorCalls = constructorSuperCalls
|
||||
)
|
||||
@@ -124,23 +124,31 @@ private fun collectUnionTypes(allTypes: Map<String, GenerateTraitOrClass>) =
|
||||
.toSet()
|
||||
.map { UnionType(it) }
|
||||
|
||||
fun generateUnionTypeTraits(allUnionTypes : Iterable<UnionType>): List<GenerateTraitOrClass> =
|
||||
allUnionTypes.map { GenerateTraitOrClass(
|
||||
name = it.name,
|
||||
type = GenerateDefinitionType.TRAIT,
|
||||
superTypes = emptyList(),
|
||||
memberAttributes = emptyList(),
|
||||
memberFunctions = emptyList(),
|
||||
constnats = emptyList(),
|
||||
constructor = null,
|
||||
superConstructorCalls = emptyList()
|
||||
) }
|
||||
fun mapUnionType(it : UnionType) = GenerateTraitOrClass(
|
||||
name = it.name,
|
||||
type = GenerateDefinitionType.TRAIT,
|
||||
superTypes = emptyList(),
|
||||
memberAttributes = emptyList(),
|
||||
memberFunctions = emptyList(),
|
||||
constnats = emptyList(),
|
||||
constructor = null,
|
||||
superConstructorCalls = emptyList()
|
||||
)
|
||||
|
||||
fun generateUnionTypeTraits(allUnionTypes : Iterable<UnionType>): List<GenerateTraitOrClass> = allUnionTypes.map(::mapUnionType)
|
||||
|
||||
fun mapDefinitions(repository: Repository, definitions: Iterable<InterfaceDefinition>) =
|
||||
definitions.filter { "NoInterfaceObject" !in it.extendedAttributes.map { it.call } }.map { generateTrait(repository, it) }
|
||||
|
||||
private fun <O : Appendable> O.renderAttributeDeclaration(allTypes: Set<String>, arg: GenerateAttribute, override: Boolean) {
|
||||
append(" ")
|
||||
|
||||
private fun <O: Appendable> O.indent(level : Int) {
|
||||
for (i in 1..level) {
|
||||
append(" ")
|
||||
}
|
||||
}
|
||||
|
||||
private fun <O : Appendable> O.renderAttributeDeclaration(allTypes: Set<String>, arg: GenerateAttribute, override: Boolean, level : Int = 1) {
|
||||
indent(level)
|
||||
|
||||
if (override) {
|
||||
append("override ")
|
||||
@@ -158,10 +166,12 @@ private fun <O : Appendable> O.renderAttributeDeclaration(allTypes: Set<String>,
|
||||
|
||||
appendln()
|
||||
if (arg.getterNoImpl) {
|
||||
appendln(" get() = noImpl")
|
||||
indent(level + 1)
|
||||
appendln("get() = noImpl")
|
||||
}
|
||||
if (arg.setterNoImpl) {
|
||||
appendln(" set(value) = noImpl")
|
||||
indent(level + 1)
|
||||
appendln("set(value) = noImpl")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +199,7 @@ private fun <O : Appendable> O.renderArgumentsDeclaration(allTypes: Set<String>,
|
||||
private fun renderCall(call: GenerateFunctionCall) = "${call.name}(${call.arguments.join(", ")})"
|
||||
|
||||
private fun <O : Appendable> O.renderFunction(allTypes: Set<String>, f: GenerateFunction, override: Boolean) {
|
||||
append(" ")
|
||||
indent(1)
|
||||
|
||||
when (f.native) {
|
||||
NativeGetterOrSetter.GETTER -> append("nativeGetter ")
|
||||
@@ -205,7 +215,7 @@ private fun <O : Appendable> O.renderFunction(allTypes: Set<String>, f: Generate
|
||||
appendln(") : ${f.returnType.mapUnknownType(allTypes)} = noImpl")
|
||||
}
|
||||
|
||||
fun <O : Appendable> O.render(allTypes: Map<String, GenerateTraitOrClass>, classesToUnions : Map<String, List<UnionType>>, iface: GenerateTraitOrClass, markerAnnotation : Boolean = false) {
|
||||
fun <O : Appendable> O.render(allTypes: Map<String, GenerateTraitOrClass>, classesToUnions : Map<String, List<String>>, iface: GenerateTraitOrClass, markerAnnotation : Boolean = false) {
|
||||
val superTypes = iface.allSuperTypes(allTypes).filter { it.name != "" }
|
||||
val superTypesNames = superTypes.map { it.name }.toSet()
|
||||
|
||||
@@ -229,7 +239,7 @@ fun <O : Appendable> O.render(allTypes: Map<String, GenerateTraitOrClass>, class
|
||||
val superTypesWithCalls =
|
||||
iface.superConstructorCalls.filter { it.name in superTypesNames }.map { renderCall(it) } +
|
||||
iface.superTypes.filter { it !in superCalls && it in superTypesNames } +
|
||||
(classesToUnions[iface.name]?.map {it.name} ?: emptyList())
|
||||
(classesToUnions[iface.name] ?: emptyList())
|
||||
|
||||
if (superTypesWithCalls.isNotEmpty()) {
|
||||
superTypesWithCalls.joinTo(this, ", ", " : ")
|
||||
@@ -248,28 +258,41 @@ fun <O : Appendable> O.render(allTypes: Map<String, GenerateTraitOrClass>, class
|
||||
renderFunction(allTypes.keySet(), it, it.proto in superProtos)
|
||||
}
|
||||
if (iface.constnats.isNotEmpty()) {
|
||||
indent(1)
|
||||
appendln("companion object {")
|
||||
iface.constnats.forEach {
|
||||
renderAttributeDeclaration(allTypes.keySet(), it, false)
|
||||
renderAttributeDeclaration(allTypes.keySet(), it, override = false, level = 2)
|
||||
}
|
||||
indent(1)
|
||||
appendln("}")
|
||||
}
|
||||
|
||||
appendln("}")
|
||||
}
|
||||
|
||||
fun <O : Appendable> O.render(ifaces: List<GenerateTraitOrClass>) {
|
||||
fun <O : Appendable> O.render(ifaces: List<GenerateTraitOrClass>, typedefs : Iterable<TypedefDefinition>) {
|
||||
val all = ifaces.groupBy { it.name }.mapValues { it.getValue().single() }
|
||||
val unionTypes = collectUnionTypes(all)
|
||||
val unionTypeTraits = generateUnionTypeTraits(unionTypes)
|
||||
val allUnions = unionTypeTraits.groupBy { it.name }.mapValues { it.getValue().single() }
|
||||
val classesToUnions = unionTypes.flatMap { unionType -> unionType.types.map { it to unionType } }.groupBy { it.first }.mapValues { it.getValue().map { it.second } }
|
||||
val typedefsToBeGenerated = typedefs.filter {it.types.startsWith("Union<")}
|
||||
.map { UnionType(splitUnionType(it.types)) to it.name }
|
||||
.filter { it.first.types.all { type -> type in all} }
|
||||
val typedefsClasses = typedefsToBeGenerated.groupBy { it.second }.mapValues { mapUnionType(it.value.first().first).copy(name = it.key) }
|
||||
|
||||
val classesToUnions = unionTypes.flatMap { unionType -> unionType.types.map { it to unionType } }.groupBy { it.first }.mapValues { it.getValue().map { it.second.name} } +
|
||||
typedefsToBeGenerated.flatMap { typedef -> typedef.first.types.map { it to typedef.second } }.groupBy { it.first }.mapValues { it.getValue().map {it.second} }
|
||||
|
||||
val allTypes = all + allUnions + typedefsClasses
|
||||
ifaces.forEach {
|
||||
render(all + allUnions, classesToUnions, it)
|
||||
render(allTypes, classesToUnions, it)
|
||||
}
|
||||
|
||||
unionTypeTraits.forEach {
|
||||
render(all, emptyMap(), it, markerAnnotation = true)
|
||||
render(allTypes, emptyMap(), it, markerAnnotation = true)
|
||||
}
|
||||
}
|
||||
|
||||
typedefsClasses.values().forEach {
|
||||
render(allTypes, emptyMap(), it, markerAnnotation = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ val urls = listOf(
|
||||
"http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html",
|
||||
"https://raw.githubusercontent.com/whatwg/fetch/master/Overview.src.html",
|
||||
"http://www.w3.org/TR/vibration/",
|
||||
"http://dev.w3.org/csswg/cssom/"
|
||||
"http://dev.w3.org/csswg/cssom/",
|
||||
"https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl"
|
||||
)
|
||||
|
||||
private fun extractIDLText(url: String, out: StringBuilder) {
|
||||
@@ -45,9 +46,11 @@ private fun extractIDLText(url: String, out: StringBuilder) {
|
||||
fun getAllIDLs(): String =
|
||||
StringBuilder {
|
||||
urls.forEach {
|
||||
extractIDLText(it, this)
|
||||
if (it.endsWith(".idl")) {
|
||||
appendln(URL(it).readText())
|
||||
} else {
|
||||
extractIDLText(it, this)
|
||||
}
|
||||
}
|
||||
|
||||
// appendln(constantPart)
|
||||
}.toString()
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ enum class DefinitionType {
|
||||
DICTIONARY
|
||||
}
|
||||
trait Definition
|
||||
data class TypedefDefinition(val from : String, val to : String) : Definition
|
||||
data class TypedefDefinition(val types: String, val name: String) : Definition
|
||||
data class InterfaceDefinition(val name : String, val extendedAttributes: List<ExtendedAttribute>, val operations : List<Operation>, val attributes : List<Attribute>, val superTypes : List<String>, val constants : List<Constant>, val dictionary : Boolean = false) : Definition
|
||||
data class ExtensionInterfaceDefinition(val name : String, val implements : String) : Definition
|
||||
data class EnumDefinition(val name : String) : Definition
|
||||
@@ -256,7 +256,7 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>) : WebID
|
||||
private val attributes = ArrayList<Attribute>()
|
||||
private var readOnly : Boolean = false
|
||||
private val inherited = ArrayList<String>()
|
||||
private var singleType : String? = null
|
||||
private var typedefType: String? = null
|
||||
private var implements : String? = null
|
||||
private val constants = ArrayList<Constant>()
|
||||
|
||||
@@ -264,7 +264,7 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>) : WebID
|
||||
DefinitionType.INTERFACE -> InterfaceDefinition(name, extendedAttributes, operations, attributes, inherited, constants)
|
||||
DefinitionType.DICTIONARY -> InterfaceDefinition(name, extendedAttributes, operations, attributes, inherited, constants, true)
|
||||
DefinitionType.EXTENSION_INTERFACE -> ExtensionInterfaceDefinition(name, implements ?: "")
|
||||
DefinitionType.TYPEDEF -> TypedefDefinition(singleType ?: "", name)
|
||||
DefinitionType.TYPEDEF -> TypedefDefinition(typedefType ?: "", name)
|
||||
DefinitionType.ENUM -> EnumDefinition(name)
|
||||
}
|
||||
|
||||
@@ -281,9 +281,23 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>) : WebID
|
||||
}
|
||||
|
||||
override fun visitTypedef(ctx: WebIDLParser.TypedefContext): Definition {
|
||||
if (name != "") { // TODO temporary workaround for local typedefs
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
type = DefinitionType.TYPEDEF
|
||||
name = getName(ctx)
|
||||
visitChildren(ctx)
|
||||
|
||||
typedefType = ctx.accept(object : WebIDLBaseVisitor<String>() {
|
||||
private var foundType = ""
|
||||
|
||||
override fun defaultResult() : String = foundType
|
||||
|
||||
override fun visitType(ctx: WebIDLParser.TypeContext): String {
|
||||
foundType = TypeVisitor().visit(ctx)
|
||||
return defaultResult()
|
||||
}
|
||||
})
|
||||
|
||||
return defaultResult()
|
||||
}
|
||||
@@ -338,11 +352,6 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>) : WebID
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
override fun visitSingleType(ctx: SingleTypeContext): Definition {
|
||||
singleType = ctx.getText()
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
override fun visitOperation(ctx: OperationContext) : Definition {
|
||||
with(OperationVisitor(memberAttributes.toList())) {
|
||||
operations.add(visit(ctx))
|
||||
@@ -423,7 +432,7 @@ fun parseIDL(reader : Reader) : Repository {
|
||||
|
||||
return Repository(
|
||||
declarations.filterIsInstance<InterfaceDefinition>().filter {it.name.isEmpty().not()}.groupBy { it.name }.mapValues { it.getValue().reduce(::merge) },
|
||||
declarations.filterIsInstance<TypedefDefinition>().groupBy { it.to }.mapValues { it.getValue().first() },
|
||||
declarations.filterIsInstance<TypedefDefinition>().groupBy { it.name }.mapValues { it.getValue().first() },
|
||||
declarations.filterIsInstance<ExtensionInterfaceDefinition>().groupBy { it.name }.mapValues { it.getValue().map {it.implements} },
|
||||
declarations.filterIsInstance<EnumDefinition>().groupBy { it.name }.mapValues { it.getValue().reduce {a, b -> a} }
|
||||
)
|
||||
|
||||
@@ -11,11 +11,15 @@ fun main(args: Array<String>) {
|
||||
idl.lineSequence().forEachIndexed { i, line ->
|
||||
println("${i.toString().padStart(4, ' ')}: ${line}")
|
||||
}
|
||||
|
||||
println()
|
||||
defs.typeDefs.values().forEach { typedef ->
|
||||
println(typedef)
|
||||
}
|
||||
|
||||
val definitions = mapDefinitions(defs, defs.interfaces.values())
|
||||
|
||||
File("../../../js/js.libraries/src/core/dom3.kt").writer().use { w ->
|
||||
File("../../../js/js.libraries/src/core/dom.kt").writer().use { w ->
|
||||
w.appendln("/*")
|
||||
w.appendln(" * Generated file")
|
||||
w.appendln(" * DO NOT EDIT")
|
||||
@@ -27,6 +31,6 @@ fun main(args: Array<String>) {
|
||||
w.appendln("package org.w3c.dom")
|
||||
w.appendln()
|
||||
|
||||
w.render(definitions)
|
||||
w.render(definitions, defs.typeDefs.values())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ enum class GenerateDefinitionType {
|
||||
|
||||
data class GenerateFunction(val name: String, val returnType: String, val arguments: List<GenerateAttribute>, val native : NativeGetterOrSetter)
|
||||
data class GenerateFunctionCall(val name: String, val arguments: List<String>)
|
||||
class GenerateTraitOrClass(val name: String,
|
||||
data class GenerateTraitOrClass(val name: String,
|
||||
val type : GenerateDefinitionType,
|
||||
val superTypes: List<String>,
|
||||
val memberAttributes: List<GenerateAttribute>,
|
||||
|
||||
Reference in New Issue
Block a user