JS: add enum emulation to IDL2K
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.idl2k
|
||||
|
||||
import org.jetbrains.idl2k.util.mapEnumConstant
|
||||
|
||||
private fun Operation.getterOrSetter() = this.attributes.map { it.call }.toSet().let { attributes ->
|
||||
when {
|
||||
"getter" in attributes -> NativeGetterOrSetter.GETTER
|
||||
@@ -89,7 +91,7 @@ fun generateAttribute(putNoImpl: Boolean, repository: Repository, attribute: Att
|
||||
type = mapType(repository, attribute.type).let { if (nullableAttributes) it.toNullable() else it },
|
||||
initializer =
|
||||
if (putNoImpl && !attribute.static) {
|
||||
mapLiteral(attribute.defaultValue, mapType(repository, attribute.type))
|
||||
mapLiteral(attribute.defaultValue, mapType(repository, attribute.type), repository.enums)
|
||||
}
|
||||
else if (attribute.defaultValue != null) {
|
||||
"definedExternally"
|
||||
@@ -228,15 +230,21 @@ fun generateUnions(ifaces: List<GenerateTraitOrClass>, typedefs: Iterable<Typede
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapLiteral(literal: String?, expectedType: Type = DynamicType) = when (literal) {
|
||||
"[]" -> when {
|
||||
expectedType == DynamicType -> "arrayOf<dynamic>()"
|
||||
expectedType is AnyType -> "arrayOf<dynamic>()"
|
||||
expectedType is UnionType -> "arrayOf<dynamic>()"
|
||||
else -> "arrayOf()"
|
||||
private fun mapLiteral(literal: String?, expectedType: Type = DynamicType, enums: Map<String, EnumDefinition>) =
|
||||
if (literal != null && expectedType is SimpleType && expectedType.type in enums.keys) {
|
||||
expectedType.type + "." + mapEnumConstant(literal.removeSurrounding("\"", "\""))
|
||||
}
|
||||
else {
|
||||
when (literal) {
|
||||
"[]" -> when {
|
||||
expectedType == DynamicType -> "arrayOf<dynamic>()"
|
||||
expectedType is AnyType -> "arrayOf<dynamic>()"
|
||||
expectedType is UnionType -> "arrayOf<dynamic>()"
|
||||
else -> "arrayOf()"
|
||||
}
|
||||
else -> literal
|
||||
}
|
||||
}
|
||||
else -> literal
|
||||
}
|
||||
|
||||
fun implementInterfaces(declarations: List<GenerateTraitOrClass>) {
|
||||
val unimplementedMemberMap = getUnimplementedMembers(declarations)
|
||||
|
||||
@@ -20,13 +20,12 @@ 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
|
||||
import org.antlr.webidl.WebIDLParser
|
||||
import org.antlr.webidl.WebIDLParser.*
|
||||
import java.util.ArrayList
|
||||
import java.util.*
|
||||
|
||||
data class ExtendedAttribute(val name: String?, val call: String, val arguments: List<Attribute>)
|
||||
data class Operation(val name: String, val returnType: Type, val parameters: List<Attribute>, val attributes: List<ExtendedAttribute>, val static: Boolean)
|
||||
@@ -57,7 +56,7 @@ data class InterfaceDefinition(
|
||||
) : 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, val entries: List<String>) : Definition
|
||||
|
||||
class ExtendedAttributeArgumentsParser(private val namespace: String) : WebIDLBaseVisitor<List<Attribute>>() {
|
||||
private val arguments = ArrayList<Attribute>()
|
||||
@@ -337,13 +336,15 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
|
||||
private val constants = ArrayList<Constant>()
|
||||
private var partial = false
|
||||
private var callback = false
|
||||
private val enumEntries = mutableListOf<String>()
|
||||
private var enumEntryExpected = false
|
||||
|
||||
override fun defaultResult(): Definition = when (kind) {
|
||||
DefinitionKind.INTERFACE -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, false, partial, callback)
|
||||
DefinitionKind.DICTIONARY -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, /* dictionary = */ true, partial, callback)
|
||||
DefinitionKind.EXTENSION_INTERFACE -> ExtensionInterfaceDefinition(namespace, name, implements ?: "")
|
||||
DefinitionKind.TYPEDEF -> TypedefDefinition(typedefType ?: AnyType(true), namespace, name)
|
||||
DefinitionKind.ENUM -> EnumDefinition(namespace, name)
|
||||
DefinitionKind.ENUM -> EnumDefinition(namespace, name, enumEntries)
|
||||
}
|
||||
|
||||
override fun visitCallbackRestOrInterface(ctx: WebIDLParser.CallbackRestOrInterfaceContext): Definition {
|
||||
@@ -408,12 +409,23 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
|
||||
}
|
||||
|
||||
override fun visitEnum_(ctx: Enum_Context): Definition {
|
||||
enumEntryExpected = true
|
||||
kind = DefinitionKind.ENUM
|
||||
name = getName(ctx)
|
||||
|
||||
super.visitEnum_(ctx)
|
||||
|
||||
enumEntryExpected = false
|
||||
return defaultResult()
|
||||
}
|
||||
|
||||
override fun visitTerminal(node: TerminalNode): Definition {
|
||||
if (enumEntryExpected && node.symbol.type == WebIDLParser.STRING_WEBIDL) {
|
||||
enumEntries += node.symbol.text.removeSurrounding("\"", "\"")
|
||||
}
|
||||
return super.visitTerminal(node)
|
||||
}
|
||||
|
||||
override fun visitDictionary(ctx: DictionaryContext): Definition {
|
||||
kind = DefinitionKind.DICTIONARY
|
||||
name = getName(ctx)
|
||||
|
||||
@@ -40,7 +40,7 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
}
|
||||
val unions = generateUnions(definitions, repository.typeDefs.values)
|
||||
val allPackages = definitions.map { it.namespace }.distinct().sorted()
|
||||
val allPackages = (definitions.asSequence().map { it.namespace } + repository.enums.values.map { it.namespace }).distinct().sorted()
|
||||
implementInterfaces(definitions)
|
||||
|
||||
outDir.deleteRecursively()
|
||||
@@ -66,7 +66,7 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
w.appendln()
|
||||
|
||||
w.render(pkg, definitions, unions)
|
||||
w.render(pkg, definitions, unions, repository.enums.values.toList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.idl2k
|
||||
|
||||
import org.jetbrains.idl2k.util.mapEnumConstant
|
||||
import java.math.BigInteger
|
||||
|
||||
private fun <O : Appendable> O.indent(commented: Boolean = false, level: Int) {
|
||||
@@ -142,7 +143,9 @@ private fun GenerateFunction.isCommented(parent: String) =
|
||||
private fun GenerateAttribute.isRequiredFunctionArgument(owner: String, functionName: String) = "$owner.$functionName.$name" in requiredArguments
|
||||
private fun GenerateFunction.fixRequiredArguments(parent: String) = copy(arguments = arguments.map { arg -> arg.copy(initializer = if (arg.isRequiredFunctionArgument(parent, name)) null else arg.initializer) })
|
||||
|
||||
fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUnions: Map<String, List<String>>, iface: GenerateTraitOrClass, markerAnnotation: Boolean = false) {
|
||||
fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, enums: List<EnumDefinition>, typeNamesToUnions: Map<String, List<String>>, iface: GenerateTraitOrClass, markerAnnotation: Boolean = false) {
|
||||
val allTypesAndEnums = allTypes.keys + enums.map { it.name }
|
||||
|
||||
append("public external ")
|
||||
if (markerAnnotation) {
|
||||
append("@marker ")
|
||||
@@ -159,7 +162,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
|
||||
append(iface.name)
|
||||
val primary = iface.primaryConstructor
|
||||
if (primary != null && (primary.constructor.arguments.isNotEmpty() || iface.secondaryConstructors.isNotEmpty())) {
|
||||
renderArgumentsDeclaration(primary.constructor.fixRequiredArguments(iface.name).arguments.dynamicIfUnknownType(allTypes.keys), false)
|
||||
renderArgumentsDeclaration(primary.constructor.fixRequiredArguments(iface.name).arguments.dynamicIfUnknownType(allTypesAndEnums), false)
|
||||
}
|
||||
|
||||
val superTypesExclude = inheritanceExclude[iface.name] ?: emptySet()
|
||||
@@ -176,7 +179,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
|
||||
iface.secondaryConstructors.forEach { secondary ->
|
||||
indent(false, 1)
|
||||
append("constructor")
|
||||
renderArgumentsDeclaration(secondary.constructor.fixRequiredArguments(iface.name).arguments.dynamicIfUnknownType(allTypes.keys), false)
|
||||
renderArgumentsDeclaration(secondary.constructor.fixRequiredArguments(iface.name).arguments.dynamicIfUnknownType(allTypesAndEnums), false)
|
||||
|
||||
appendln()
|
||||
}
|
||||
@@ -188,7 +191,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
|
||||
|
||||
iface.memberAttributes
|
||||
.filter { it !in superAttributes && !it.static && (it.isVar || (it.isVal && superAttributesByName[it.name]?.hasNoVars() ?: true)) }
|
||||
.map { it.dynamicIfUnknownType(allTypes.keys) }
|
||||
.map { it.dynamicIfUnknownType(allTypesAndEnums) }
|
||||
.groupBy { it.name }
|
||||
.mapValues { it.value.filter { "${iface.name}.${it.name}" !in commentOutDeclarations && "${iface.name}.${it.name}: ${it.type.render()}" !in commentOutDeclarations } }
|
||||
.filterValues { it.isNotEmpty() }
|
||||
@@ -217,7 +220,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
|
||||
}
|
||||
}
|
||||
val memberFunctions = iface.memberFunctions.filter { (it !in superFunctions || it.override) && !it.static }
|
||||
.map { it.dynamicIfUnknownType(allTypes.keys) }.groupBy { it.signature }.reduceValues(::betterFunction).values
|
||||
.map { it.dynamicIfUnknownType(allTypesAndEnums) }.groupBy { it.signature }.reduceValues(::betterFunction).values
|
||||
|
||||
fun doRenderFunction(function: GenerateFunction, level: Int = 1) {
|
||||
renderFunctionDeclaration(
|
||||
@@ -255,7 +258,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
|
||||
appendln()
|
||||
|
||||
if (iface.generateBuilderFunction) {
|
||||
renderBuilderFunction(iface, allSuperTypes, allTypes.keys)
|
||||
renderBuilderFunction(iface, allSuperTypes, allTypesAndEnums)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,21 +339,40 @@ private fun merge(a: GenerateAttribute, b: GenerateAttribute): GenerateAttribute
|
||||
|
||||
fun <K, V> List<Pair<K, V>>.toMultiMap(): Map<K, List<V>> = groupBy { it.first }.mapValues { it.value.map { it.second } }
|
||||
|
||||
fun Appendable.render(namespace: String, ifaces: List<GenerateTraitOrClass>, unions : GenerateUnionTypes) {
|
||||
fun Appendable.render(enumDefinition: EnumDefinition) {
|
||||
appendln("/* please, don't implement this interface! */")
|
||||
appendln("public external interface ${enumDefinition.name} {")
|
||||
indent(level = 1)
|
||||
appendln("companion object")
|
||||
appendln("}")
|
||||
|
||||
for (entry in enumDefinition.entries) {
|
||||
val entryName = mapEnumConstant(entry)
|
||||
appendln("public inline val ${enumDefinition.name}.Companion.$entryName: ${enumDefinition.name} " +
|
||||
"get() = \"$entry\".asDynamic().unsafeCast<${enumDefinition.name}>()")
|
||||
}
|
||||
|
||||
appendln()
|
||||
}
|
||||
|
||||
fun Appendable.render(namespace: String, ifaces: List<GenerateTraitOrClass>, unions: GenerateUnionTypes, enums: List<EnumDefinition>) {
|
||||
val declaredTypes = ifaces.associateBy { it.name }
|
||||
|
||||
val allTypes = declaredTypes + unions.anonymousUnionsMap + unions.typedefsMarkersMap
|
||||
declaredTypes.values.filter { it.namespace == namespace }.forEach {
|
||||
render(allTypes, unions.typeNamesToUnionsMap, it)
|
||||
render(allTypes, enums, unions.typeNamesToUnionsMap, it)
|
||||
}
|
||||
|
||||
unions.anonymousUnionsMap.values.filter { it.namespace == "" || it.namespace == namespace }.forEach {
|
||||
render(allTypes, emptyMap(), it, markerAnnotation = true)
|
||||
render(allTypes, enums, emptyMap(), it, markerAnnotation = true)
|
||||
}
|
||||
|
||||
unions.typedefsMarkersMap.values.filter { it.namespace == "" || it.namespace == namespace }.forEach {
|
||||
render(allTypes, emptyMap(), it, markerAnnotation = true)
|
||||
render(allTypes, enums, emptyMap(), it, markerAnnotation = true)
|
||||
}
|
||||
|
||||
enums.filter { it.namespace == namespace }
|
||||
.forEach { render(it) }
|
||||
}
|
||||
|
||||
enum class MemberModality {
|
||||
|
||||
@@ -78,7 +78,6 @@ internal fun mapType(repository: Repository, type: Type): Type = when (type) {
|
||||
typeName in typeMapper -> typeMapper[typeName]!!.withNullability(type.nullable)
|
||||
typeName in repository.interfaces -> type
|
||||
typeName in repository.typeDefs -> mapTypedef(repository, type)
|
||||
typeName in repository.enums -> SimpleType("String", type.nullable)
|
||||
|
||||
else -> type
|
||||
}
|
||||
|
||||
@@ -41,3 +41,5 @@ fun <T> List<List<T>>.mutations() : List<List<T>> {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun mapEnumConstant(entry: String) = if (entry.isEmpty()) "EMPTY" else entry.toUpperCase().replace("-", "_")
|
||||
Reference in New Issue
Block a user