JS better typedefs and union-types support

This commit is contained in:
Sergey Mashkov
2015-04-30 18:26:43 +03:00
committed by Sergey Mashkov
parent e487825237
commit 374dcd56f2
8 changed files with 761 additions and 191 deletions
File diff suppressed because it is too large Load Diff
@@ -103,6 +103,7 @@ interfaceMember
| readWriteAttribute
| readWriteMaplike
| readWriteSetlike
| typedef
;
dictionary
+5 -1
View File
@@ -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")) {
+48 -25
View File
@@ -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()
+19 -10
View File
@@ -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>,