130 lines
6.5 KiB
Kotlin
130 lines
6.5 KiB
Kotlin
package io.gitlab.jfronny.scripts.codegen
|
|
|
|
class ClassGenerator(`package`: String, val name: String, val indent: String = " ") : Generator<String>() {
|
|
override fun generateFinalized() = ensureBody { gen.appendLine("}").toString() }
|
|
private val gen: StringBuilder = StringBuilder("package $`package`;\n\n")
|
|
private var headerGenerated = false
|
|
private var extends: String? = null
|
|
private val implements: MutableList<String> = ArrayList()
|
|
private var hadImport = false
|
|
|
|
private fun <T> ensureHeader(action: () -> T): T = ensureMutable {
|
|
if (headerGenerated) throw IllegalAccessException("Attempted to generate pre-header statement while in body")
|
|
action()
|
|
}
|
|
|
|
private fun <T> ensureBody(action: () -> T): T = ensureMutable {
|
|
if (!headerGenerated) {
|
|
headerGenerated = true
|
|
if (hadImport) gen.appendLine()
|
|
gen.append("public class $name")
|
|
if (extends != null) gen.append(" extends $extends")
|
|
if (implements.isNotEmpty()) gen.append(" implements ").append(implements.joinToString(", ") { it })
|
|
gen.append(" {")
|
|
gen.appendLine()
|
|
}
|
|
action()
|
|
}
|
|
|
|
fun rawHead(toWrite: String): Unit = ensureHeader { gen.appendLine(toWrite.trimIndent().trim('\n').prependIndent(indent)) }
|
|
fun rawBody(toWrite: String): Unit = ensureBody { gen.appendLine(toWrite.trimIndent().trim('\n').prependIndent(indent)) }
|
|
|
|
fun import(`import`: String): Unit = ensureHeader {
|
|
check(import, "import", importPattern)
|
|
gen.appendLine("import $import;")
|
|
hadImport = true
|
|
}
|
|
|
|
fun extends(extends: String): Unit = ensureHeader {
|
|
check(extends, "extended class", classPattern)
|
|
if (this.extends != null) throw IllegalAccessException("Attempted to extend multiple classes")
|
|
this.extends = extends
|
|
}
|
|
|
|
fun implements(implements: String): Unit = ensureHeader {
|
|
check(implements, "implemented interface", classPattern)
|
|
this.implements.add(implements)
|
|
}
|
|
|
|
fun fieldRaw(name: String, type: String, valueRaw: String, modifiers: String = defaultModifiers): Unit = ensureBody {
|
|
check(name, "field", classEntryPattern)
|
|
check(type, "field type", classPattern)
|
|
check(modifiers, "set of modifiers", modifierPattern)
|
|
gen.appendLine("$indent$modifiers $type $name = $valueRaw;")
|
|
}
|
|
|
|
fun field(name: String, value: Boolean, modifiers: String = defaultModifiers) = fieldRaw(name, "boolean", value.toString(), modifiers)
|
|
fun field(name: String, value: Short, modifiers: String = defaultModifiers) = fieldRaw(name, "short", value.toString(), modifiers)
|
|
fun field(name: String, value: Int, modifiers: String = defaultModifiers) = fieldRaw(name, "int", value.toString(), modifiers)
|
|
fun field(name: String, value: Long, modifiers: String = defaultModifiers) = fieldRaw(name, "long", value.toString(), modifiers)
|
|
fun field(name: String, value: Float, modifiers: String = defaultModifiers) = fieldRaw(name, "float", value.toString() + "f", modifiers)
|
|
fun field(name: String, value: Double, modifiers: String = defaultModifiers) = fieldRaw(name, "double", value.toString(), modifiers)
|
|
fun field(name: String, value: String, modifiers: String = defaultModifiers) = fieldRaw(name, "String", enquote(value), modifiers)
|
|
|
|
fun procedure(name: String, argument: Map<String, String>, modifiers: String = defaultModifiers, body: String, throws: String? = null): Unit = ensureBody {
|
|
check(name, "procedure", classEntryPattern)
|
|
if (argument.any { !classEntryPattern.matches(it.key) || !classPattern.matches(it.value) }) throw IllegalArgumentException("invalid argument on procedure")
|
|
check(modifiers, "set of modifiers", modifierPattern)
|
|
ensureBrackets(body)
|
|
if (throws != null) check(throws, "thrown exceptions list", classListPattern)
|
|
gen.append(indent)
|
|
gen.append(modifiers)
|
|
gen.append(" void ")
|
|
gen.append(name)
|
|
gen.append("(")
|
|
gen.append(argument.entries.joinToString(", ") { "${it.key} ${it.value}" })
|
|
gen.append(") ")
|
|
if (throws != null) gen.append(throws).append(' ')
|
|
gen.append('{')
|
|
gen.appendLine()
|
|
gen.appendLine(body.trimIndent().prependIndent("$indent "))
|
|
gen.appendLine("$indent}")
|
|
}
|
|
|
|
fun function(name: String, returnType: String, argument: Map<String, String>, modifiers: String = defaultModifiers, body: String, throws: String? = null): Unit = ensureBody {
|
|
check(name, "procedure", classEntryPattern)
|
|
check(returnType, "return type", classPattern)
|
|
if (argument.any { !classEntryPattern.matches(it.key) || !classPattern.matches(it.value) }) throw IllegalArgumentException("invalid argument on procedure")
|
|
check(modifiers, "set of modifiers", modifierPattern)
|
|
ensureBrackets(body)
|
|
if (throws != null) check(throws, "thrown exceptions list", classListPattern)
|
|
gen.append(indent)
|
|
gen.append(modifiers)
|
|
gen.append(" $returnType ")
|
|
gen.append(name)
|
|
gen.append("(")
|
|
gen.append(argument.entries.joinToString(", ") { "${it.key} ${it.value}" })
|
|
gen.append(") ")
|
|
if (throws != null) gen.append(throws).append(' ')
|
|
gen.append('{')
|
|
gen.appendLine()
|
|
gen.appendLine(body.trimIndent().prependIndent("$indent "))
|
|
gen.appendLine("$indent}")
|
|
}
|
|
|
|
companion object {
|
|
@JvmStatic private val defaultModifiers = "public static"
|
|
@JvmStatic private fun enquote(value: String): String = "\"${value.replace("\\", "\\\\").replace("\"", "\\\"")}\""
|
|
@JvmStatic private fun ensureBrackets(value: String): Unit {
|
|
var state = 0 // 0 -> outside of anything, 1 -> inside string, 2 -> inside block quote
|
|
var brackets = 0
|
|
value.forEachIndexed { i, c ->
|
|
when (state) {
|
|
0 -> {
|
|
if (c == '"') state = if (i + 2 < value.length && value[i+1] == '"' && value[i+2] == '"') 2 else 1
|
|
if (c == '{') brackets++
|
|
if (c == '}') brackets--
|
|
}
|
|
1 -> {
|
|
if (c == '"') state = 0
|
|
}
|
|
2 -> {
|
|
if (c == '"' && i + 2 < value.length && value[i+1] == '"' && value[i+2] == '"') state = 0
|
|
}
|
|
}
|
|
}
|
|
if (brackets != 0) throw IllegalArgumentException("Unclosed brackets in method body")
|
|
}
|
|
}
|
|
}
|