IDL2K better dictionary support: generate interfaces with builder function

This commit is contained in:
Sergey Mashkov
2015-06-17 13:45:21 +03:00
parent c4d53e1e16
commit 8238883ac4
11 changed files with 886 additions and 179 deletions
+9 -6
View File
@@ -1,5 +1,6 @@
package org.jetbrains.idl2k
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ
import java.util.*
private fun Operation.getterOrSetter() = this.attributes.map { it.call }.toSet().let { attributes ->
@@ -22,7 +23,7 @@ fun generateFunction(repository: Repository, function: Operation, functionName:
initializer = it.defaultValue,
getterSetterNoImpl = false,
override = false,
readOnly = true,
kind = AttributeKind.ARGUMENT,
vararg = it.vararg,
static = it.static
)
@@ -66,7 +67,7 @@ fun generateAttribute(putNoImpl: Boolean, repository: Repository, attribute: Att
type = mapType(repository, attribute.type),
initializer = attribute.defaultValue,
getterSetterNoImpl = putNoImpl,
readOnly = attribute.readOnly,
kind = if (attribute.readOnly) AttributeKind.VAL else AttributeKind.VAR,
override = false,
vararg = attribute.vararg,
static = attribute.static
@@ -74,7 +75,7 @@ fun generateAttribute(putNoImpl: Boolean, repository: Repository, attribute: Att
private fun InterfaceDefinition.superTypes(repository: Repository) = superTypes.map { repository.interfaces[it] }.filterNotNull()
private fun resolveDefinitionKind(repository: Repository, iface: InterfaceDefinition, constructors: List<ExtendedAttribute> = iface.findConstructors()): GenerateDefinitionKind =
if (iface.dictionary || constructors.isNotEmpty() || iface.superTypes(repository).any { resolveDefinitionKind(repository, it) == GenerateDefinitionKind.CLASS }) {
if (constructors.isNotEmpty() || iface.superTypes(repository).any { resolveDefinitionKind(repository, it) == GenerateDefinitionKind.CLASS }) {
GenerateDefinitionKind.CLASS
} else {
GenerateDefinitionKind.TRAIT
@@ -82,7 +83,7 @@ private fun resolveDefinitionKind(repository: Repository, iface: InterfaceDefini
private fun InterfaceDefinition.mapAttributes(repository: Repository) = attributes.map { generateAttribute(!dictionary, repository, it) }
private fun InterfaceDefinition.mapOperations(repository: Repository) = operations.flatMap { generateFunctions(repository, it) }
private fun Constant.mapConstant(repository : Repository) = GenerateAttribute(name, mapType(repository, type), value, false, true, false, false, true)
private fun Constant.mapConstant(repository : Repository) = GenerateAttribute(name, mapType(repository, type), value, false, AttributeKind.VAL, false, false, true)
private val EMPTY_CONSTRUCTOR = ExtendedAttribute(null, "Constructor", emptyList())
fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateTraitOrClass {
@@ -132,7 +133,8 @@ fun generateTrait(repository: Repository, iface: InterfaceDefinition): GenerateT
memberFunctions = (iface.mapOperations(repository) + extensions.flatMap { it.mapOperations(repository) }).distinct().toList(),
constants = (iface.constants.map { it.mapConstant(repository) } + extensions.flatMap { it.constants.map { it.mapConstant(repository) } }.distinct().toList()),
primaryConstructor = primaryConstructorWithCall,
secondaryConstructors = secondaryConstructorsWithCall
secondaryConstructors = secondaryConstructorsWithCall,
generateBuilderFunction = iface.dictionary
)
}
@@ -161,7 +163,8 @@ fun mapUnionType(it: UnionType) = GenerateTraitOrClass(
memberFunctions = emptyList(),
constants = emptyList(),
primaryConstructor = null,
secondaryConstructors = emptyList()
secondaryConstructors = emptyList(),
generateBuilderFunction = false
)
fun generateUnionTypeTraits(allUnionTypes: Sequence<UnionType>): Sequence<GenerateTraitOrClass> = allUnionTypes.map(::mapUnionType)
+11 -3
View File
@@ -25,12 +25,19 @@ data class Repository(
val enums: Map<String, EnumDefinition>
)
data class GenerateAttribute(val name: String, val type: Type, val initializer: String?, val getterSetterNoImpl: Boolean, val readOnly: Boolean, val override: Boolean, var vararg: Boolean, val static: Boolean)
enum class AttributeKind {
VAL, VAR, ARGUMENT
}
data class GenerateAttribute(val name: String, val type: Type, val initializer: String?, val getterSetterNoImpl: Boolean, val kind: AttributeKind, val override: Boolean, var vararg: Boolean, val static: Boolean)
val GenerateAttribute.getterNoImpl: Boolean
get() = getterSetterNoImpl
val GenerateAttribute.setterNoImpl: Boolean
get() = getterSetterNoImpl && !readOnly
get() = getterSetterNoImpl && kind == AttributeKind.VAR
val GenerateAttribute.isVal: Boolean
get() = kind == AttributeKind.VAL
val GenerateAttribute.isVar: Boolean
get() = kind == AttributeKind.VAR
val Type.typeSignature: String
get() = when {
@@ -74,7 +81,8 @@ data class GenerateTraitOrClass(
val memberFunctions: List<GenerateFunction>,
val constants: List<GenerateAttribute>,
val primaryConstructor: ConstructorWithSuperTypeCall?,
val secondaryConstructors: List<ConstructorWithSuperTypeCall>
val secondaryConstructors: List<ConstructorWithSuperTypeCall>,
val generateBuilderFunction: Boolean
)
val GenerateFunction.signature: String
+56 -26
View File
@@ -2,7 +2,7 @@ package org.jetbrains.idl2k
import java.math.BigInteger
private fun <O : Appendable> O.indent(commented: Boolean, level: Int) {
private fun <O : Appendable> O.indent(commented: Boolean = false, level: Int) {
if (commented) {
append("//")
}
@@ -11,23 +11,31 @@ private fun <O : Appendable> O.indent(commented: Boolean, level: Int) {
}
}
private fun Appendable.renderAttributeDeclaration(arg: GenerateAttribute, override: Boolean, open: Boolean, commented: Boolean, level: Int = 1) {
indent(commented, level)
private fun Appendable.renderAttributeDeclaration(arg: GenerateAttribute, override: Boolean, open: Boolean, omitDefaults: Boolean = false) {
when {
override -> append("override ")
open -> append("open ")
arg.vararg -> append("vararg ")
}
append(if (arg.readOnly) "val" else "var")
append(" ")
append(arg.name)
append(when(arg.kind) {
AttributeKind.VAL -> "val "
AttributeKind.VAR -> "var "
AttributeKind.ARGUMENT -> ""
})
append(arg.name.replaceKeywords())
append(": ")
append(arg.type.render())
if (arg.initializer != null) {
if (arg.initializer != null && !omitDefaults) {
append(" = ")
append(arg.initializer.replaceWrongConstants(arg.type))
}
}
private fun Appendable.renderAttributeDeclarationAsProperty(arg: GenerateAttribute, override: Boolean, open: Boolean, commented: Boolean, level: Int, omitDefaults: Boolean) {
indent(commented, level)
renderAttributeDeclaration(arg, override, open, omitDefaults)
appendln()
if (arg.getterNoImpl) {
@@ -50,19 +58,10 @@ private fun String.replaceWrongConstants(type: Type) = when {
}
private fun String.replaceKeywords() = if (this in keywords) this + "_" else this
private fun Appendable.renderArgumentsDeclaration(args: List<GenerateAttribute>, omitDefaults: Boolean) =
private fun Appendable.renderArgumentsDeclaration(args: List<GenerateAttribute>, omitDefaults: Boolean = false) =
args.map {
StringBuilder {
if (it.vararg) {
append("vararg ")
}
append(it.name.replaceKeywords())
append(": ")
append(it.type.render())
if (!omitDefaults && it.initializer != null && it.initializer != "") {
append(" = ")
append(it.initializer.replaceWrongConstants(it.type))
}
renderAttributeDeclaration(it, it.override, false, omitDefaults)
}
}.joinTo(this, ", ", "(", ")")
@@ -90,10 +89,6 @@ private fun Appendable.renderFunctionDeclaration(f: GenerateFunction, override:
}
private fun List<GenerateAttribute>.hasNoVars() = none { it.isVar }
private val GenerateAttribute.isVal: Boolean
get() = readOnly
private val GenerateAttribute.isVar: Boolean
get() = !readOnly
private fun GenerateAttribute.isCommented(parent: String) = "$parent.$name" in commentOutDeclarations || "$parent.$name: ${type.render()}" in commentOutDeclarations
private fun GenerateFunction.isCommented(parent: String) =
@@ -154,7 +149,13 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
.filter { it !in superAttributes && !it.static && (it.isVar || (it.isVal && superAttributesByName[it.name]?.hasNoVars() ?: true)) }
.map { it.dynamicIfUnknownType(allTypes.keySet()) }
.groupBy { it.signature }.reduceValues().values().forEach { arg ->
renderAttributeDeclaration(arg, override = arg.signature in superSignatures, open = iface.kind == GenerateDefinitionKind.CLASS && arg.readOnly, commented = arg.isCommented(iface.name))
renderAttributeDeclarationAsProperty(arg,
override = arg.signature in superSignatures,
open = iface.kind == GenerateDefinitionKind.CLASS && arg.isVal,
commented = arg.isCommented(iface.name),
omitDefaults = iface.kind == GenerateDefinitionKind.TRAIT,
level = 1
)
}
iface.memberFunctions.filter { it !in superFunctions && !it.static }.map { it.dynamicIfUnknownType(allTypes.keySet()) }.groupBy { it.signature }.reduceValues(::betterFunction).values().forEach {
renderFunctionDeclaration(it.fixRequiredArguments(iface.name), it.signature in superSignatures, commented = it.isCommented(iface.name))
@@ -168,10 +169,10 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
indent(false, 1)
appendln("companion object {")
iface.constants.forEach {
renderAttributeDeclaration(it, override = false, open = false, level = 2, commented = it.isCommented(iface.name))
renderAttributeDeclarationAsProperty(it, override = false, open = false, level = 2, commented = it.isCommented(iface.name), omitDefaults = false)
}
staticAttributes.forEach {
renderAttributeDeclaration(it, override = false, open = false, level = 2, commented = it.isCommented(iface.name))
renderAttributeDeclarationAsProperty(it, override = false, open = false, level = 2, commented = it.isCommented(iface.name), omitDefaults = false)
}
staticFunctions.forEach {
renderFunctionDeclaration(it.fixRequiredArguments(iface.name), override = false, level = 2, commented = it.isCommented(iface.name))
@@ -182,6 +183,35 @@ fun Appendable.render(allTypes: Map<String, GenerateTraitOrClass>, typeNamesToUn
appendln("}")
appendln()
if (iface.generateBuilderFunction) {
renderBuilderFunction(iface, allSuperTypes, allTypes.keySet())
}
}
fun Appendable.renderBuilderFunction(dictionary: GenerateTraitOrClass, allSuperTypes: List<GenerateTraitOrClass>, allTypes: Set<String>) {
val fields = (dictionary.memberAttributes + allSuperTypes.flatMap { it.memberAttributes }).distinctBy { it.signature }.map { it.copy(kind = AttributeKind.ARGUMENT) }.dynamicIfUnknownType(allTypes)
append("inline fun ${dictionary.name}")
renderArgumentsDeclaration(fields)
appendln(": ${dictionary.name} {")
indent(level = 1)
appendln("val o = js(\"({})\") as ${dictionary.name}")
appendln()
for (field in fields) {
indent(level = 1)
appendln("o.`${field.name}` = ${field.name.replaceKeywords()}")
}
appendln()
indent(level = 1)
appendln("return o")
appendln("}")
appendln()
}
fun betterFunction(f1: GenerateFunction, f2: GenerateFunction): GenerateFunction =