Refactor stdlib generator engine.
Introduce special class to hold generic function properties.
This commit is contained in:
@@ -37,98 +37,61 @@ enum class PrimitiveType(val name: String) {
|
|||||||
|
|
||||||
|
|
||||||
class GenericFunction(val signature: String, val keyword: String = "fun") : Comparable<GenericFunction> {
|
class GenericFunction(val signature: String, val keyword: String = "fun") : Comparable<GenericFunction> {
|
||||||
|
|
||||||
|
open class SpecializedProperty<TKey: Any, TValue : Any>() {
|
||||||
|
private val values = HashMap<TKey?, TValue>()
|
||||||
|
|
||||||
|
fun get(key: TKey): TValue? = values.getOrElse(key, { values.getOrElse(null, { null }) })
|
||||||
|
|
||||||
|
fun set(keys: Collection<TKey>, value: TValue) {
|
||||||
|
if (keys.isEmpty())
|
||||||
|
values[null] = value;
|
||||||
|
else
|
||||||
|
for (key in keys) {
|
||||||
|
values[key] = value
|
||||||
|
onKeySet(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun invoke(vararg keys: TKey, valueBuilder: ()-> TValue) = set(keys.asList(), valueBuilder())
|
||||||
|
fun invoke(value: TValue, vararg keys: TKey) = set(keys.asList(), value)
|
||||||
|
|
||||||
|
protected open fun onKeySet(key: TKey) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class FamilyProperty<TValue: Any>() : SpecializedProperty<Family, TValue>()
|
||||||
|
open class PrimitiveProperty<TValue: Any>() : SpecializedProperty<PrimitiveType, TValue>()
|
||||||
|
|
||||||
|
|
||||||
val defaultFamilies = array(Iterables, Sequences, ArraysOfObjects, ArraysOfPrimitives, Strings)
|
val defaultFamilies = array(Iterables, Sequences, ArraysOfObjects, ArraysOfPrimitives, Strings)
|
||||||
val defaultPrimitives = PrimitiveType.values()
|
val defaultPrimitives = PrimitiveType.values()
|
||||||
val numericPrimitives = array(PrimitiveType.Int, PrimitiveType.Long, PrimitiveType.Byte, PrimitiveType.Short, PrimitiveType.Double, PrimitiveType.Float)
|
val numericPrimitives = array(PrimitiveType.Int, PrimitiveType.Long, PrimitiveType.Byte, PrimitiveType.Short, PrimitiveType.Double, PrimitiveType.Float)
|
||||||
|
|
||||||
var toNullableT: Boolean = false
|
var toNullableT: Boolean = false
|
||||||
|
|
||||||
var defaultInline = false
|
|
||||||
var receiverAsterisk = false
|
var receiverAsterisk = false
|
||||||
val inlineFamilies = HashMap<Family, Boolean>()
|
|
||||||
|
|
||||||
val buildFamilies = LinkedHashSet(defaultFamilies.toList())
|
val buildFamilies = LinkedHashSet(defaultFamilies.toList())
|
||||||
val buildPrimitives = LinkedHashSet(defaultPrimitives.toList())
|
val buildPrimitives = LinkedHashSet(defaultPrimitives.toList())
|
||||||
|
|
||||||
var deprecate: String = ""
|
val deprecate = FamilyProperty<String>()
|
||||||
val deprecates = hashMapOf<Family, String>()
|
val doc = FamilyProperty<String>()
|
||||||
|
val platformName = PrimitiveProperty<String>()
|
||||||
var doc: String = ""
|
val inline = FamilyProperty<Boolean>()
|
||||||
val docs = HashMap<Family, String>()
|
|
||||||
|
|
||||||
var platformName: String? = null
|
|
||||||
val platformNames = hashMapOf<PrimitiveType, String>()
|
|
||||||
|
|
||||||
var defaultBody: String = ""
|
|
||||||
val bodies = HashMap<Family, String>()
|
|
||||||
val customPrimitiveBodies = HashMap<Pair<Family, PrimitiveType>, String>()
|
|
||||||
|
|
||||||
var defaultReturnType = ""
|
|
||||||
val returnTypes = HashMap<Family, String>()
|
|
||||||
|
|
||||||
val typeParams = ArrayList<String>()
|
val typeParams = ArrayList<String>()
|
||||||
|
val returns = FamilyProperty<String>()
|
||||||
fun body(vararg families: Family, b: () -> String) {
|
val body = object : FamilyProperty<String>() {
|
||||||
if (families.isEmpty())
|
override fun onKeySet(key: Family) = include(key)
|
||||||
defaultBody = b()
|
|
||||||
else {
|
|
||||||
for (f in families) {
|
|
||||||
include(f)
|
|
||||||
bodies[f] = b()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
val customPrimitiveBodies = HashMap<Pair<Family, PrimitiveType>, String>()
|
||||||
|
|
||||||
fun bodyForTypes(family: Family, vararg primitiveTypes: PrimitiveType, b: () -> String) {
|
fun bodyForTypes(family: Family, vararg primitiveTypes: PrimitiveType, b: () -> String) {
|
||||||
include(family)
|
include(family)
|
||||||
for (f in primitiveTypes) {
|
for (primitive in primitiveTypes) {
|
||||||
customPrimitiveBodies.put(family to f, b())
|
customPrimitiveBodies.put(family to primitive, b())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun doc(vararg families: Family, b: () -> String) {
|
|
||||||
if (families.isEmpty())
|
|
||||||
doc = b()
|
|
||||||
else {
|
|
||||||
for (f in families) {
|
|
||||||
docs[f] = b()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun deprecate(vararg families: Family, b: () -> String) {
|
|
||||||
if (families.isEmpty())
|
|
||||||
deprecate = b()
|
|
||||||
else {
|
|
||||||
for (f in families) {
|
|
||||||
deprecates[f] = b()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun platformName(name: String, vararg primitives: PrimitiveType) {
|
|
||||||
if (primitives.isEmpty())
|
|
||||||
platformName = name
|
|
||||||
else
|
|
||||||
for (primitive in primitives) {
|
|
||||||
platformNames[primitive] = name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun returns(vararg families: Family, b: () -> String) {
|
|
||||||
if (families.isEmpty())
|
|
||||||
defaultReturnType = b()
|
|
||||||
else {
|
|
||||||
for (f in families) {
|
|
||||||
returnTypes[f] = b()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun returns(r: String) {
|
|
||||||
defaultReturnType = r
|
|
||||||
}
|
|
||||||
|
|
||||||
fun typeParam(t: String) {
|
fun typeParam(t: String) {
|
||||||
typeParams.add(t)
|
typeParams.add(t)
|
||||||
}
|
}
|
||||||
@@ -137,14 +100,6 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
|||||||
receiverAsterisk = v
|
receiverAsterisk = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fun inline(value: Boolean, vararg families: Family) {
|
|
||||||
if (families.isEmpty())
|
|
||||||
defaultInline = value
|
|
||||||
else
|
|
||||||
for (f in families)
|
|
||||||
inlineFamilies.put(f, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun exclude(vararg families: Family) {
|
fun exclude(vararg families: Family) {
|
||||||
buildFamilies.removeAll(families.toList())
|
buildFamilies.removeAll(families.toList())
|
||||||
}
|
}
|
||||||
@@ -197,7 +152,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
|||||||
}.toString()
|
}.toString()
|
||||||
builder.append(text)
|
builder.append(text)
|
||||||
builder.appendln()
|
builder.appendln()
|
||||||
if (deprecates[f] == null && deprecate.isEmpty())
|
if (deprecate[f] == null) // (deprecates[f] == null && deprecate.isEmpty())
|
||||||
builder.appendln("deprecated(\"Migrate to using Sequence<T> and respective functions\")")
|
builder.appendln("deprecated(\"Migrate to using Sequence<T> and respective functions\")")
|
||||||
val streamText = text
|
val streamText = text
|
||||||
.replace("Sequence", "Stream")
|
.replace("Sequence", "Stream")
|
||||||
@@ -209,9 +164,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun doBuild(builder: StringBuilder, f: Family, primitive: PrimitiveType?) {
|
fun doBuild(builder: StringBuilder, f: Family, primitive: PrimitiveType?) {
|
||||||
val returnType = returnTypes[f] ?: defaultReturnType
|
val returnType = returns[f] ?: throw RuntimeException("No return type specified for $signature")
|
||||||
if (returnType.isEmpty())
|
|
||||||
throw RuntimeException("No return type specified for $signature")
|
|
||||||
|
|
||||||
val isAsteriskOrT = if (receiverAsterisk) "*" else "T"
|
val isAsteriskOrT = if (receiverAsterisk) "*" else "T"
|
||||||
val receiver = when (f) {
|
val receiver = when (f) {
|
||||||
@@ -321,8 +274,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val methodDoc = docs[f] ?: doc
|
doc[f]?.let { methodDoc ->
|
||||||
if (methodDoc != "") {
|
|
||||||
builder.append("/**\n")
|
builder.append("/**\n")
|
||||||
StringReader(methodDoc).forEachLine {
|
StringReader(methodDoc).forEachLine {
|
||||||
val line = it.trim()
|
val line = it.trim()
|
||||||
@@ -332,19 +284,19 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
|||||||
}
|
}
|
||||||
builder.append(" */\n")
|
builder.append(" */\n")
|
||||||
}
|
}
|
||||||
val deprecated = deprecates[f] ?: deprecate
|
|
||||||
if (deprecated != "") {
|
deprecate[f]?.let { deprecated ->
|
||||||
builder.append("deprecated(\"$deprecated\")\n")
|
builder.append("deprecated(\"$deprecated\")\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!f.isPrimitiveSpecialization && primitive != null) {
|
if (!f.isPrimitiveSpecialization && primitive != null) {
|
||||||
val platformName = (platformNames[primitive] ?: platformName) ?.let { it.replace("<T>", primitive.name)}
|
platformName[primitive]
|
||||||
if (platformName != null)
|
?.replace("<T>", primitive.name)
|
||||||
builder.append("platformName(\"${platformName}\")\n")
|
?.let { platformName -> builder.append("platformName(\"${platformName}\")\n")}
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.append("public ")
|
builder.append("public ")
|
||||||
if (inlineFamilies[f] ?: defaultInline)
|
if (inline[f] == true)
|
||||||
builder.append("inline ")
|
builder.append("inline ")
|
||||||
|
|
||||||
builder.append("$keyword ")
|
builder.append("$keyword ")
|
||||||
@@ -364,14 +316,14 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
|||||||
builder.append(".${signature.renderType()}: ${returnType.renderType()}")
|
builder.append(".${signature.renderType()}: ${returnType.renderType()}")
|
||||||
if (keyword == "fun") builder.append(" {")
|
if (keyword == "fun") builder.append(" {")
|
||||||
|
|
||||||
val body = (customPrimitiveBodies[f to primitive] ?: bodies[f] ?: defaultBody).trim("\n")
|
val body = (customPrimitiveBodies[f to primitive] ?: body[f] ?: throw RuntimeException("No body specified for $signature for ${f to primitive}")).trim('\n')
|
||||||
val indent: Int = body.takeWhile { it == ' ' }.length()
|
val indent: Int = body.takeWhile { it == ' ' }.length()
|
||||||
|
|
||||||
builder.append('\n')
|
builder.append('\n')
|
||||||
StringReader(body).forEachLine {
|
StringReader(body).forEachLine {
|
||||||
var count = indent
|
var count = indent
|
||||||
val line = it.dropWhile { count-- > 0 && it == ' ' }.renderType()
|
val line = it.dropWhile { count-- > 0 && it == ' ' }.renderType()
|
||||||
if (line.isNotEmpty()) {
|
if (!line.isEmpty()) {
|
||||||
builder.append(" ").append(line)
|
builder.append(" ").append(line)
|
||||||
builder.append("\n")
|
builder.append("\n")
|
||||||
}
|
}
|
||||||
@@ -383,12 +335,6 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
|
|||||||
public override fun compareTo(other: GenericFunction): Int = this.signature.compareTo(other.signature)
|
public override fun compareTo(other: GenericFunction): Int = this.signature.compareTo(other.signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.trimTrailingSpaces(): String {
|
|
||||||
var answer = this;
|
|
||||||
while (answer.endsWith(' ') || answer.endsWith('\n')) answer = answer.substring(0, answer.length() - 1)
|
|
||||||
return answer
|
|
||||||
}
|
|
||||||
|
|
||||||
fun f(signature: String, init: GenericFunction.() -> Unit): GenericFunction {
|
fun f(signature: String, init: GenericFunction.() -> Unit): GenericFunction {
|
||||||
val gf = GenericFunction(signature)
|
val gf = GenericFunction(signature)
|
||||||
gf.init()
|
gf.init()
|
||||||
|
|||||||
Reference in New Issue
Block a user