JS: add enum emulation to IDL2K
This commit is contained in:
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.idl2k
|
package org.jetbrains.idl2k
|
||||||
|
|
||||||
|
import org.jetbrains.idl2k.util.mapEnumConstant
|
||||||
|
|
||||||
private fun Operation.getterOrSetter() = this.attributes.map { it.call }.toSet().let { attributes ->
|
private fun Operation.getterOrSetter() = this.attributes.map { it.call }.toSet().let { attributes ->
|
||||||
when {
|
when {
|
||||||
"getter" in attributes -> NativeGetterOrSetter.GETTER
|
"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 },
|
type = mapType(repository, attribute.type).let { if (nullableAttributes) it.toNullable() else it },
|
||||||
initializer =
|
initializer =
|
||||||
if (putNoImpl && !attribute.static) {
|
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) {
|
else if (attribute.defaultValue != null) {
|
||||||
"definedExternally"
|
"definedExternally"
|
||||||
@@ -228,15 +230,21 @@ fun generateUnions(ifaces: List<GenerateTraitOrClass>, typedefs: Iterable<Typede
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mapLiteral(literal: String?, expectedType: Type = DynamicType) = when (literal) {
|
private fun mapLiteral(literal: String?, expectedType: Type = DynamicType, enums: Map<String, EnumDefinition>) =
|
||||||
"[]" -> when {
|
if (literal != null && expectedType is SimpleType && expectedType.type in enums.keys) {
|
||||||
expectedType == DynamicType -> "arrayOf<dynamic>()"
|
expectedType.type + "." + mapEnumConstant(literal.removeSurrounding("\"", "\""))
|
||||||
expectedType is AnyType -> "arrayOf<dynamic>()"
|
}
|
||||||
expectedType is UnionType -> "arrayOf<dynamic>()"
|
else {
|
||||||
else -> "arrayOf()"
|
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>) {
|
fun implementInterfaces(declarations: List<GenerateTraitOrClass>) {
|
||||||
val unimplementedMemberMap = getUnimplementedMembers(declarations)
|
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.CommonTokenStream
|
||||||
import org.antlr.v4.runtime.ParserRuleContext
|
import org.antlr.v4.runtime.ParserRuleContext
|
||||||
import org.antlr.v4.runtime.tree.ParseTree
|
import org.antlr.v4.runtime.tree.ParseTree
|
||||||
import org.antlr.v4.runtime.tree.RuleNode
|
|
||||||
import org.antlr.v4.runtime.tree.TerminalNode
|
import org.antlr.v4.runtime.tree.TerminalNode
|
||||||
import org.antlr.webidl.WebIDLBaseVisitor
|
import org.antlr.webidl.WebIDLBaseVisitor
|
||||||
import org.antlr.webidl.WebIDLLexer
|
import org.antlr.webidl.WebIDLLexer
|
||||||
import org.antlr.webidl.WebIDLParser
|
import org.antlr.webidl.WebIDLParser
|
||||||
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 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)
|
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
|
) : Definition
|
||||||
|
|
||||||
data class ExtensionInterfaceDefinition(val namespace: String, val name: String, val implements: String) : 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>>() {
|
class ExtendedAttributeArgumentsParser(private val namespace: String) : WebIDLBaseVisitor<List<Attribute>>() {
|
||||||
private val arguments = ArrayList<Attribute>()
|
private val arguments = ArrayList<Attribute>()
|
||||||
@@ -337,13 +336,15 @@ class DefinitionVisitor(val extendedAttributes: List<ExtendedAttribute>, val nam
|
|||||||
private val constants = ArrayList<Constant>()
|
private val constants = ArrayList<Constant>()
|
||||||
private var partial = false
|
private var partial = false
|
||||||
private var callback = false
|
private var callback = false
|
||||||
|
private val enumEntries = mutableListOf<String>()
|
||||||
|
private var enumEntryExpected = false
|
||||||
|
|
||||||
override fun defaultResult(): Definition = when (kind) {
|
override fun defaultResult(): Definition = when (kind) {
|
||||||
DefinitionKind.INTERFACE -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, false, partial, callback)
|
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.DICTIONARY -> InterfaceDefinition(name, namespace, extendedAttributes, operations, attributes, inherited, constants, /* dictionary = */ true, partial, callback)
|
||||||
DefinitionKind.EXTENSION_INTERFACE -> ExtensionInterfaceDefinition(namespace, name, implements ?: "")
|
DefinitionKind.EXTENSION_INTERFACE -> ExtensionInterfaceDefinition(namespace, name, implements ?: "")
|
||||||
DefinitionKind.TYPEDEF -> TypedefDefinition(typedefType ?: AnyType(true), namespace, name)
|
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 {
|
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 {
|
override fun visitEnum_(ctx: Enum_Context): Definition {
|
||||||
|
enumEntryExpected = true
|
||||||
kind = DefinitionKind.ENUM
|
kind = DefinitionKind.ENUM
|
||||||
name = getName(ctx)
|
name = getName(ctx)
|
||||||
|
|
||||||
|
super.visitEnum_(ctx)
|
||||||
|
|
||||||
|
enumEntryExpected = false
|
||||||
return defaultResult()
|
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 {
|
override fun visitDictionary(ctx: DictionaryContext): Definition {
|
||||||
kind = DefinitionKind.DICTIONARY
|
kind = DefinitionKind.DICTIONARY
|
||||||
name = getName(ctx)
|
name = getName(ctx)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val unions = generateUnions(definitions, repository.typeDefs.values)
|
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)
|
implementInterfaces(definitions)
|
||||||
|
|
||||||
outDir.deleteRecursively()
|
outDir.deleteRecursively()
|
||||||
@@ -66,7 +66,7 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
w.appendln()
|
w.appendln()
|
||||||
|
|
||||||
w.render(pkg, definitions, unions)
|
w.render(pkg, definitions, unions, repository.enums.values.toList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.idl2k
|
package org.jetbrains.idl2k
|
||||||
|
|
||||||
|
import org.jetbrains.idl2k.util.mapEnumConstant
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
|
|
||||||
private fun <O : Appendable> O.indent(commented: Boolean = false, level: Int) {
|
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 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) })
|
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 ")
|
append("public external ")
|
||||||
if (markerAnnotation) {
|
if (markerAnnotation) {
|
||||||
append("@marker ")
|
append("@marker ")
|
||||||
@@ -159,7 +162,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
|
|||||||
append(iface.name)
|
append(iface.name)
|
||||||
val primary = iface.primaryConstructor
|
val primary = iface.primaryConstructor
|
||||||
if (primary != null && (primary.constructor.arguments.isNotEmpty() || iface.secondaryConstructors.isNotEmpty())) {
|
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()
|
val superTypesExclude = inheritanceExclude[iface.name] ?: emptySet()
|
||||||
@@ -176,7 +179,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
|
|||||||
iface.secondaryConstructors.forEach { secondary ->
|
iface.secondaryConstructors.forEach { secondary ->
|
||||||
indent(false, 1)
|
indent(false, 1)
|
||||||
append("constructor")
|
append("constructor")
|
||||||
renderArgumentsDeclaration(secondary.constructor.fixRequiredArguments(iface.name).arguments.dynamicIfUnknownType(allTypes.keys), false)
|
renderArgumentsDeclaration(secondary.constructor.fixRequiredArguments(iface.name).arguments.dynamicIfUnknownType(allTypesAndEnums), false)
|
||||||
|
|
||||||
appendln()
|
appendln()
|
||||||
}
|
}
|
||||||
@@ -188,7 +191,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
|
|||||||
|
|
||||||
iface.memberAttributes
|
iface.memberAttributes
|
||||||
.filter { it !in superAttributes && !it.static && (it.isVar || (it.isVal && superAttributesByName[it.name]?.hasNoVars() ?: true)) }
|
.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 }
|
.groupBy { it.name }
|
||||||
.mapValues { it.value.filter { "${iface.name}.${it.name}" !in commentOutDeclarations && "${iface.name}.${it.name}: ${it.type.render()}" !in commentOutDeclarations } }
|
.mapValues { it.value.filter { "${iface.name}.${it.name}" !in commentOutDeclarations && "${iface.name}.${it.name}: ${it.type.render()}" !in commentOutDeclarations } }
|
||||||
.filterValues { it.isNotEmpty() }
|
.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 }
|
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) {
|
fun doRenderFunction(function: GenerateFunction, level: Int = 1) {
|
||||||
renderFunctionDeclaration(
|
renderFunctionDeclaration(
|
||||||
@@ -255,7 +258,7 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
|
|||||||
appendln()
|
appendln()
|
||||||
|
|
||||||
if (iface.generateBuilderFunction) {
|
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 <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 declaredTypes = ifaces.associateBy { it.name }
|
||||||
|
|
||||||
val allTypes = declaredTypes + unions.anonymousUnionsMap + unions.typedefsMarkersMap
|
val allTypes = declaredTypes + unions.anonymousUnionsMap + unions.typedefsMarkersMap
|
||||||
declaredTypes.values.filter { it.namespace == namespace }.forEach {
|
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 {
|
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 {
|
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 {
|
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 typeMapper -> typeMapper[typeName]!!.withNullability(type.nullable)
|
||||||
typeName in repository.interfaces -> type
|
typeName in repository.interfaces -> type
|
||||||
typeName in repository.typeDefs -> mapTypedef(repository, type)
|
typeName in repository.typeDefs -> mapTypedef(repository, type)
|
||||||
typeName in repository.enums -> SimpleType("String", type.nullable)
|
|
||||||
|
|
||||||
else -> type
|
else -> type
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,3 +41,5 @@ fun <T> List<List<T>>.mutations() : List<List<T>> {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun mapEnumConstant(entry: String) = if (entry.isEmpty()) "EMPTY" else entry.toUpperCase().replace("-", "_")
|
||||||
Reference in New Issue
Block a user