diff --git a/libraries/tools/idl2k/src/main/kotlin/gen.kt b/libraries/tools/idl2k/src/main/kotlin/gen.kt index f891a57ecf5..43fb64f9105 100644 --- a/libraries/tools/idl2k/src/main/kotlin/gen.kt +++ b/libraries/tools/idl2k/src/main/kotlin/gen.kt @@ -40,7 +40,8 @@ fun generateFunction(repository: Repository, function: Operation, functionName: override = false, kind = AttributeKind.ARGUMENT, vararg = it.vararg, - static = it.static + static = it.static, + required = it.required ) }, nativeGetterOrSetter = nativeGetterOrSetter, @@ -100,7 +101,8 @@ fun generateAttribute(putNoImpl: Boolean, repository: Repository, attribute: Att kind = if (attribute.readOnly) AttributeKind.VAL else AttributeKind.VAR, override = false, vararg = attribute.vararg, - static = attribute.static + static = attribute.static, + required = attribute.required ) private fun InterfaceDefinition.superTypes(repository: Repository) = superTypes.map { repository.interfaces[it] }.filterNotNull() @@ -118,7 +120,7 @@ private fun resolveDefinitionKind(repository: Repository, iface: InterfaceDefini private fun InterfaceDefinition.mapAttributes(repository: Repository) = attributes.map { generateAttribute(putNoImpl = dictionary, repository = repository, attribute = it, nullableAttributes = dictionary) } private fun InterfaceDefinition.mapOperations(repository: Repository) = operations.flatMap { generateFunctions(repository, it) } -private fun Constant.mapConstant(repository : Repository) = GenerateAttribute(name, mapType(repository, type), null, false, AttributeKind.VAL, false, false, true) +private fun Constant.mapConstant(repository : Repository) = GenerateAttribute(name, mapType(repository, type), null, false, AttributeKind.VAL, false, false, true, false) private val EMPTY_CONSTRUCTOR = ExtendedAttribute(null, "Constructor", emptyList()) fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateTraitOrClass { diff --git a/libraries/tools/idl2k/src/main/kotlin/idl.kt b/libraries/tools/idl2k/src/main/kotlin/idl.kt index af086b053cb..7e368009d47 100644 --- a/libraries/tools/idl2k/src/main/kotlin/idl.kt +++ b/libraries/tools/idl2k/src/main/kotlin/idl.kt @@ -29,7 +29,7 @@ import java.util.ArrayList data class ExtendedAttribute(val name: String?, val call: String, val arguments: List) data class Operation(val name: String, val returnType: Type, val parameters: List, val attributes: List, 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 Attribute(val name: String, val type: Type, val readOnly: Boolean = true, val defaultValue: String? = null, val vararg: Boolean, val static: Boolean, val required: Boolean) data class Constant(val name: String, val type: Type, val value: String?) enum class DefinitionKind { @@ -102,7 +102,7 @@ class ExtendedAttributeParser(private val namespace: String) : WebIDLBaseVisitor object : WebIDLBaseVisitor() { override fun visitTerminal(node: TerminalNode) { if (node.symbol.type == WebIDLLexer.IDENTIFIER_WEBIDL) { - arguments.add(Attribute(node.text, AnyType(), true, vararg = false, static = false)) + arguments.add(Attribute(node.text, AnyType(), true, vararg = false, static = false, required = false)) } } }.visitChildren(ctx) @@ -202,8 +202,9 @@ class AttributeVisitor(private val readOnly: Boolean = false, private val static private var name: String = "" private var defaultValue: String? = null private var vararg: Boolean = false + private var required: Boolean = false - override fun defaultResult(): Attribute = Attribute(name, type, readOnly, defaultValue, vararg, static) + override fun defaultResult(): Attribute = Attribute(name, type, readOnly, defaultValue, vararg, static, required) override fun visitType(ctx: WebIDLParser.TypeContext): Attribute { type = TypeVisitor(namespace).visit(ctx) @@ -214,6 +215,9 @@ class AttributeVisitor(private val readOnly: Boolean = false, private val static if (ctx.children?.any { it is TerminalNode && it.text == "optional" } ?: false) { defaultValue = "noImpl" } + if (ctx.children?.any { it is TerminalNode && it.text == "required" } ?: false) { + required = true + } return visitChildren(ctx) } @@ -367,6 +371,7 @@ class DefinitionVisitor(val extendedAttributes: List, val nam ?.text val type = TypeVisitor(namespace).visit(ctx.children.first { it is TypeContext }) + var required = false val defaultValue = object : WebIDLBaseVisitor() { private var value: String? = null @@ -376,9 +381,16 @@ class DefinitionVisitor(val extendedAttributes: List, val nam value = ctx2.text return value } + + override fun visitRequired(ctx: RequiredContext?): String? { + if (ctx?.children?.any { it is TerminalNode && it.text == "required" } ?: false) { + required = true + } + return super.visitRequired(ctx) + } }.visit(ctx) - attributes.add(Attribute(name ?: "", type, false, defaultValue, false, static)) + attributes.add(Attribute(name ?: "", type, false, defaultValue, false, static, required)) return defaultResult() } diff --git a/libraries/tools/idl2k/src/main/kotlin/model.kt b/libraries/tools/idl2k/src/main/kotlin/model.kt index 05a90a0ceb4..532883fe078 100644 --- a/libraries/tools/idl2k/src/main/kotlin/model.kt +++ b/libraries/tools/idl2k/src/main/kotlin/model.kt @@ -28,7 +28,7 @@ data class Repository( enum class AttributeKind { VAL, VAR, ARGUMENT } -data class GenerateAttribute(val name: String, val type: Type, val initializer: String?, val getterSetterNoImpl: Boolean, val kind: AttributeKind, 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 kind: AttributeKind, val override: Boolean, var vararg: Boolean, val static: Boolean, val required: Boolean) val GenerateAttribute.getterNoImpl: Boolean get() = getterSetterNoImpl diff --git a/libraries/tools/idl2k/src/main/kotlin/render.kt b/libraries/tools/idl2k/src/main/kotlin/render.kt index 62fcdefd4de..50ec4850579 100644 --- a/libraries/tools/idl2k/src/main/kotlin/render.kt +++ b/libraries/tools/idl2k/src/main/kotlin/render.kt @@ -86,6 +86,7 @@ private val keywords = setOf("interface", "is", "as") private fun String.parse() = if (this.startsWith("0x")) BigInteger(this.substring(2), 16) else BigInteger(this) private fun String.replaceWrongConstants(type: Type) = when { + this == "null" && type.nullable -> "null" this == "noImpl" || type is SimpleType && type.type == "Int" && parse() > BigInteger.valueOf(Int.MAX_VALUE.toLong()) -> "noImpl" type is SimpleType && type.type == "Double" && this.matches("[0-9]+".toRegex()) -> "${this}.0" else -> this @@ -242,7 +243,11 @@ fun Appendable.render(allTypes: Map, typeNamesToUn } fun Appendable.renderBuilderFunction(dictionary: GenerateTraitOrClass, allSuperTypes: List, allTypes: Set) { - val fields = (dictionary.memberAttributes + allSuperTypes.flatMap { it.memberAttributes }).distinctBy { it.signature }.map { it.copy(kind = AttributeKind.ARGUMENT) }.dynamicIfUnknownType(allTypes) + val fields = (dictionary.memberAttributes + allSuperTypes.flatMap { it.memberAttributes }) + .distinctBy { it.signature } + .map { it.copy(kind = AttributeKind.ARGUMENT) } + .dynamicIfUnknownType(allTypes) + .map { if (it.initializer == null && (it.type.nullable || it.type == DynamicType) && !it.required) it.copy(initializer = "null") else it } appendln("@Suppress(\"NOTHING_TO_INLINE\")") append("public inline fun ${dictionary.name}") @@ -308,7 +313,8 @@ private fun merge(a: GenerateAttribute, b: GenerateAttribute): GenerateAttribute merge(a.kind, b.kind), a.override, a.vararg, - a.static + a.static, + a.required || b.required ) }