JS IDL2K better callbacks support + bugfixes according to review
This commit is contained in:
committed by
Sergey Mashkov
parent
a11e0a84b5
commit
0ce1edd417
@@ -74,7 +74,7 @@ definition
|
||||
;
|
||||
|
||||
module
|
||||
: 'module' IDENTIFIER_WEBIDL '{' definitions '}' ';'?
|
||||
: 'module' IDENTIFIER_WEBIDL '{' definitions '}' ';'
|
||||
;
|
||||
|
||||
callbackOrInterface
|
||||
|
||||
@@ -23,11 +23,14 @@ import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
val urls = listOf(
|
||||
// "http://heycam.github.io/webidl/" to "org.w3c.webidl"
|
||||
"https://raw.githubusercontent.com/whatwg/html-mirror/master/source" to "org.w3c.dom",
|
||||
"https://html.spec.whatwg.org/" to "org.w3c.dom",
|
||||
"https://raw.githubusercontent.com/whatwg/dom/master/dom.html" to "org.w3c.dom",
|
||||
"http://www.w3.org/TR/uievents/" to "org.w3c.dom.events",
|
||||
"https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html" to "org.w3c.dom",
|
||||
"http://www.w3.org/TR/animation-timing/" to "org.w3c.dom",
|
||||
"http://www.w3.org/TR/hr-time/" to "org.w3c.time",
|
||||
"https://raw.githubusercontent.com/whatwg/xhr/master/Overview.src.html" to "org.w3c.xhr",
|
||||
"https://raw.githubusercontent.com/w3c/FileAPI/gh-pages/index.html" to "org.w3c.files",
|
||||
"https://raw.githubusercontent.com/whatwg/notifications/master/notifications.html" to "org.w3c.notifications",
|
||||
|
||||
@@ -10,21 +10,24 @@ private fun Operation.getterOrSetter() = this.attributes.map { it.call }.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
fun String.isNullable() = endsWith(")?") || (endsWith("?") && !contains("->"))
|
||||
|
||||
fun String.ensureNullable() = when {
|
||||
endsWith("?") -> this
|
||||
this == "dynamic" -> this
|
||||
isNullable() -> this
|
||||
contains("->") -> "($this)?"
|
||||
else -> "$this?"
|
||||
}
|
||||
|
||||
fun String.dropNullable() = when {
|
||||
endsWith(")?") -> this.removeSuffix("?").removeSurrounding("(", ")")
|
||||
contains("->") -> this
|
||||
endsWith("?") -> this.removeSuffix("?")
|
||||
else -> this
|
||||
}
|
||||
|
||||
fun String.copyNullabilityFrom(type : String) = when {
|
||||
type.endsWith("?") -> ensureNullable()
|
||||
type.isNullable() -> ensureNullable()
|
||||
else -> this
|
||||
}
|
||||
|
||||
@@ -32,7 +35,7 @@ fun generateFunction(repository: Repository, function: Operation, functionName:
|
||||
function.attributes.map { it.call }.toSet().let { attributes ->
|
||||
GenerateFunction(
|
||||
name = functionName,
|
||||
returnType = mapType(repository, function.returnType).let { mapped -> if (nativeGetterOrSetter != NativeGetterOrSetter.NONE) mapped.ensureNullable() else mapped },
|
||||
returnType = mapType(repository, function.returnType).let { mapped -> if (nativeGetterOrSetter == NativeGetterOrSetter.GETTER) mapped.ensureNullable() else mapped },
|
||||
arguments = function.parameters.map {
|
||||
GenerateAttribute(
|
||||
name = it.name,
|
||||
@@ -59,9 +62,11 @@ fun generateFunctions(repository: Repository, function: Operation): List<Generat
|
||||
val interfaceType = repository.interfaces[it.type.dropNullable()]
|
||||
when {
|
||||
interfaceType == null -> it
|
||||
interfaceType.operations.size() != 1 -> it
|
||||
interfaceType.callback -> interfaceType.operations.single().let { callbackFunction ->
|
||||
it.copy(type = callbackFunction.parameters
|
||||
.map { mapType(repository, it.type) }
|
||||
.map { it.copy(type = mapType(repository, it.type)) }
|
||||
.map { it.formatFunctionTypePart() }
|
||||
.join(",", "(", ") -> ${mapType(repository, callbackFunction.returnType)}")
|
||||
.copyNullabilityFrom(it.type))
|
||||
}
|
||||
@@ -71,7 +76,8 @@ fun generateFunctions(repository: Repository, function: Operation): List<Generat
|
||||
|
||||
val functionWithCallbackOrNull = when {
|
||||
callbackArgumentsAsLambdas == function.parameters -> null
|
||||
else -> generateFunction(repository, function.copy(parameters = callbackArgumentsAsLambdas), function.name, NativeGetterOrSetter.NONE)
|
||||
realFunction != null -> generateFunction(repository, function.copy(parameters = callbackArgumentsAsLambdas), function.name, NativeGetterOrSetter.NONE)
|
||||
else -> null
|
||||
}
|
||||
|
||||
return listOf(realFunction, getterOrSetterFunction, functionWithCallbackOrNull).filterNotNull()
|
||||
@@ -88,8 +94,8 @@ fun generateAttribute(putNoImpl: Boolean, repository: Repository, attribute: Att
|
||||
)
|
||||
|
||||
private fun InterfaceDefinition.superTypes(repository: Repository) = superTypes.map { repository.interfaces[it] }.filterNotNull()
|
||||
private fun resolveDefinitionType(repository: Repository, iface: InterfaceDefinition, constructor: ExtendedAttribute? = iface.findConstructor()): GenerateDefinitionKind =
|
||||
if (iface.dictionary || constructor != null || iface.superTypes(repository).any { resolveDefinitionType(repository, it) == GenerateDefinitionKind.CLASS }) {
|
||||
private fun resolveDefinitionKind(repository: Repository, iface: InterfaceDefinition, constructor: ExtendedAttribute? = iface.findConstructor()): GenerateDefinitionKind =
|
||||
if (iface.dictionary || constructor != null || iface.superTypes(repository).any { resolveDefinitionKind(repository, it) == GenerateDefinitionKind.CLASS }) {
|
||||
GenerateDefinitionKind.CLASS
|
||||
}
|
||||
else {
|
||||
@@ -108,7 +114,7 @@ fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateT
|
||||
val constructorSuperCalls = iface.superTypes
|
||||
.map { repository.interfaces[it] }
|
||||
.filterNotNull()
|
||||
.filter { resolveDefinitionType(repository, it) == GenerateDefinitionKind.CLASS }
|
||||
.filter { resolveDefinitionKind(repository, it) == GenerateDefinitionKind.CLASS }
|
||||
.map {
|
||||
val superConstructor = it.findConstructor()
|
||||
GenerateFunctionCall(
|
||||
@@ -123,10 +129,10 @@ fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateT
|
||||
)
|
||||
}
|
||||
|
||||
val entityType = resolveDefinitionType(repository, iface, constructor)
|
||||
val entityKind = resolveDefinitionKind(repository, iface, constructor)
|
||||
val extensions = repository.externals[iface.name]?.map { repository.interfaces[it] }?.filterNotNull() ?: emptyList()
|
||||
|
||||
return GenerateTraitOrClass(iface.name, iface.namespace, entityType, iface.superTypes,
|
||||
return GenerateTraitOrClass(iface.name, iface.namespace, entityKind, iface.superTypes,
|
||||
memberAttributes = (iface.mapAttributes(repository) + extensions.flatMap { it.mapAttributes(repository) }).distinct().toList(),
|
||||
memberFunctions = (iface.mapOperations(repository) + extensions.flatMap { it.mapOperations(repository) }).distinct().toList(),
|
||||
constants = (iface.constants.map {it.mapConstant(repository)} + extensions.flatMap { it.constants.map {it.mapConstant(repository)} }.distinct().toList()),
|
||||
@@ -151,3 +157,25 @@ fun generateUnionTypeTraits(allUnionTypes : Iterable<UnionType>): List<GenerateT
|
||||
|
||||
fun mapDefinitions(repository: Repository, definitions: Iterable<InterfaceDefinition>) =
|
||||
definitions.filter { "NoInterfaceObject" !in it.extendedAttributes.map { it.call } }.map { generateTrait(repository, it) }
|
||||
|
||||
fun generateUnions(ifaces: List<GenerateTraitOrClass>, typedefs: Iterable<TypedefDefinition>) : GenerateUnionTypes {
|
||||
val declaredTypes = ifaces.toMap { it.name }
|
||||
|
||||
val anonymousUnionTypes = collectUnionTypes(declaredTypes)
|
||||
val anonymousUnionTypeTraits = generateUnionTypeTraits(anonymousUnionTypes)
|
||||
val anonymousUnionsMap = anonymousUnionTypeTraits.toMap { it.name }
|
||||
|
||||
val typedefsToBeGenerated = typedefs.filter { it.types.startsWith("Union<") }
|
||||
.map { NamedValue(it.name, UnionType(it.namespace, splitUnionType(it.types))) }
|
||||
.filter { it.value.memberTypes.all { type -> type in declaredTypes } }
|
||||
val typedefsMarkersMap = typedefsToBeGenerated.groupBy { it.name }.mapValues { mapUnionType(it.value.first().value).copy(name = it.key) }
|
||||
|
||||
val typeNamesToUnions = anonymousUnionTypes.flatMap { unionType -> unionType.memberTypes.map { unionMember -> unionMember to unionType.name } }.toMultiMap() +
|
||||
typedefsToBeGenerated.flatMap { typedef -> typedef.value.memberTypes.map { unionMember -> unionMember to typedef.name } }.toMultiMap()
|
||||
|
||||
return GenerateUnionTypes(
|
||||
typeNamesToUnions = typeNamesToUnions,
|
||||
anonymousUnionsMap = anonymousUnionsMap,
|
||||
typedefsMarkersMap = typedefsMarkersMap
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,10 +29,12 @@ import java.util.ArrayList
|
||||
|
||||
data class ExtendedAttribute(val name: String?, val call: String, val arguments: List<Attribute>)
|
||||
data class Operation(val name: String, val returnType: String, val parameters: List<Attribute>, val attributes: List<ExtendedAttribute>)
|
||||
data class Attribute(val name: String, val type: String, val readOnly: Boolean, val defaultValue: String? = null, val vararg: Boolean)
|
||||
data class Attribute(val name: String, val type: String, val readOnly: Boolean = true, val defaultValue: String? = null, val vararg: Boolean)
|
||||
data class Constant(val name: String, val type: String, val value: String?)
|
||||
|
||||
enum class DefinitionType {
|
||||
fun Attribute.formatFunctionTypePart() = if (vararg) "vararg $type" else type
|
||||
|
||||
enum class DefinitionKind {
|
||||
INTERFACE
|
||||
TYPEDEF
|
||||
EXTENSION_INTERFACE
|
||||
@@ -75,6 +77,10 @@ class ExtendedAttributeArgumentsParser : WebIDLBaseVisitor<List<Attribute>>() {
|
||||
}
|
||||
}
|
||||
|
||||
// [Constructor]
|
||||
// [Constructor(any, Int)]
|
||||
// [Constructor(Int arg, String arg2 = "a")]
|
||||
// [name = Constructor]
|
||||
class ExtendedAttributeParser : WebIDLBaseVisitor<ExtendedAttribute>() {
|
||||
private var name: String? = null
|
||||
private var call: String = ""
|
||||
@@ -150,7 +156,7 @@ class TypeVisitor : WebIDLBaseVisitor<String>() {
|
||||
}
|
||||
}
|
||||
|
||||
class OperationVisitor(val attributes: List<ExtendedAttribute>) : WebIDLBaseVisitor<Operation>() {
|
||||
class OperationVisitor(private val attributes: List<ExtendedAttribute>) : WebIDLBaseVisitor<Operation>() {
|
||||
private var name: String = ""
|
||||
private var returnType: String = ""
|
||||
private val parameters = ArrayList<Attribute>()
|
||||
@@ -177,7 +183,7 @@ class OperationVisitor(val attributes: List<ExtendedAttribute>) : WebIDLBaseVisi
|
||||
}
|
||||
|
||||
override fun visitOptionalOrRequiredArgument(ctx: WebIDLParser.OptionalOrRequiredArgumentContext): Operation {
|
||||
val attributeVisitor = AttributeVisitor(false)
|
||||
val attributeVisitor = AttributeVisitor()
|
||||
attributeVisitor.visit(ctx)
|
||||
val parameter = attributeVisitor.visitChildren(ctx)
|
||||
|
||||
@@ -187,11 +193,11 @@ class OperationVisitor(val attributes: List<ExtendedAttribute>) : WebIDLBaseVisi
|
||||
}
|
||||
}
|
||||
|
||||
class AttributeVisitor(val readOnly: Boolean) : WebIDLBaseVisitor<Attribute>() {
|
||||
var type: String = ""
|
||||
var name: String = ""
|
||||
var defaultValue: String? = null
|
||||
var vararg: Boolean = false
|
||||
class AttributeVisitor(private val readOnly: Boolean = false) : WebIDLBaseVisitor<Attribute>() {
|
||||
private var type: String = ""
|
||||
private var name: String = ""
|
||||
private var defaultValue: String? = null
|
||||
private var vararg: Boolean = false
|
||||
|
||||
override fun defaultResult(): Attribute = Attribute(name, type, readOnly, defaultValue, vararg)
|
||||
|
||||
@@ -208,20 +214,12 @@ class AttributeVisitor(val readOnly: Boolean) : WebIDLBaseVisitor<Attribute>() {
|
||||
}
|
||||
|
||||
override fun visitAttributeRest(ctx: WebIDLParser.AttributeRestContext): Attribute {
|
||||
try {
|
||||
name = getName(ctx)
|
||||
} catch (ignore: Throwable) {
|
||||
name = ctx.children.filter { it is TerminalNode }.filter { it.getText() != ";" }.last().getText()
|
||||
}
|
||||
name = getNameOrNull(ctx) ?: ctx.children.filter { it is TerminalNode }.filter { it.getText() != ";" }.last().getText()
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
override fun visitArgumentName(ctx: WebIDLParser.ArgumentNameContext): Attribute {
|
||||
try {
|
||||
name = getName(ctx)
|
||||
} catch (ignore: Throwable) {
|
||||
name = ctx.getText()
|
||||
}
|
||||
name = getNameOrNull(ctx) ?: ctx.getText()
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
@@ -236,10 +234,10 @@ class AttributeVisitor(val readOnly: Boolean) : WebIDLBaseVisitor<Attribute>() {
|
||||
}
|
||||
}
|
||||
|
||||
class ConstantVisitor(val attributes: List<ExtendedAttribute>) : WebIDLBaseVisitor<Constant>() {
|
||||
var type: String = ""
|
||||
var name: String = ""
|
||||
var value: String? = null
|
||||
class ConstantVisitor : WebIDLBaseVisitor<Constant>() {
|
||||
private var type: String = ""
|
||||
private var name: String = ""
|
||||
private var value: String? = null
|
||||
|
||||
override fun defaultResult(): Constant = Constant(name, type, value)
|
||||
|
||||
@@ -260,8 +258,8 @@ class ConstantVisitor(val attributes: List<ExtendedAttribute>) : WebIDLBaseVisit
|
||||
}
|
||||
}
|
||||
|
||||
class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val namespace: String, val declarations : MutableList<Definition>) : WebIDLBaseVisitor<Definition>() {
|
||||
private var type: DefinitionType = DefinitionType.INTERFACE
|
||||
class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val namespace: String, val declarations: MutableList<Definition>) : WebIDLBaseVisitor<Definition>() {
|
||||
private var kind: DefinitionKind = DefinitionKind.INTERFACE
|
||||
private var name = ""
|
||||
private val memberAttributes = ArrayList<ExtendedAttribute>()
|
||||
private val operations = ArrayList<Operation>()
|
||||
@@ -274,12 +272,12 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
|
||||
private var partial = false
|
||||
private var callback = false
|
||||
|
||||
override fun defaultResult(): Definition = when (type) {
|
||||
DefinitionType.INTERFACE -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, false, partial, callback)
|
||||
DefinitionType.DICTIONARY -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, true, partial, callback)
|
||||
DefinitionType.EXTENSION_INTERFACE -> ExtensionInterfaceDefinition(namespace, name, implements ?: "")
|
||||
DefinitionType.TYPEDEF -> TypedefDefinition(typedefType ?: "", namespace, name)
|
||||
DefinitionType.ENUM -> EnumDefinition(namespace, name)
|
||||
override fun defaultResult(): Definition = when (kind) {
|
||||
DefinitionKind.INTERFACE -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, false, partial, callback)
|
||||
DefinitionKind.DICTIONARY -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, true, partial, callback)
|
||||
DefinitionKind.EXTENSION_INTERFACE -> ExtensionInterfaceDefinition(namespace, name, implements ?: "")
|
||||
DefinitionKind.TYPEDEF -> TypedefDefinition(typedefType ?: "", namespace, name)
|
||||
DefinitionKind.ENUM -> EnumDefinition(namespace, name)
|
||||
}
|
||||
|
||||
override fun visitCallbackRestOrInterface(ctx: WebIDLParser.CallbackRestOrInterfaceContext): Definition {
|
||||
@@ -288,10 +286,12 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
|
||||
}
|
||||
|
||||
override fun visitCallbackRest(ctx: WebIDLParser.CallbackRestContext): Definition {
|
||||
kind = DefinitionKind.TYPEDEF
|
||||
name = getName(ctx)
|
||||
with(OperationVisitor(memberAttributes.toList())) {
|
||||
operations.add(visit(ctx))
|
||||
}
|
||||
|
||||
val function = OperationVisitor(memberAttributes.toList()).visit(ctx)
|
||||
typedefType = "(${function.parameters.map { it.formatFunctionTypePart() }.join(",")}) -> ${function.returnType}"
|
||||
|
||||
memberAttributes.clear()
|
||||
return defaultResult()
|
||||
}
|
||||
@@ -324,7 +324,7 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
type = DefinitionType.TYPEDEF
|
||||
kind = DefinitionKind.TYPEDEF
|
||||
name = getName(ctx)
|
||||
|
||||
typedefType = ctx.accept(object : WebIDLBaseVisitor<String>() {
|
||||
@@ -342,14 +342,14 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
|
||||
}
|
||||
|
||||
override fun visitEnum_(ctx: Enum_Context): Definition {
|
||||
type = DefinitionType.ENUM
|
||||
kind = DefinitionKind.ENUM
|
||||
name = getName(ctx)
|
||||
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
override fun visitDictionary(ctx: DictionaryContext): Definition {
|
||||
type = DefinitionType.DICTIONARY
|
||||
kind = DefinitionKind.DICTIONARY
|
||||
name = getName(ctx)
|
||||
|
||||
return visitChildren(ctx)
|
||||
@@ -381,8 +381,8 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
|
||||
override fun visitImplementsStatement(ctx: ImplementsStatementContext): Definition {
|
||||
val identifiers = ctx.children.filterIdentifiers().map { it.getText() }
|
||||
|
||||
if (identifiers.size() >= 2) {
|
||||
type = DefinitionType.EXTENSION_INTERFACE
|
||||
if (identifiers.size() == 2) {
|
||||
kind = DefinitionKind.EXTENSION_INTERFACE
|
||||
name = identifiers[0]
|
||||
implements = identifiers[1]
|
||||
visitChildren(ctx)
|
||||
@@ -392,16 +392,14 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
|
||||
}
|
||||
|
||||
override fun visitOperation(ctx: OperationContext): Definition {
|
||||
with(OperationVisitor(memberAttributes.toList())) {
|
||||
operations.add(visit(ctx))
|
||||
}
|
||||
operations.add(OperationVisitor(memberAttributes.toList()).visit(ctx))
|
||||
memberAttributes.clear()
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
override fun visitInheritance(ctx: WebIDLParser.InheritanceContext): Definition {
|
||||
if (ctx.children != null) {
|
||||
inherited.addAll(ctx.children.filterIdentifiers().map {it.getText().trim()}.filter {it != ""})
|
||||
inherited.addAll(ctx.children.filterIdentifiers().map { it.getText().trim() }.filter { it != "" })
|
||||
}
|
||||
return defaultResult()
|
||||
}
|
||||
@@ -424,24 +422,20 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
|
||||
}
|
||||
|
||||
override fun visitConst_(ctx: WebIDLParser.Const_Context): Definition {
|
||||
constants.add(ConstantVisitor(memberAttributes.toList()).visit(ctx))
|
||||
constants.add(ConstantVisitor().visit(ctx))
|
||||
memberAttributes.clear()
|
||||
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
override fun visitExtendedAttribute(ctx: ExtendedAttributeContext): Definition {
|
||||
val att = with(ExtendedAttributeParser()) {
|
||||
visit(ctx)
|
||||
}
|
||||
|
||||
memberAttributes.add(att)
|
||||
memberAttributes.add(ExtendedAttributeParser().visit(ctx))
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ModuleVisitor(val declarations : MutableList<Definition>, var namespace : String = "") : WebIDLBaseVisitor<Unit>() {
|
||||
class ModuleVisitor(val declarations: MutableList<Definition>, var namespace: String = "") : WebIDLBaseVisitor<Unit>() {
|
||||
val extendedAttributes = ArrayList<ExtendedAttribute>()
|
||||
|
||||
override fun visitDefinition(ctx: WebIDLParser.DefinitionContext) {
|
||||
@@ -465,6 +459,7 @@ class ModuleVisitor(val declarations : MutableList<Definition>, var namespace :
|
||||
|
||||
private fun List<ParseTree>?.filterIdentifiers(): List<ParseTree> = this?.filter { it is TerminalNode && it.getSymbol().getType() == WebIDLLexer.IDENTIFIER_WEBIDL } ?: emptyList()
|
||||
private fun getName(ctx: ParserRuleContext) = ctx.children.filterIdentifiers().first().getText()
|
||||
private fun getNameOrNull(ctx: ParserRuleContext) = ctx.children.filterIdentifiers().firstOrNull()?.getText()
|
||||
|
||||
fun parseIDL(reader: CharStream): Repository {
|
||||
val ll = WebIDLLexer(reader)
|
||||
|
||||
@@ -16,7 +16,7 @@ fun main(args: Array<String>) {
|
||||
outDir.deleteRecursively()
|
||||
outDir.mkdirs()
|
||||
|
||||
val repository = srcDir.walkTopDown().filter { it.isDirectory() || it.extension == "idl" }.asSequence().filter {it.isFile()}.fold(Repository(emptyMap(), emptyMap(), emptyMap(), emptyMap())) { acc, e ->
|
||||
val repository = srcDir.walkTopDown().filter { it.isDirectory() || it.extension == "idl" }.asSequence().filter { it.isFile() }.fold(Repository(emptyMap(), emptyMap(), emptyMap(), emptyMap())) { acc, e ->
|
||||
val fileRepository = parseIDL(ANTLRFileStream(e.getAbsolutePath(), "UTF-8"))
|
||||
|
||||
Repository(
|
||||
@@ -28,6 +28,7 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
val definitions = mapDefinitions(repository, repository.interfaces.values())
|
||||
val unions = generateUnions(definitions, repository.typeDefs.values())
|
||||
val allPackages = definitions.map { it.namespace }.distinct().sort()
|
||||
|
||||
allPackages.forEach { pkg ->
|
||||
@@ -43,19 +44,19 @@ fun main(args: Array<String>) {
|
||||
w.appendln("package ${pkg}")
|
||||
w.appendln()
|
||||
|
||||
allPackages.filter {it != pkg}.forEach { import ->
|
||||
allPackages.filter { it != pkg }.forEach { import ->
|
||||
w.appendln("import ${import}.*")
|
||||
}
|
||||
w.appendln()
|
||||
|
||||
w.render(pkg, definitions, repository.typeDefs.values())
|
||||
w.render(pkg, definitions, unions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <K, V> Map<K, List<V>>.reduceValues(reduce : (V, V) -> V = {a, b -> b}) : Map<K, V> = mapValues { it.value.reduce(reduce) }
|
||||
private fun <K, V> Map<K, List<V>>.reduceValues(reduce: (V, V) -> V = { a, b -> b }): Map<K, V> = mapValues { it.value.reduce(reduce) }
|
||||
|
||||
private fun <K, V> Map<K, V>.mergeReduce(other : Map<K, V>, reduce : (V, V) -> V = {a, b -> b}) : Map<K, V> {
|
||||
private fun <K, V> Map<K, V>.mergeReduce(other: Map<K, V>, reduce: (V, V) -> V = { a, b -> b }): Map<K, V> {
|
||||
val result = LinkedHashMap<K, V>(this.size() + other.size())
|
||||
result.putAll(this)
|
||||
other.forEach { e ->
|
||||
@@ -63,7 +64,8 @@ private fun <K, V> Map<K, V>.mergeReduce(other : Map<K, V>, reduce : (V, V) -> V
|
||||
|
||||
if (existing == null) {
|
||||
result[e.key] = e.value
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
result[e.key] = reduce(e.value, existing)
|
||||
}
|
||||
}
|
||||
@@ -71,7 +73,7 @@ private fun <K, V> Map<K, V>.mergeReduce(other : Map<K, V>, reduce : (V, V) -> V
|
||||
return result
|
||||
}
|
||||
|
||||
private fun <K, V> Map<K, List<V>>.merge(other : Map<K, List<V>>) : Map<K, List<V>> {
|
||||
private fun <K, V> Map<K, List<V>>.merge(other: Map<K, List<V>>): Map<K, List<V>> {
|
||||
val result = LinkedHashMap<K, MutableList<V>>(size() + other.size())
|
||||
this.forEach {
|
||||
result[it.key] = ArrayList(it.value)
|
||||
@@ -80,7 +82,8 @@ private fun <K, V> Map<K, List<V>>.merge(other : Map<K, List<V>>) : Map<K, List<
|
||||
val list = result[it.key]
|
||||
if (list == null) {
|
||||
result[it.key] = ArrayList(it.value)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
list.addAll(it.value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,11 +35,12 @@ val GenerateAttribute.setterNoImpl: Boolean
|
||||
get() = getterSetterNoImpl && !readOnly
|
||||
|
||||
val String.typeSignature: String
|
||||
get() = if (contains("->")) "()" else this
|
||||
get() = if (contains("->")) "Function${FunctionType(this).arity}" else this
|
||||
|
||||
val GenerateAttribute.signature: String
|
||||
get() = "$name:${type.typeSignature}"
|
||||
fun GenerateAttribute.dynamicIfUnknownType(allTypes : Set<String>, standardTypes : Set<String> = standardTypes()) = this.copy(type = type.dynamicIfUnknownType(allTypes, standardTypes))
|
||||
|
||||
fun GenerateAttribute.dynamicIfUnknownType(allTypes : Set<String>, standardTypes : Set<String> = standardTypes()) = copy(type = type.dynamicIfUnknownType(allTypes, standardTypes))
|
||||
|
||||
enum class NativeGetterOrSetter {
|
||||
NONE
|
||||
@@ -52,7 +53,6 @@ enum class GenerateDefinitionKind {
|
||||
CLASS
|
||||
}
|
||||
|
||||
|
||||
class UnionType(val namespace: String, types: Collection<String>) {
|
||||
val memberTypes = HashSet(types)
|
||||
val name = "Union${this.memberTypes.sort().joinToString("Or")}"
|
||||
@@ -93,10 +93,15 @@ val GenerateFunction.signature: String
|
||||
get() = arguments.map { it.type.typeSignature }.joinToString(", ", "$name(", ")")
|
||||
|
||||
fun GenerateFunction.dynamicIfUnknownType(allTypes : Set<String>) = standardTypes().let { standardTypes ->
|
||||
this.copy(returnType = returnType.dynamicIfUnknownType(allTypes, standardTypes), arguments = arguments.map { it.dynamicIfUnknownType(allTypes, standardTypes) })
|
||||
copy(returnType = returnType.dynamicIfUnknownType(allTypes, standardTypes), arguments = arguments.map { it.dynamicIfUnknownType(allTypes, standardTypes) })
|
||||
}
|
||||
|
||||
fun InterfaceDefinition.findExtendedAttribute(name: String) = extendedAttributes.firstOrNull { it.call == name }
|
||||
fun InterfaceDefinition?.hasExtendedAttribute(name: String) = this?.findExtendedAttribute(name) ?: null != null
|
||||
fun InterfaceDefinition.findConstructor() = findExtendedAttribute("Constructor")
|
||||
|
||||
data class GenerateUnionTypes(
|
||||
val typeNamesToUnions : Map<String, List<String>>,
|
||||
val anonymousUnionsMap : Map<String, GenerateTraitOrClass>,
|
||||
val typedefsMarkersMap : Map<String, GenerateTraitOrClass>
|
||||
)
|
||||
|
||||
@@ -65,7 +65,7 @@ private fun Appendable.renderFunctionDeclaration(allTypes: Set<String>, f: Gener
|
||||
|
||||
when (f.nativeGetterOrSetter) {
|
||||
NativeGetterOrSetter.GETTER -> append("nativeGetter ")
|
||||
NativeGetterOrSetter.GETTER -> append("nativeSetter ")
|
||||
NativeGetterOrSetter.SETTER -> append("nativeSetter ")
|
||||
}
|
||||
|
||||
if (override) {
|
||||
@@ -150,33 +150,19 @@ private fun Pair<String, String>.betterName() = if (((0..9).map { it.toString()
|
||||
|
||||
fun <K, V> List<Pair<K, V>>.toMultiMap(): Map<K, List<V>> = groupBy { it.first }.mapValues { it.value.map { it.second } }
|
||||
|
||||
fun Appendable.render(namespace: String, ifaces: List<GenerateTraitOrClass>, typedefs: Iterable<TypedefDefinition>) {
|
||||
fun Appendable.render(namespace: String, ifaces: List<GenerateTraitOrClass>, unions : GenerateUnionTypes) {
|
||||
val declaredTypes = ifaces.toMap { it.name }
|
||||
|
||||
val anonymousUnionTypes = collectUnionTypes(declaredTypes)
|
||||
val anonymousUnionTypeTraits = generateUnionTypeTraits(anonymousUnionTypes)
|
||||
val anonymousUnionsMap = anonymousUnionTypeTraits.toMap { it.name }
|
||||
|
||||
val typedefsToBeGenerated = typedefs.filter { it.types.startsWith("Union<") }
|
||||
.filter { it.namespace == namespace }
|
||||
.map { NamedValue(it.name, UnionType(namespace, splitUnionType(it.types))) }
|
||||
.filter { it.value.memberTypes.all { type -> type in declaredTypes } }
|
||||
val typedefsMarkerTraits = typedefsToBeGenerated.groupBy { it.name }.mapValues { mapUnionType(it.value.first().value).copy(name = it.key) }
|
||||
|
||||
// TODO better name, extract duplication
|
||||
val typeNamesToUnions = anonymousUnionTypes.flatMap { unionType -> unionType.memberTypes.map { unionMember -> unionMember to unionType.name } }.toMultiMap()
|
||||
typedefsToBeGenerated.flatMap { typedef -> typedef.value.memberTypes.map { unionMember -> unionMember to typedef.name } }.toMultiMap()
|
||||
|
||||
val allTypes = declaredTypes + anonymousUnionsMap + typedefsMarkerTraits
|
||||
val allTypes = declaredTypes + unions.anonymousUnionsMap + unions.typedefsMarkersMap
|
||||
declaredTypes.values().filter { it.namespace == namespace }.forEach {
|
||||
render(allTypes, typeNamesToUnions, it)
|
||||
render(allTypes, unions.typeNamesToUnions, it)
|
||||
}
|
||||
|
||||
anonymousUnionTypeTraits.filter { it.namespace == "" || it.namespace == namespace }.forEach {
|
||||
unions.anonymousUnionsMap.values().filter { it.namespace == "" || it.namespace == namespace }.forEach {
|
||||
render(allTypes, emptyMap(), it, markerAnnotation = true)
|
||||
}
|
||||
|
||||
typedefsMarkerTraits.values().filter { it.namespace == "" || it.namespace == namespace }.forEach {
|
||||
unions.typedefsMarkersMap.values().filter { it.namespace == "" || it.namespace == namespace }.forEach {
|
||||
render(allTypes, emptyMap(), it, markerAnnotation = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,10 @@ private val typeMapper = mapOf(
|
||||
"long" to "Int",
|
||||
"float" to "Float",
|
||||
"double" to "Double",
|
||||
"any" to "Any?",
|
||||
"any" to "dynamic",
|
||||
"DOMTimeStamp" to "Number",
|
||||
"object" to "dynamic", // TODO map to Any?
|
||||
"EventHandler" to "(Event) -> Unit",
|
||||
"WindowProxy" to "Window",
|
||||
"Function" to "() -> dynamic",
|
||||
"USVString" to "String",
|
||||
"DOMString" to "String",
|
||||
"ByteString" to "String",
|
||||
@@ -57,31 +55,60 @@ fun allSuperTypesImpl(roots: List<GenerateTraitOrClass>, all: Map<String, Genera
|
||||
}
|
||||
}
|
||||
|
||||
data class FunctionType(val parameterTypes : List<Attribute>, val returnType : String)
|
||||
val FunctionType.arity : Int
|
||||
get() = parameterTypes.size()
|
||||
val FunctionType.text : String
|
||||
get() = "(${parameterTypes.map { it.formatFunctionTypePart() }.join(",")}) -> ${returnType}"
|
||||
|
||||
fun FunctionType(text : String) : FunctionType {
|
||||
val (parameters, returnType) = text.split("->".toRegex()).map {it.trim()}.filter { it != "" }
|
||||
|
||||
return FunctionType(
|
||||
parameterTypes = parameters.removeSurrounding("(", ")").split(',')
|
||||
.map { it.trim() }
|
||||
.filter { !it.isEmpty() }
|
||||
.map { Attribute(name = "", type = it.removePrefix("vararg "), vararg = it.startsWith("vararg ")) }
|
||||
.toList(),
|
||||
returnType = returnType
|
||||
)
|
||||
}
|
||||
|
||||
fun standardTypes() = typeMapper.values().map {it.dropNullable()}.toSet()
|
||||
fun String.dynamicIfUnknownType(allTypes: Set<String>, standardTypes: Set<String> = standardTypes()): String = when {
|
||||
startsWith("Union<") -> UnionType("", splitUnionType(this)).name.dynamicIfUnknownType(allTypes, standardTypes).copyNullabilityFrom(this)
|
||||
endsWith("?") -> this.dropNullable().dynamicIfUnknownType(allTypes, standardTypes).ensureNullable()
|
||||
contains("->") -> {
|
||||
val (parameters, returnType) = this.split("->".toRegex()).map {it.trim()}.filter { it != "" }
|
||||
|
||||
"(${parameters.removeSurrounding("(", ")").split(',').map {it.dynamicIfUnknownType(allTypes, standardTypes)}.join(",")}) -> ${returnType.dynamicIfUnknownType(allTypes, standardTypes)}"
|
||||
}
|
||||
this in allTypes -> this
|
||||
this in standardTypes -> this
|
||||
startsWith("Array<") -> "Array<" + removePrefix("Array<").removeSuffix(">").dynamicIfUnknownType(allTypes, standardTypes) + ">"
|
||||
startsWith("Union<") -> UnionType("", splitUnionType(this)).name.dynamicIfUnknownType(allTypes, standardTypes).copyNullabilityFrom(this)
|
||||
this != dropNullable() -> dropNullable().dynamicIfUnknownType(allTypes, standardTypes).ensureNullable()
|
||||
contains("->") -> {
|
||||
FunctionType(this).let { function ->
|
||||
function.copy(
|
||||
returnType = function.returnType.dynamicIfUnknownType(allTypes, standardTypes),
|
||||
parameterTypes = function.parameterTypes.map { it.copy(type = it.type.dynamicIfUnknownType(allTypes, standardTypes)) }
|
||||
).text
|
||||
}
|
||||
}
|
||||
else -> "dynamic"
|
||||
}
|
||||
|
||||
private fun mapType(repository: Repository, type: String): String =
|
||||
when {
|
||||
type in typeMapper -> typeMapper[type]!!
|
||||
type.endsWith("?") -> mapType(repository, type.dropNullable()).ensureNullable()
|
||||
type.isNullable() -> mapType(repository, type.dropNullable()).ensureNullable()
|
||||
type.endsWith("...") -> mapType(repository, type.substring(0, type.length() - 3))
|
||||
type.endsWith("[]") -> "Array<${mapType(repository, type.substring(0, type.length() - 2))}>"
|
||||
type.startsWith("unrestricted") -> mapType(repository, type.substring(12))
|
||||
type.startsWith("sequence") -> "Any" // TODO how do we handle sequences?
|
||||
type.startsWith("sequence<") -> "Array<${mapType(repository, type.removePrefix("sequence<").removeSuffix(">").trim())}>"
|
||||
type.startsWith("sequence") -> "Array<dynamic>"
|
||||
type in repository.typeDefs -> mapTypedef(repository, type)
|
||||
type in repository.enums -> "String"
|
||||
type.endsWith("Callback") -> "() -> Unit"
|
||||
type.contains("->") -> FunctionType(type).let { function ->
|
||||
function.copy(
|
||||
returnType = mapType(repository, function.returnType),
|
||||
parameterTypes = function.parameterTypes.takeWhile { !it.vararg }.map { it.copy(type = mapType(repository, it.type)) }
|
||||
).text
|
||||
}
|
||||
type.startsWith("Promise<") -> "dynamic"
|
||||
repository.interfaces[type].hasExtendedAttribute("NoInterfaceObject") -> "dynamic"
|
||||
else -> type
|
||||
@@ -99,7 +126,7 @@ private fun mapTypedef(repository: Repository, type: String): String {
|
||||
// Union<A, Union<B>, C> -> [A, B, C]
|
||||
// Union<Union<Union<A, B>>, C> -> [A, B, C]
|
||||
private fun splitUnionType(unionType: String) =
|
||||
unionType.replaceAll("Union<", "").replaceAll("[>]+", "").split("\\s*,\\s*".toRegex()).distinct().map {it.replaceAll("\\?$", "")}
|
||||
unionType.replace("Union<".toRegex(), "").replace("[>]+".toRegex(), "").split("\\s*,\\s*".toRegex()).distinct().map {it.replace("\\?$".toRegex(), "")}
|
||||
|
||||
private fun GenerateFunction?.allTypes() = if (this != null) sequenceOf(returnType) + arguments.asSequence().map { it.type } else emptySequence()
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.jetbrains.idl2k.util
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun List<List<*>>.mutationsCount() = if (isEmpty()) 0 else fold(1) { acc, e -> acc * e.size() }
|
||||
|
||||
fun <T> List<List<T>>.mutations() : List<List<T>> {
|
||||
val indices = IntArray(size())
|
||||
val sizes = map { it.size() }
|
||||
|
||||
fun next() : Boolean {
|
||||
var carry = 1
|
||||
|
||||
for (pos in size() - 1 downTo 0) {
|
||||
var index = indices[pos]
|
||||
val size = sizes[pos]
|
||||
|
||||
index += carry
|
||||
carry = (index - size + 1).coerceAtLeast(0)
|
||||
|
||||
if (index >= size) {
|
||||
indices[pos] = index - size
|
||||
} else {
|
||||
indices[pos] = index
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return carry == 0
|
||||
}
|
||||
|
||||
val count = mutationsCount()
|
||||
if (count == 0) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val result = ArrayList<List<T>>(count)
|
||||
do {
|
||||
result.add(indices.mapIndexed { pos, index -> this[pos][index] })
|
||||
} while (next())
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user