JS: add support of Promise<T> in IDL2K

This commit is contained in:
Alexey Andreev
2017-01-25 19:57:07 +03:00
parent 563a3a25cb
commit 68d14de000
5 changed files with 91 additions and 24 deletions
+1
View File
@@ -50,6 +50,7 @@
<version>${antlr.version}</version>
<executions>
<execution>
<id>antlr</id>
<goals>
<goal>antlr4</goal>
</goals>
@@ -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 '>'
;
+62 -5
View File
@@ -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<List<Type>>()
class TypeVisitor(val namespace: String) : WebIDLBaseVisitor<Type>() {
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<Type>() {
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
}
}
@@ -63,6 +63,8 @@ fun Type.dynamicIfUnknownType(allTypes: Set<String>, standardTypes: Set<Type> =
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 {
+15 -11
View File
@@ -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<Attribute>, val returnType : Type, override val nullable: Boolean) : Type {
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.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<Type>, override val nullable: Boolean) : Type {
class UnionType(val namespace: String, types: Collection<Type>, override val nullable: Boolean) : Type() {
val memberTypes: Set<Type> = 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<Type>, 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: Type> 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