IDL2K rework types

Fixes #KT-8015
This commit is contained in:
Sergey Mashkov
2015-06-12 21:11:37 +03:00
parent 387291cbf7
commit 68183a74fa
7 changed files with 228 additions and 208 deletions
+12 -35
View File
@@ -10,32 +10,11 @@ private fun Operation.getterOrSetter() = this.attributes.map { it.call }.toSet()
} }
} }
fun String.isNullable() = endsWith(")?") || (endsWith("?") && !contains("->"))
fun String.ensureNullable() = when {
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.isNullable() -> ensureNullable()
else -> this
}
fun generateFunction(repository: Repository, function: Operation, functionName: String, nativeGetterOrSetter: NativeGetterOrSetter = function.getterOrSetter()): GenerateFunction = fun generateFunction(repository: Repository, function: Operation, functionName: String, nativeGetterOrSetter: NativeGetterOrSetter = function.getterOrSetter()): GenerateFunction =
function.attributes.map { it.call }.toSet().let { attributes -> function.attributes.map { it.call }.toSet().let { attributes ->
GenerateFunction( GenerateFunction(
name = functionName, name = functionName,
returnType = mapType(repository, function.returnType).let { mapped -> if (nativeGetterOrSetter == NativeGetterOrSetter.GETTER) mapped.ensureNullable() else mapped }, returnType = mapType(repository, function.returnType).let { mapped -> if (nativeGetterOrSetter == NativeGetterOrSetter.GETTER) mapped.toNullable() else mapped },
arguments = function.parameters.map { arguments = function.parameters.map {
GenerateAttribute( GenerateAttribute(
name = it.name, name = it.name,
@@ -61,16 +40,13 @@ fun generateFunctions(repository: Repository, function: Operation): List<Generat
NativeGetterOrSetter.SETTER -> generateFunction(repository, function, "set") NativeGetterOrSetter.SETTER -> generateFunction(repository, function, "set")
} }
val callbackArgumentsAsLambdas = function.parameters.map { val callbackArgumentsAsLambdas = function.parameters.map {
val interfaceType = repository.interfaces[it.type.dropNullable()] val parameterType = mapType(repository, it.type) as? SimpleType
val interfaceType = repository.interfaces[parameterType?.type]
when { when {
interfaceType == null -> it interfaceType == null -> it
interfaceType.operations.size() != 1 -> it interfaceType.operations.size() != 1 -> it
interfaceType.callback -> interfaceType.operations.single().let { callbackFunction -> interfaceType.callback -> interfaceType.operations.single().let { callbackFunction ->
it.copy(type = callbackFunction.parameters it.copy(type = FunctionType(callbackFunction.parameters.map { it.copy(type = mapType(repository, it.type)) }, mapType(repository, callbackFunction.returnType), parameterType?.nullable ?: false))
.map { it.copy(type = mapType(repository, it.type)) }
.map { it.formatFunctionTypePart() }
.join(", ", "(", ") -> ${mapType(repository, callbackFunction.returnType)}")
.copyNullabilityFrom(it.type))
} }
else -> it else -> it
} }
@@ -161,7 +137,7 @@ fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateT
fun generateConstructorAsFunction(repository: Repository, constructor: ExtendedAttribute) = generateFunction( fun generateConstructorAsFunction(repository: Repository, constructor: ExtendedAttribute) = generateFunction(
repository, repository,
Operation("", "Unit", constructor.arguments, emptyList(), false), Operation("", UnitType, constructor.arguments, emptyList(), false),
functionName = "", functionName = "",
nativeGetterOrSetter = NativeGetterOrSetter.NONE) nativeGetterOrSetter = NativeGetterOrSetter.NONE)
@@ -187,7 +163,7 @@ fun mapUnionType(it: UnionType) = GenerateTraitOrClass(
secondaryConstructors = emptyList() secondaryConstructors = emptyList()
) )
fun generateUnionTypeTraits(allUnionTypes: Iterable<UnionType>): List<GenerateTraitOrClass> = allUnionTypes.map(::mapUnionType) fun generateUnionTypeTraits(allUnionTypes: Sequence<UnionType>): Sequence<GenerateTraitOrClass> = allUnionTypes.map(::mapUnionType)
fun mapDefinitions(repository: Repository, definitions: Iterable<InterfaceDefinition>) = fun mapDefinitions(repository: Repository, definitions: Iterable<InterfaceDefinition>) =
definitions.filter { "NoInterfaceObject" !in it.extendedAttributes.map { it.call } }.map { generateTrait(repository, it) } definitions.filter { "NoInterfaceObject" !in it.extendedAttributes.map { it.call } }.map { generateTrait(repository, it) }
@@ -199,13 +175,14 @@ fun generateUnions(ifaces: List<GenerateTraitOrClass>, typedefs: Iterable<Typede
val anonymousUnionTypeTraits = generateUnionTypeTraits(anonymousUnionTypes) val anonymousUnionTypeTraits = generateUnionTypeTraits(anonymousUnionTypes)
val anonymousUnionsMap = anonymousUnionTypeTraits.toMap { it.name } val anonymousUnionsMap = anonymousUnionTypeTraits.toMap { it.name }
val typedefsToBeGenerated = typedefs.filter { it.types.startsWith("Union<") } val typedefsToBeGenerated = typedefs.filter { it.types is UnionType }
.map { NamedValue(it.name, UnionType(it.namespace, splitUnionType(it.types))) } .map { NamedValue(it.name, it.types as UnionType) }
.filter { it.value.memberTypes.all { type -> type in declaredTypes } } .filter { it.value.memberTypes.all { type -> type is SimpleType && type.type in declaredTypes } }
val typedefsMarkersMap = typedefsToBeGenerated.groupBy { it.name }.mapValues { mapUnionType(it.value.first().value).copy(name = it.key) } 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() merge val typeNamesToUnions = anonymousUnionTypes.toList().flatMap { unionType -> unionType.memberTypes.filterIsInstance<SimpleType>().map { unionMember -> unionMember.type to unionType.name } }.toMultiMap() merge
typedefsToBeGenerated.flatMap { typedef -> typedef.value.memberTypes.map { unionMember -> unionMember to typedef.name } }.toMultiMap() typedefsToBeGenerated.flatMap { typedef -> typedef.value.memberTypes.filterIsInstance<SimpleType>().map { unionMember -> unionMember.type to typedef.name } }.toMultiMap()
return GenerateUnionTypes( return GenerateUnionTypes(
typeNamesToUnionsMap = typeNamesToUnions, typeNamesToUnionsMap = typeNamesToUnions,
+52 -48
View File
@@ -28,11 +28,9 @@ import org.antlr.webidl.WebIDLParser.*
import java.util.ArrayList import java.util.ArrayList
data class ExtendedAttribute(val name: String?, val call: String, val arguments: List<Attribute>) 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>, val static: Boolean) data class Operation(val name: String, val returnType: Type, val parameters: List<Attribute>, val attributes: List<ExtendedAttribute>, val static: Boolean)
data class Attribute(val name: String, val type: String, val readOnly: Boolean = true, val defaultValue: String? = null, val vararg: Boolean, val static: Boolean) data class Attribute(val name: String, val type: Type, val readOnly: Boolean = true, val defaultValue: String? = null, val vararg: Boolean, val static: Boolean)
data class Constant(val name: String, val type: String, val value: String?) data class Constant(val name: String, val type: Type, val value: String?)
fun Attribute.formatFunctionTypePart() = if (vararg) "vararg $type" else type
enum class DefinitionKind { enum class DefinitionKind {
INTERFACE, INTERFACE,
@@ -43,7 +41,7 @@ enum class DefinitionKind {
} }
interface Definition interface Definition
data class TypedefDefinition(val types: String, val namespace: String, val name: String) : Definition data class TypedefDefinition(val types: Type, val namespace: String, val name: String) : Definition
data class InterfaceDefinition( data class InterfaceDefinition(
val name: String, val name: String,
val namespace: String, val namespace: String,
@@ -60,13 +58,13 @@ data class InterfaceDefinition(
data class ExtensionInterfaceDefinition(val namespace: String, val name: String, val implements: String) : Definition data class ExtensionInterfaceDefinition(val namespace: String, val name: String, val implements: String) : Definition
data class EnumDefinition(val namespace: String, val name: String) : Definition data class EnumDefinition(val namespace: String, val name: String) : Definition
class ExtendedAttributeArgumentsParser : WebIDLBaseVisitor<List<Attribute>>() { class ExtendedAttributeArgumentsParser(private val namespace: String) : WebIDLBaseVisitor<List<Attribute>>() {
private val arguments = ArrayList<Attribute>() private val arguments = ArrayList<Attribute>()
override fun defaultResult(): List<Attribute> = arguments override fun defaultResult(): List<Attribute> = arguments
override fun visitOptionalOrRequiredArgument(ctx: WebIDLParser.OptionalOrRequiredArgumentContext): List<Attribute> { override fun visitOptionalOrRequiredArgument(ctx: WebIDLParser.OptionalOrRequiredArgumentContext): List<Attribute> {
val attributeVisitor = AttributeVisitor() val attributeVisitor = AttributeVisitor(namespace = namespace)
attributeVisitor.visit(ctx) attributeVisitor.visit(ctx)
val parameter = attributeVisitor.visitChildren(ctx) val parameter = attributeVisitor.visitChildren(ctx)
@@ -81,7 +79,7 @@ class ExtendedAttributeArgumentsParser : WebIDLBaseVisitor<List<Attribute>>() {
// [Constructor(any, Int)] // [Constructor(any, Int)]
// [Constructor(Int arg, String arg2 = "a")] // [Constructor(Int arg, String arg2 = "a")]
// [name = Constructor] // [name = Constructor]
class ExtendedAttributeParser : WebIDLBaseVisitor<ExtendedAttribute>() { class ExtendedAttributeParser(private val namespace: String) : WebIDLBaseVisitor<ExtendedAttribute>() {
private var name: String? = null private var name: String? = null
private var call: String = "" private var call: String = ""
private val arguments = ArrayList<Attribute>() private val arguments = ArrayList<Attribute>()
@@ -96,7 +94,7 @@ class ExtendedAttributeParser : WebIDLBaseVisitor<ExtendedAttribute>() {
} }
override fun visitArgumentList(ctx: WebIDLParser.ArgumentListContext): ExtendedAttribute { override fun visitArgumentList(ctx: WebIDLParser.ArgumentListContext): ExtendedAttribute {
arguments.addAll(ExtendedAttributeArgumentsParser().visitChildren(ctx)) arguments.addAll(ExtendedAttributeArgumentsParser(namespace).visitChildren(ctx))
return defaultResult() return defaultResult()
} }
@@ -104,7 +102,7 @@ class ExtendedAttributeParser : WebIDLBaseVisitor<ExtendedAttribute>() {
object : WebIDLBaseVisitor<Unit>() { object : WebIDLBaseVisitor<Unit>() {
override fun visitTerminal(node: TerminalNode) { override fun visitTerminal(node: TerminalNode) {
if (node.getSymbol().getType() == WebIDLLexer.IDENTIFIER_WEBIDL) { if (node.getSymbol().getType() == WebIDLLexer.IDENTIFIER_WEBIDL) {
arguments.add(Attribute(node.getText(), "any", true, vararg = false, static = false)) arguments.add(Attribute(node.getText(), AnyType(), true, vararg = false, static = false))
} }
} }
}.visitChildren(ctx) }.visitChildren(ctx)
@@ -118,47 +116,53 @@ class ExtendedAttributeParser : WebIDLBaseVisitor<ExtendedAttribute>() {
} }
} }
class UnionTypeVisitor : WebIDLBaseVisitor<List<String>>() { class UnionTypeVisitor(val namespace: String) : WebIDLBaseVisitor<List<Type>>() {
val list = ArrayList<String>() val list = ArrayList<Type>()
override fun defaultResult() = list override fun defaultResult() = list
override fun visitUnionMemberType(ctx: WebIDLParser.UnionMemberTypeContext): List<String> { override fun visitUnionMemberType(ctx: WebIDLParser.UnionMemberTypeContext): List<Type> {
list.add(TypeVisitor().visitChildren(ctx)) list.add(TypeVisitor(namespace).visitChildren(ctx))
return list return list
} }
} }
class TypeVisitor : WebIDLBaseVisitor<String>() { class TypeVisitor(val namespace: String) : WebIDLBaseVisitor<Type>() {
private var type = "" private var type: Type = AnyType()
override fun defaultResult() = type override fun defaultResult() = type
override fun visitNonAnyType(ctx: WebIDLParser.NonAnyTypeContext): String { override fun visitNonAnyType(ctx: WebIDLParser.NonAnyTypeContext): Type {
type = ctx.getText() type = SimpleType(ctx.getText(), false)
return type return type
} }
override fun visitUnionType(ctx: WebIDLParser.UnionTypeContext): String { override fun visitUnionType(ctx: WebIDLParser.UnionTypeContext): Type {
type = "Union<" + UnionTypeVisitor().visitChildren(ctx).joinToString(",") + ">" type = UnionType(namespace, UnionTypeVisitor(namespace).visitChildren(ctx), false)
return type return type
} }
override fun visitTypeSuffix(ctx: TypeSuffixContext): String { override fun visitTypeSuffix(ctx: TypeSuffixContext): Type {
type += ctx.getText() when (ctx.getText()?.trim()) {
"?" -> type = type.toNullable()
"[]" -> type = ArrayType(type, false)
"[]?" -> type = ArrayType(type, true)
"?[]" -> type = ArrayType(type.toNullable(), false)
}
return type return type
} }
override fun visitTerminal(node: TerminalNode): String { override fun visitTerminal(node: TerminalNode): Type {
type = node.getText() type = SimpleType(node.getText(), false)
return type return type
} }
} }
class OperationVisitor(private val attributes: List<ExtendedAttribute>, private val static: Boolean) : WebIDLBaseVisitor<Operation>() { class OperationVisitor(private val attributes: List<ExtendedAttribute>, private val static: Boolean, private val namespace: String) : WebIDLBaseVisitor<Operation>() {
private var name: String = "" private var name: String = ""
private var returnType: String = "" private var returnType: Type = UnitType
private val parameters = ArrayList<Attribute>() private val parameters = ArrayList<Attribute>()
private val exts = ArrayList<ExtendedAttribute>() private val exts = ArrayList<ExtendedAttribute>()
@@ -178,12 +182,12 @@ class OperationVisitor(private val attributes: List<ExtendedAttribute>, private
} }
override fun visitReturnType(ctx: ReturnTypeContext): Operation { override fun visitReturnType(ctx: ReturnTypeContext): Operation {
returnType = TypeVisitor().visit(ctx) returnType = TypeVisitor(namespace).visit(ctx)
return defaultResult() return defaultResult()
} }
override fun visitOptionalOrRequiredArgument(ctx: WebIDLParser.OptionalOrRequiredArgumentContext): Operation { override fun visitOptionalOrRequiredArgument(ctx: WebIDLParser.OptionalOrRequiredArgumentContext): Operation {
val attributeVisitor = AttributeVisitor(static = false) val attributeVisitor = AttributeVisitor(static = false, namespace = namespace)
attributeVisitor.visit(ctx) attributeVisitor.visit(ctx)
val parameter = attributeVisitor.visitChildren(ctx) val parameter = attributeVisitor.visitChildren(ctx)
@@ -193,8 +197,8 @@ class OperationVisitor(private val attributes: List<ExtendedAttribute>, private
} }
} }
class AttributeVisitor(private val readOnly: Boolean = false, private val static: Boolean = false) : WebIDLBaseVisitor<Attribute>() { class AttributeVisitor(private val readOnly: Boolean = false, private val static: Boolean = false, private val namespace: String) : WebIDLBaseVisitor<Attribute>() {
private var type: String = "" private var type: Type = AnyType(true)
private var name: String = "" private var name: String = ""
private var defaultValue: String? = null private var defaultValue: String? = null
private var vararg: Boolean = false private var vararg: Boolean = false
@@ -202,7 +206,7 @@ class AttributeVisitor(private val readOnly: Boolean = false, private val static
override fun defaultResult(): Attribute = Attribute(name, type, readOnly, defaultValue, vararg, static) override fun defaultResult(): Attribute = Attribute(name, type, readOnly, defaultValue, vararg, static)
override fun visitType(ctx: WebIDLParser.TypeContext): Attribute { override fun visitType(ctx: WebIDLParser.TypeContext): Attribute {
type = TypeVisitor().visit(ctx) type = TypeVisitor(namespace).visit(ctx)
return defaultResult() return defaultResult()
} }
@@ -235,7 +239,7 @@ class AttributeVisitor(private val readOnly: Boolean = false, private val static
} }
class ConstantVisitor : WebIDLBaseVisitor<Constant>() { class ConstantVisitor : WebIDLBaseVisitor<Constant>() {
private var type: String = "" private var type: Type = AnyType(false)
private var name: String = "" private var name: String = ""
private var value: String? = null private var value: String? = null
@@ -248,7 +252,7 @@ class ConstantVisitor : WebIDLBaseVisitor<Constant>() {
} }
override fun visitConstType(ctx: WebIDLParser.ConstTypeContext): Constant { override fun visitConstType(ctx: WebIDLParser.ConstTypeContext): Constant {
type = ctx.getText() type = SimpleType(ctx.getText(), false)
return defaultResult() return defaultResult()
} }
@@ -267,7 +271,7 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
private var readOnly: Boolean = false private var readOnly: Boolean = false
private var static: Boolean = false private var static: Boolean = false
private val inherited = ArrayList<String>() private val inherited = ArrayList<String>()
private var typedefType: String? = null private var typedefType: Type? = null
private var implements: String? = null private var implements: String? = null
private val constants = ArrayList<Constant>() private val constants = ArrayList<Constant>()
private var partial = false private var partial = false
@@ -277,7 +281,7 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
DefinitionKind.INTERFACE -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, false, partial, callback) 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.DICTIONARY -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, true, partial, callback)
DefinitionKind.EXTENSION_INTERFACE -> ExtensionInterfaceDefinition(namespace, name, implements ?: "") DefinitionKind.EXTENSION_INTERFACE -> ExtensionInterfaceDefinition(namespace, name, implements ?: "")
DefinitionKind.TYPEDEF -> TypedefDefinition(typedefType ?: "", namespace, name) DefinitionKind.TYPEDEF -> TypedefDefinition(typedefType ?: AnyType(true), namespace, name)
DefinitionKind.ENUM -> EnumDefinition(namespace, name) DefinitionKind.ENUM -> EnumDefinition(namespace, name)
} }
@@ -290,8 +294,8 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
kind = DefinitionKind.TYPEDEF kind = DefinitionKind.TYPEDEF
name = getName(ctx) name = getName(ctx)
val function = OperationVisitor(memberAttributes.toList(), static).visit(ctx) val function = OperationVisitor(memberAttributes.toList(), static, namespace).visit(ctx)
typedefType = "(${function.parameters.map { it.formatFunctionTypePart() }.join(", ")}) -> ${function.returnType}" typedefType = FunctionType(function.parameters, function.returnType, false)
memberAttributes.clear() memberAttributes.clear()
return defaultResult() return defaultResult()
@@ -328,13 +332,13 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
kind = DefinitionKind.TYPEDEF kind = DefinitionKind.TYPEDEF
name = getName(ctx) name = getName(ctx)
typedefType = ctx.accept(object : WebIDLBaseVisitor<String>() { typedefType = ctx.accept(object : WebIDLBaseVisitor<Type>() {
private var foundType = "" private var foundType: Type = AnyType(false)
override fun defaultResult(): String = foundType override fun defaultResult(): Type = foundType
override fun visitType(ctx: WebIDLParser.TypeContext): String { override fun visitType(ctx: WebIDLParser.TypeContext): Type {
foundType = TypeVisitor().visit(ctx) foundType = TypeVisitor(namespace).visit(ctx)
return defaultResult() return defaultResult()
} }
}) })
@@ -362,7 +366,7 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
.firstOrNull { it.getText() != "" } .firstOrNull { it.getText() != "" }
?.getText() ?.getText()
val type = TypeVisitor().visit(ctx.children.first { it is TypeContext }) val type = TypeVisitor(namespace).visit(ctx.children.first { it is TypeContext })
val defaultValue = object : WebIDLBaseVisitor<String?>() { val defaultValue = object : WebIDLBaseVisitor<String?>() {
private var value: String? = null private var value: String? = null
@@ -398,7 +402,7 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
} }
private fun visitOperationImpl(ctx: ParserRuleContext) { private fun visitOperationImpl(ctx: ParserRuleContext) {
operations.add(OperationVisitor(memberAttributes.toList(), static).visit(ctx)) operations.add(OperationVisitor(memberAttributes.toList(), static, namespace).visit(ctx))
memberAttributes.clear() memberAttributes.clear()
} }
@@ -436,7 +440,7 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
} }
override fun visitAttributeRest(ctx: WebIDLParser.AttributeRestContext): Definition { override fun visitAttributeRest(ctx: WebIDLParser.AttributeRestContext): Definition {
with(AttributeVisitor(readOnly, static)) { with(AttributeVisitor(readOnly, static, namespace)) {
visit(ctx) visit(ctx)
this@DefinitionVisitor.attributes.add(visitChildren(ctx)) this@DefinitionVisitor.attributes.add(visitChildren(ctx))
} }
@@ -452,7 +456,7 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
} }
override fun visitExtendedAttribute(ctx: ExtendedAttributeContext): Definition { override fun visitExtendedAttribute(ctx: ExtendedAttributeContext): Definition {
memberAttributes.add(ExtendedAttributeParser().visit(ctx)) memberAttributes.add(ExtendedAttributeParser(namespace).visit(ctx))
return defaultResult() return defaultResult()
} }
@@ -468,7 +472,7 @@ class ModuleVisitor(val declarations: MutableList<Definition>, var namespace: St
} }
override fun visitExtendedAttribute(ctx: ExtendedAttributeContext?) { override fun visitExtendedAttribute(ctx: ExtendedAttributeContext?) {
val att = with(ExtendedAttributeParser()) { val att = with(ExtendedAttributeParser(namespace)) {
visit(ctx) visit(ctx)
} }
@@ -14,7 +14,7 @@ fun main(args: Array<String>) {
return return
} }
val repository = srcDir.walkTopDown().filter { it.isDirectory() || it.extension == "idl" }.asSequence().filter { it.isFile() }.fold(Repository(emptyMap(), emptyMap(), emptyMap(), emptyMap())) { acc, e -> val repositoryPre = 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")) val fileRepository = parseIDL(ANTLRFileStream(e.getAbsolutePath(), "UTF-8"))
Repository( Repository(
@@ -25,6 +25,8 @@ fun main(args: Array<String>) {
) )
} }
val repository = repositoryPre.copy(typeDefs = repositoryPre.typeDefs.mapValues { it.value.copy(mapType(repositoryPre, it.value.types)) })
val definitions = mapDefinitions(repository, repository.interfaces.values()).map { val definitions = mapDefinitions(repository, repository.interfaces.values()).map {
if (it.name in relocations) { if (it.name in relocations) {
// we need this to get interfaces listed in the relocations in valid package // we need this to get interfaces listed in the relocations in valid package
+9 -17
View File
@@ -27,21 +27,24 @@ data class Repository(
val enums: Map<String, EnumDefinition> val enums: Map<String, EnumDefinition>
) )
data class GenerateAttribute(val name: String, val type: String, val initializer: String?, val getterSetterNoImpl: Boolean, val readOnly: Boolean, val override: Boolean, var vararg: Boolean, val static: Boolean) data class GenerateAttribute(val name: String, val type: Type, val initializer: String?, val getterSetterNoImpl: Boolean, val readOnly: Boolean, val override: Boolean, var vararg: Boolean, val static: Boolean)
val GenerateAttribute.getterNoImpl: Boolean val GenerateAttribute.getterNoImpl: Boolean
get() = getterSetterNoImpl get() = getterSetterNoImpl
val GenerateAttribute.setterNoImpl: Boolean val GenerateAttribute.setterNoImpl: Boolean
get() = getterSetterNoImpl && !readOnly get() = getterSetterNoImpl && !readOnly
val String.typeSignature: String val Type.typeSignature: String
get() = if (contains("->")) "Function${FunctionType(this).arity}" else this get() = when {
this is FunctionType -> "Function$arity"
else -> this.toString()
}
val GenerateAttribute.signature: String val GenerateAttribute.signature: String
get() = "$name:${type.typeSignature}" get() = "$name:${type.typeSignature}"
fun GenerateAttribute.dynamicIfUnknownType(allTypes : Set<String>, standardTypes : Set<String> = standardTypes()) = copy(type = type.dynamicIfUnknownType(allTypes, standardTypes)) fun GenerateAttribute.dynamicIfUnknownType(allTypes : Set<String>, standardTypes : Set<Type> = standardTypes()) = copy(type = type.dynamicIfUnknownType(allTypes, standardTypes))
fun List<GenerateAttribute>.dynamicIfUnknownType(allTypes : Set<String>, standardTypes : Set<String> = standardTypes()) = map { it.dynamicIfUnknownType(allTypes, standardTypes) } fun List<GenerateAttribute>.dynamicIfUnknownType(allTypes : Set<String>, standardTypes : Set<Type> = standardTypes()) = map { it.dynamicIfUnknownType(allTypes, standardTypes) }
enum class NativeGetterOrSetter { enum class NativeGetterOrSetter {
NONE, NONE,
@@ -54,21 +57,10 @@ enum class GenerateDefinitionKind {
CLASS CLASS
} }
class UnionType(val namespace: String, types: Collection<String>) {
val memberTypes = HashSet(types)
val name = "Union${this.memberTypes.sort().joinToString("Or")}"
fun contains(type: String) = type in memberTypes
override fun equals(other: Any?): Boolean = other is UnionType && name == other.name
override fun hashCode(): Int = name.hashCode()
override fun toString(): String = name
}
data class GenerateFunctionCall(val name: String, val arguments: List<String>) data class GenerateFunctionCall(val name: String, val arguments: List<String>)
data class GenerateFunction( data class GenerateFunction(
val name: String, val name: String,
val returnType: String, val returnType: Type,
val arguments: List<GenerateAttribute>, val arguments: List<GenerateAttribute>,
val nativeGetterOrSetter: NativeGetterOrSetter, val nativeGetterOrSetter: NativeGetterOrSetter,
val static: Boolean val static: Boolean
@@ -19,7 +19,7 @@ private fun Appendable.renderAttributeDeclaration(arg: GenerateAttribute, overri
append(" ") append(" ")
append(arg.name) append(arg.name)
append(": ") append(": ")
append(arg.type) append(arg.type.render())
if (arg.initializer != null) { if (arg.initializer != null) {
append(" = ") append(" = ")
append(arg.initializer.replaceWrongConstants(arg.type)) append(arg.initializer.replaceWrongConstants(arg.type))
@@ -39,9 +39,9 @@ private fun Appendable.renderAttributeDeclaration(arg: GenerateAttribute, overri
private val keywords = setOf("interface") private val keywords = setOf("interface")
private fun String.parse() = if (this.startsWith("0x")) BigInteger(this.substring(2), 16) else BigInteger(this) private fun String.parse() = if (this.startsWith("0x")) BigInteger(this.substring(2), 16) else BigInteger(this)
private fun String.replaceWrongConstants(type: String) = when { private fun String.replaceWrongConstants(type: Type) = when {
this == "noImpl" || type == "Int" && parse() > BigInteger.valueOf(Int.MAX_VALUE.toLong()) -> "noImpl" this == "noImpl" || type is SimpleType && type.type == "Int" && parse() > BigInteger.valueOf(Int.MAX_VALUE.toLong()) -> "noImpl"
type == "Double" && this.matches("[0-9]+".toRegex()) -> "${this}.0" type is SimpleType && type.type == "Double" && this.matches("[0-9]+".toRegex()) -> "${this}.0"
else -> this else -> this
} }
private fun String.replaceKeywords() = if (this in keywords) this + "_" else this private fun String.replaceKeywords() = if (this in keywords) this + "_" else this
@@ -54,7 +54,7 @@ private fun Appendable.renderArgumentsDeclaration(args: List<GenerateAttribute>,
} }
append(it.name.replaceKeywords()) append(it.name.replaceKeywords())
append(": ") append(": ")
append(it.type) append(it.type.render())
if (!omitDefaults && it.initializer != null && it.initializer != "") { if (!omitDefaults && it.initializer != null && it.initializer != "") {
append(" = ") append(" = ")
append(it.initializer.replaceWrongConstants(it.type)) append(it.initializer.replaceWrongConstants(it.type))
@@ -82,7 +82,7 @@ private fun Appendable.renderFunctionDeclaration(f: GenerateFunction, override:
} }
append("fun ${f.name.replaceKeywords()}(") append("fun ${f.name.replaceKeywords()}(")
renderArgumentsDeclaration(f.arguments, override) renderArgumentsDeclaration(f.arguments, override)
appendln("): ${f.returnType} = noImpl") appendln("): ${f.returnType.render()} = noImpl")
} }
fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUnions: Map<String, List<String>>, iface: GenerateTraitOrClass, markerAnnotation: Boolean = false) { fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUnions: Map<String, List<String>>, iface: GenerateTraitOrClass, markerAnnotation: Boolean = false) {
@@ -177,7 +177,7 @@ fun betterFunction(f1: GenerateFunction, f2: GenerateFunction): GenerateFunction
) )
private fun <F, T> Pair<F, F>.map(block: (F) -> T) = block(first) to block(second) private fun <F, T> Pair<F, F>.map(block: (F) -> T) = block(first) to block(second)
private fun Pair<String, String>.betterType() = if (listOf("dynamic", "Any").any { first.contains(it) }) first else second private fun Pair<Type, Type>.betterType() = if (first is DynamicType || first is AnyType) first else second
private fun Pair<String, String>.betterName() = if (((0..9).map { it.toString() } + listOf("arg")).none { first.toLowerCase().contains(it) }) first else second private fun Pair<String, String>.betterName() = if (((0..9).map { it.toString() } + listOf("arg")).none { first.toLowerCase().contains(it) }) first else second
fun <K, V> List<Pair<K, V>>.toMultiMap(): Map<K, List<V>> = groupBy { it.first }.mapValues { it.value.map { it.second } } fun <K, V> List<Pair<K, V>>.toMultiMap(): Map<K, List<V>> = groupBy { it.first }.mapValues { it.value.map { it.second } }
@@ -19,30 +19,30 @@ package org.jetbrains.idl2k
import java.util.* import java.util.*
private val typeMapper = mapOf( private val typeMapper = mapOf(
"unsignedlong" to "Int", "unsignedlong" to SimpleType("Int", false),
"unsignedlonglong" to "Long", "unsignedlonglong" to SimpleType("Long", false),
"longlong" to "Long", "longlong" to SimpleType("Long", false),
"unsignedshort" to "Short", "unsignedshort" to SimpleType("Short", false),
"unsignedbyte" to "Byte", "unsignedbyte" to SimpleType("Byte", false),
"octet" to "Byte", "octet" to SimpleType("Byte", false),
"void" to "Unit", "void" to UnitType,
"boolean" to "Boolean", "boolean" to SimpleType("Boolean", false),
"byte" to "Byte", "byte" to SimpleType("Byte", false),
"short" to "Short", "short" to SimpleType("Short", false),
"long" to "Int", "long" to SimpleType("Int", false),
"float" to "Float", "float" to SimpleType("Float", false),
"double" to "Double", "double" to SimpleType("Double", false),
"any" to "Any?", "any" to AnyType(true),
"DOMTimeStamp" to "Number", "DOMTimeStamp" to SimpleType("Number", false),
"object" to "dynamic", // TODO map to Any? "object" to DynamicType, // TODO map to Any?
"WindowProxy" to "Window", "WindowProxy" to SimpleType("Window", false),
"USVString" to "String", "USVString" to SimpleType("String", false),
"DOMString" to "String", "DOMString" to SimpleType("String", false),
"ByteString" to "String", "ByteString" to SimpleType("String", false),
"DOMError" to "dynamic", "DOMError" to DynamicType,
"Elements" to "dynamic", "Elements" to DynamicType,
"Date" to "Date", "Date" to SimpleType("Date", false),
"" to "dynamic" "" to DynamicType
) )
@@ -55,87 +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 "), static = false) }
.toList(),
returnType = returnType
)
}
fun standardTypes() = typeMapper.values().map {it.dropNullable()}.toSet() fun standardTypes() = typeMapper.values().map {it.dropNullable()}.toSet()
fun String.dynamicIfUnknownType(allTypes: Set<String>, standardTypes: Set<String> = standardTypes()): String = when { fun Type.dynamicIfUnknownType(allTypes: Set<String>, standardTypes: Set<Type> = standardTypes()): Type = when {
this in allTypes -> this this is DynamicType, this is UnitType -> 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)
isNullable() -> dropNullable().dynamicIfUnknownType(allTypes, standardTypes).ensureNullable()
contains("->") -> {
val function = FunctionType(this)
function.copy( this is SimpleType && this.type in allTypes -> this
returnType = function.returnType.dynamicIfUnknownType(allTypes, standardTypes), this.dropNullable() in standardTypes -> this
parameterTypes = function.parameterTypes.map { it.copy(type = it.type.dynamicIfUnknownType(allTypes, standardTypes)) } this is ArrayType -> copy(memberType = this.memberType.dynamicIfUnknownType(allTypes, standardTypes))
).text this is UnionType -> if (this.name !in allTypes) DynamicType else this
} this is FunctionType -> copy(returnType = returnType.dynamicIfUnknownType(allTypes, standardTypes), parameterTypes = parameterTypes.map { it.copy(type = it.type.dynamicIfUnknownType(allTypes, standardTypes)) })
else -> "dynamic"
else -> DynamicType
} }
private fun String.dynamicIfAnyType() = if (this == "Any?") "dynamic" else this private fun Type.dynamicIfAnyType(): Type = if (this is AnyType && this.nullable) DynamicType else this
private fun mapType(repository: Repository, type: String): String = private fun mapType(repository: Repository, type: Type): Type = when (type) {
when { is SimpleType -> {
type in typeMapper -> typeMapper[type]!! val typeName = type.type
type.isNullable() -> mapType(repository, type.dropNullable()).ensureNullable() when {
type.endsWith("...") -> mapType(repository, type.substring(0, type.length() - 3)) typeName in typeMapper -> typeMapper[typeName]!!.withNullability(type.nullable)
type.endsWith("[]") -> "Array<${mapType(repository, type.substring(0, type.length() - 2))}>" typeName.endsWith("?") -> mapType(repository, SimpleType(typeName.removeSuffix("?"), false)).toNullable()
type.startsWith("unrestricted") -> mapType(repository, type.substring(12)) typeName.endsWith("[]") -> ArrayType(memberType = mapType(repository, SimpleType(typeName.removeSuffix("[]"), false)), nullable = type.nullable)
type.startsWith("sequence<") -> "Array<${mapType(repository, type.removePrefix("sequence<").removeSuffix(">").trim())}>" typeName.startsWith("unrestricted") -> mapType(repository, SimpleType(typeName.removePrefix("unrestricted"), false))
type.startsWith("sequence") -> "Array<dynamic>" typeName.startsWith("sequence<") -> ArrayType(mapType(repository, SimpleType(typeName.removePrefix("sequence<").removeSuffix(">").trim(), false)), type.nullable)
type.startsWith("Union<") -> "Union<" + splitUnionType(type).map { mapType(repository, it) }.join(",") + ">" typeName == "sequence" -> ArrayType(DynamicType, type.nullable)
type in repository.typeDefs -> mapTypedef(repository, type) typeName in repository.interfaces -> type
type in repository.enums -> "String" typeName in repository.typeDefs -> mapTypedef(repository, type)
type.contains("->") -> { typeName in repository.enums -> SimpleType("String", type.nullable)
val function = FunctionType(type) typeName.startsWith("Promise<") -> DynamicType
// TODO: Remove takeWhile { !vararg } when we have varargs supported. See KT-3115 else -> type
function.copy(
returnType = mapType(repository, function.returnType).dynamicIfAnyType(),
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
} }
is ArrayType -> type.copy(memberType = mapType(repository, type.memberType))
private fun mapTypedef(repository: Repository, type: String): String { is UnionType -> UnionType(type.namespace, type.memberTypes.map { mt -> mapType(repository, mt) }, type.nullable).toSingleTypeIfPossible()
val typedef = repository.typeDefs[type]!! is FunctionType -> type.copy(
// TODO: Remove takeWhile { !vararg } when we have varargs supported. See KT-3115
return if (!typedef.types.startsWith("Union<")) mapType(repository, typedef.types) returnType = mapType(repository, type.returnType).dynamicIfAnyType(),
else if (splitUnionType(typedef.types).size() == 1) mapType(repository, splitUnionType(typedef.types).first()) parameterTypes = type.parameterTypes.takeWhile { !it.vararg }.map { it.copy(type = mapType(repository, it.type)) }
else typedef.name )
else -> type
} }
// Union<A, B, C> -> [A, B, C] private fun mapTypedef(repository: Repository, type: SimpleType): Type {
// Union<A, Union<B>, C> -> [A, B, C] val typedef = repository.typeDefs[type.type]!!
// Union<Union<Union<A, B>>, C> -> [A, B, C]
private fun splitUnionType(unionType: String) =
unionType.replace("Union<".toRegex(), "").replace("[>]+".toRegex(), "").split("\\s*,\\s*".toRegex()).distinct().map {it.replace("\\?$".toRegex(), "")}
private fun GenerateFunction.allTypes() = sequenceOf(returnType) + arguments.asSequence().map { it.type } return when {
typedef.types is UnionType && typedef.types.memberTypes.size() == 1 -> mapType(repository, typedef.types.memberTypes.single().withNullability(type.nullable))
typedef.types is UnionType -> SimpleType(typedef.name, type.nullable)
else -> mapType(repository, typedef.types.withNullability(type.nullable))
}
}
private fun GenerateFunction?.allTypes() = if (this != null) sequenceOf(returnType) + arguments.asSequence().map { it.type } else emptySequence()
private fun collectUnionTypes(allTypes: Map<String, GenerateTraitOrClass>) = private fun collectUnionTypes(allTypes: Map<String, GenerateTraitOrClass>) =
allTypes.values().asSequence() allTypes.values().asSequence()
@@ -145,16 +118,16 @@ private fun collectUnionTypes(allTypes: Map<String, GenerateTraitOrClass>) =
it.memberAttributes.asSequence().map { it.type } + it.memberAttributes.asSequence().map { it.type } +
it.memberFunctions.asSequence().flatMap { it.allTypes() } it.memberFunctions.asSequence().flatMap { it.allTypes() }
} }
.filter { it.startsWith("Union<") } .filterIsInstance<UnionType>()
.map { splitUnionType(it) } .map { it.dropNullable() }
.filter { it.all { unionMember -> unionMember in allTypes } } .filter { it.memberTypes.all { unionMember -> unionMember is SimpleType && unionMember.type in allTypes } }
.toSet() .distinct()
.map { UnionType(guessPackage(it, allTypes), it) } .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>) = private fun guessPackage(types : List<String>, allTypes: Map<String, GenerateTraitOrClass>) =
types.map { allTypes[it] } types.map { allTypes[it] }
.map { it?.namespace } .map { it?.namespace }
.filterNotNull() .filterNotNull()
.filter { it != "" } .filter { it.isNotEmpty() }
.distinct() .distinct()
.minBy { it.split('.').size() } ?: "" .minBy { it.split('.').size() } ?: ""
@@ -0,0 +1,72 @@
package org.jetbrains.idl2k
import java.util.*
interface Type {
val nullable: Boolean
fun render(): String
protected fun String.withSuffix(): String = if (nullable) "$this?" else this
}
data object UnitType : Type {
override val nullable: Boolean
get() = false
override fun render() = "Unit"
}
data object DynamicType : Type {
override val nullable: Boolean
get() = false
override fun render() = "dynamic"
}
data class AnyType(override val nullable: Boolean = true) : Type {
override fun render() = "Any".withSuffix()
}
data class SimpleType(val type: String, override val nullable: Boolean) : Type {
override fun render() = type.withSuffix()
}
data class FunctionType(val parameterTypes : List<Attribute>, val returnType : Type, override val nullable: Boolean) : Type {
override fun render() = if (nullable) "(${renderImpl()})?" else renderImpl()
private fun renderImpl() = "(${parameterTypes.map { it.type.render() }.join(", ")}) -> ${returnType.render()}"
}
val FunctionType.arity : Int
get() = parameterTypes.size()
data class UnionType(val namespace: String, types: Collection<Type>, override val nullable: Boolean, val memberTypes: Set<Type> = LinkedHashSet(types.sortBy { it.toString() })) : Type {
val name = "Union${this.memberTypes.map { it.render() }.joinToString("Or")}"
fun contains(type: Type) = type in memberTypes
override fun equals(other: Any?): Boolean = other is UnionType && memberTypes == other.memberTypes
override fun hashCode(): Int = memberTypes.hashCode()
override fun toString(): String = memberTypes.map { it.toString() }.join(", ", "Union<", ">")
override fun render(): String = name.withSuffix()
}
fun UnionType.toSingleTypeIfPossible() = if (this.memberTypes.size() == 1) this.memberTypes.single().withNullability(nullable) else this
data class ArrayType(val memberType: Type, override val nullable: Boolean) : Type {
override fun render(): String = "Array<${memberType.render()}>".withSuffix()
}
suppress("UNCHECKED_CAST")
private fun <T: Type> T.copyWithNullability(nullable: Boolean): T = when (this) {
is UnitType -> UnitType
is DynamicType -> this
is AnyType -> this.copy(nullable = nullable)
is SimpleType -> this.copy(nullable = nullable)
is FunctionType -> this.copy(nullable = nullable)
is UnionType -> this.copy(types = this.memberTypes, nullable = nullable)
is ArrayType -> this.copy(nullable = nullable)
else -> throw UnsupportedOperationException()
} as T
private fun <T: Type> T.withNullabilityImpl(nullable: Boolean): T = if (this.nullable == nullable) this else copyWithNullability(nullable)
fun <T: Type> T.withNullability(nullable: Boolean): T = withNullabilityImpl(this.nullable or nullable)
fun <T: Type> T.toNullable(): T = withNullabilityImpl(true)
fun <T: Type> T.dropNullable(): T = withNullabilityImpl(false)