diff --git a/libraries/tools/idl2k/pom.xml b/libraries/tools/idl2k/pom.xml
index fcdf0bd23a5..8fa3ec7a00f 100644
--- a/libraries/tools/idl2k/pom.xml
+++ b/libraries/tools/idl2k/pom.xml
@@ -50,6 +50,7 @@
${antlr.version}
+ antlr
antlr4
diff --git a/libraries/tools/idl2k/src/main/antlr4/org/antlr/webidl/WebIDL.g4 b/libraries/tools/idl2k/src/main/antlr4/org/antlr/webidl/WebIDL.g4
index 76839736132..b46a2d632b3 100644
--- a/libraries/tools/idl2k/src/main/antlr4/org/antlr/webidl/WebIDL.g4
+++ b/libraries/tools/idl2k/src/main/antlr4/org/antlr/webidl/WebIDL.g4
@@ -465,7 +465,7 @@ nonAnyType
| 'DOMString' typeSuffix
| 'USVString' typeSuffix
| IDENTIFIER_WEBIDL typeSuffix
- | 'sequence' '<' type '>' null_
+ | sequenceType null_
| 'object' typeSuffix
| 'Date' typeSuffix
| 'RegExp' typeSuffix
@@ -506,6 +506,11 @@ integerType
| 'long'+
;
+sequenceType
+ : 'sequence' '<' type '>'
+ | 'FrozenArray' '<' type '>'
+;
+
promiseType
: 'Promise' '<' returnType '>'
;
diff --git a/libraries/tools/idl2k/src/main/kotlin/idl.kt b/libraries/tools/idl2k/src/main/kotlin/idl.kt
index a74d9db069c..db227c1038d 100644
--- a/libraries/tools/idl2k/src/main/kotlin/idl.kt
+++ b/libraries/tools/idl2k/src/main/kotlin/idl.kt
@@ -20,6 +20,7 @@ import org.antlr.v4.runtime.CharStream
import org.antlr.v4.runtime.CommonTokenStream
import org.antlr.v4.runtime.ParserRuleContext
import org.antlr.v4.runtime.tree.ParseTree
+import org.antlr.v4.runtime.tree.RuleNode
import org.antlr.v4.runtime.tree.TerminalNode
import org.antlr.webidl.WebIDLBaseVisitor
import org.antlr.webidl.WebIDLLexer
@@ -130,11 +131,24 @@ class UnionTypeVisitor(val namespace: String) : WebIDLBaseVisitor>()
class TypeVisitor(val namespace: String) : WebIDLBaseVisitor() {
private var type: Type = AnyType()
+ private var awaitingSimpleType = false
override fun defaultResult() = type
+ override fun visitType(ctx: TypeContext?): Type {
+ type = super.visitType(ctx)
+ return type
+ }
+
+ override fun visitReturnType(ctx: ReturnTypeContext?): Type {
+ awaitingSimpleType = true
+ type = super.visitReturnType(ctx)
+ return type
+ }
+
override fun visitNonAnyType(ctx: WebIDLParser.NonAnyTypeContext): Type {
- type = SimpleType(ctx.text, false)
+ awaitingSimpleType = true
+ type = super.visitNonAnyType(ctx)
return type
}
@@ -143,19 +157,62 @@ class TypeVisitor(val namespace: String) : WebIDLBaseVisitor() {
return type
}
+ override fun visitPromiseType(ctx: PromiseTypeContext): Type {
+ type = PromiseType(TypeVisitor(namespace).visitChildren(ctx), false)
+ return type
+ }
+
+ override fun visitSequenceType(ctx: SequenceTypeContext): Type {
+ val mutable = ctx.getChild(0).text == "sequence"
+ type = ArrayType(TypeVisitor(namespace).visitChildren(ctx), mutable = mutable, nullable = false)
+ return type
+ }
+
override fun visitTypeSuffix(ctx: TypeSuffixContext): Type {
when (ctx.text?.trim()) {
"?" -> type = type.toNullable()
- "[]" -> type = ArrayType(type, false)
- "[]?" -> type = ArrayType(type, true)
- "?[]" -> type = ArrayType(type.toNullable(), false)
+ "[]" -> type = ArrayType(type, mutable = true, nullable = false)
+ "[]?" -> type = ArrayType(type, mutable = true, nullable = false)
+ "?[]" -> type = ArrayType(type.toNullable(), mutable = true, nullable = false)
}
return type
}
+ override fun visitNull_(ctx: Null_Context): Type {
+ if (ctx.text?.trim() == "?") {
+ type = type.toNullable()
+ }
+ return type
+ }
+
override fun visitTerminal(node: TerminalNode): Type {
- type = SimpleType(node.text, false)
+ if (awaitingSimpleType) {
+ type = SimpleType(node.text, false)
+ awaitingSimpleType = false
+ }
+ return type
+ }
+
+ override fun visitUnsignedIntegerType(ctx: UnsignedIntegerTypeContext): Type {
+ awaitingSimpleType = false
+ type = super.visitUnsignedIntegerType(ctx)
+ return type
+ }
+
+ override fun visitUnrestrictedFloatType(ctx: UnrestrictedFloatTypeContext): Type {
+ awaitingSimpleType = false
+ type = super.visitUnrestrictedFloatType(ctx)
+ return type
+ }
+
+ override fun visitFloatType(ctx: FloatTypeContext): Type {
+ type = SimpleType(ctx.text, false)
+ return type
+ }
+
+ override fun visitIntegerType(ctx: IntegerTypeContext): Type {
+ type = SimpleType(ctx.text, false)
return type
}
}
diff --git a/libraries/tools/idl2k/src/main/kotlin/typeMappings.kt b/libraries/tools/idl2k/src/main/kotlin/typeMappings.kt
index 9c75c0edb6e..d0205e114af 100644
--- a/libraries/tools/idl2k/src/main/kotlin/typeMappings.kt
+++ b/libraries/tools/idl2k/src/main/kotlin/typeMappings.kt
@@ -63,6 +63,8 @@ fun Type.dynamicIfUnknownType(allTypes: Set, standardTypes: Set =
this is ArrayType -> copy(memberType = this.memberType.dynamicIfUnknownType(allTypes, standardTypes))
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)) })
+ this is PromiseType ->
+ copy(valueType = valueType.dynamicIfUnknownType(allTypes, standardTypes))
else -> DynamicType
}
@@ -74,19 +76,14 @@ internal fun mapType(repository: Repository, type: Type): Type = when (type) {
val typeName = type.type
when {
typeName in typeMapper -> typeMapper[typeName]!!.withNullability(type.nullable)
- typeName.endsWith("?") -> mapType(repository, SimpleType(typeName.removeSuffix("?"), false)).toNullable()
- typeName.endsWith("[]") -> ArrayType(memberType = mapType(repository, SimpleType(typeName.removeSuffix("[]"), false)), nullable = type.nullable)
- typeName.startsWith("unrestricted") -> mapType(repository, SimpleType(typeName.removePrefix("unrestricted"), false))
- typeName.startsWith("sequence<") -> ArrayType(mapType(repository, SimpleType(typeName.removePrefix("sequence<").removeSuffix(">").trim(), false)), type.nullable)
- typeName == "sequence" -> ArrayType(DynamicType, type.nullable)
typeName in repository.interfaces -> type
typeName in repository.typeDefs -> mapTypedef(repository, type)
typeName in repository.enums -> SimpleType("String", type.nullable)
- typeName.startsWith("Promise<") -> DynamicType
else -> type
}
}
+ is PromiseType -> type.copy(valueType = mapType(repository, type.valueType))
is ArrayType -> type.copy(memberType = mapType(repository, type.memberType))
is UnionType -> UnionType(type.namespace, type.memberTypes.map { mt -> mapType(repository, mt) }, type.nullable).toSingleTypeIfPossible()
is FunctionType -> type.copy(
@@ -94,7 +91,10 @@ internal fun mapType(repository: Repository, type: Type): Type = when (type) {
returnType = mapType(repository, type.returnType).dynamicIfAnyType(),
parameterTypes = type.parameterTypes.takeWhile { !it.vararg }.map { it.copy(type = mapType(repository, it.type)) }
)
- else -> type
+
+ is AnyType,
+ is UnitType,
+ is DynamicType -> type
}
private fun mapTypedef(repository: Repository, type: SimpleType): Type {
diff --git a/libraries/tools/idl2k/src/main/kotlin/types.kt b/libraries/tools/idl2k/src/main/kotlin/types.kt
index 3e552d38689..ee7163a79b7 100644
--- a/libraries/tools/idl2k/src/main/kotlin/types.kt
+++ b/libraries/tools/idl2k/src/main/kotlin/types.kt
@@ -2,40 +2,43 @@ package org.jetbrains.idl2k
import java.util.*
-interface Type {
- val nullable: Boolean
- fun render(): String
+sealed class Type {
+ abstract val nullable: Boolean
+ abstract fun render(): String
}
private fun String.appendNullabilitySuffix(type: Type) = if (type.nullable) "$this?" else this
-object UnitType : Type {
+object UnitType : Type() {
override val nullable: Boolean
get() = false
override fun render() = "Unit"
}
-object DynamicType : Type {
+object DynamicType : Type() {
override val nullable: Boolean
get() = false
override fun render() = "dynamic"
}
-data class AnyType(override val nullable: Boolean = true) : Type {
+data class AnyType(override val nullable: Boolean = true) : Type() {
override fun render() = "Any".appendNullabilitySuffix(this)
}
-data class SimpleType(val type: String, override val nullable: Boolean) : Type {
+data class SimpleType(val type: String, override val nullable: Boolean) : Type() {
override fun render() = type.appendNullabilitySuffix(this)
}
-data class FunctionType(val parameterTypes : List, val returnType : Type, override val nullable: Boolean) : Type {
+data class FunctionType(val parameterTypes : List, val returnType : Type, override val nullable: Boolean) : Type() {
override fun render() = if (nullable) "(${renderImpl()})?" else renderImpl()
private fun renderImpl() = "(${parameterTypes.joinToString(", ") { it.type.render() }}) -> ${returnType.render()}"
}
+data class PromiseType(val valueType: Type, override val nullable: Boolean) : Type() {
+ override fun render() = "Promise<${valueType.render()}>".appendNullabilitySuffix(this)
+}
val FunctionType.arity : Int
get() = parameterTypes.size
-class UnionType(val namespace: String, types: Collection, override val nullable: Boolean) : Type {
+class UnionType(val namespace: String, types: Collection, override val nullable: Boolean) : Type() {
val memberTypes: Set = LinkedHashSet(types.sortedBy { it.toString() })
val name = "Union${this.memberTypes.map { it.render() }.joinToString("Or")}"
@@ -52,8 +55,8 @@ class UnionType(val namespace: String, types: Collection, override val nul
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()}>".appendNullabilitySuffix(this)
+data class ArrayType(val memberType: Type, val mutable: Boolean, override val nullable: Boolean) : Type() {
+ override fun render(): String = "Array<${if (mutable) "" else "out "}${memberType.render()}>".appendNullabilitySuffix(this)
}
@Suppress("UNCHECKED_CAST")
@@ -66,6 +69,7 @@ private fun T.copyWithNullability(nullable: Boolean): T = when (this)
is FunctionType -> this.copy(nullable = nullable)
is UnionType -> this.copy(types = this.memberTypes, nullable = nullable)
is ArrayType -> this.copy(nullable = nullable)
+ is PromiseType -> this.copy(nullable = nullable)
else -> throw UnsupportedOperationException()
} as T