From 68d14de00087bdc42b22883c46fe561e2385f5fd Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 25 Jan 2017 19:57:07 +0300 Subject: [PATCH] JS: add support of Promise in IDL2K --- libraries/tools/idl2k/pom.xml | 1 + .../main/antlr4/org/antlr/webidl/WebIDL.g4 | 7 +- libraries/tools/idl2k/src/main/kotlin/idl.kt | 67 +++++++++++++++++-- .../idl2k/src/main/kotlin/typeMappings.kt | 14 ++-- .../tools/idl2k/src/main/kotlin/types.kt | 26 ++++--- 5 files changed, 91 insertions(+), 24 deletions(-) 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