blob: 313a10f3215c63ec1aeb8d8fc8687358b71b6fd1 [file] [log] [blame]
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.generators.builtins.numbers.primitives
import java.io.File
private fun String.shift(): String {
return this.split(END_LINE).joinToString(separator = END_LINE) { if (it.isEmpty()) it else " $it" }
}
internal fun file(init: FileBuilder.() -> Unit): FileBuilder {
val file = FileBuilder()
file.init()
return file
}
internal interface PrimitiveBuilder {
fun build(): String
fun throwIfAlreadyInitialized(arg: Any?, propertyName: String, className: String) {
if (arg != null) {
throw AssertionError("Property '$propertyName' for '$className' was already initialized")
}
}
fun throwIfWasNotInitialized(arg: Any?, propertyName: String, className: String) {
if (arg == null) {
throw AssertionError("Property '$propertyName' for '$className' wasn't set to its value")
}
}
fun throwNotInitialized(propertyName: String, className: String): Nothing {
throw AssertionError("Property '$propertyName' for '$className' wasn't initialized to access")
}
}
internal abstract class AnnotatedAndDocumented {
private var doc: String? = null
val annotations: MutableList<String> = mutableListOf()
var additionalDoc: String? = null
fun appendDoc(doc: String) {
if (this.doc == null) {
this.doc = doc
} else {
this.doc += "$END_LINE$doc"
}
}
protected fun StringBuilder.printDocumentationAndAnnotations(forceMultiLineDoc: Boolean = false) {
if (doc != null) {
appendLine(doc!!.printAsDoc(forceMultiLineDoc))
}
if (annotations.isNotEmpty()) {
appendLine(annotations.joinToString(separator = END_LINE) { "@$it" })
}
if (additionalDoc != null) {
appendLine("// $additionalDoc")
}
}
private fun String.printAsDoc(forceMultiLine: Boolean = false): String {
if (this.contains(END_LINE) || forceMultiLine) {
return this.split(END_LINE).joinToString(
separator = END_LINE, prefix = "/**$END_LINE", postfix = "$END_LINE */"
) { if (it.isEmpty()) " *" else " * $it" }
}
return "/** $this */"
}
}
internal class FileBuilder : PrimitiveBuilder {
private val suppresses: MutableList<String> = mutableListOf()
private val imports: MutableList<String> = mutableListOf()
private val classes: MutableList<ClassBuilder> = mutableListOf()
fun suppress(suppress: String) {
suppresses += suppress
}
fun import(newImport: String) {
imports += newImport
}
fun klass(init: ClassBuilder.() -> Unit): ClassBuilder {
val classBuilder = ClassBuilder()
classes += classBuilder.apply(init)
return classBuilder
}
override fun build(): String {
return buildString {
appendLine(File("license/COPYRIGHT_HEADER.txt").readText())
appendLine()
appendLine("// Auto-generated file. DO NOT EDIT!")
appendLine()
if (suppresses.isNotEmpty()) {
appendLine(suppresses.joinToString(separator = ", ", prefix = "@file:Suppress(", postfix = ")") { "\"$it\"" })
appendLine()
}
appendLine("package kotlin")
appendLine()
if (imports.isNotEmpty()) {
appendLine(imports.joinToString(separator = END_LINE) { "import $it" })
appendLine()
}
append(classes.joinToString(separator = END_LINE) { it.build() })
}
}
}
internal class ClassBuilder : AnnotatedAndDocumented(), PrimitiveBuilder {
var isFinal: Boolean = false
var name: String = ""
private var constructorParam: MethodParameterBuilder? = null
private var companionObject: CompanionObjectBuilder? = null
private val methods: MutableList<MethodBuilder> = mutableListOf()
fun constructorParam(init: MethodParameterBuilder.() -> Unit) {
throwIfAlreadyInitialized(constructorParam, "constructorParam", "ClassBuilder")
constructorParam = MethodParameterBuilder().apply(init)
}
fun companionObject(init: CompanionObjectBuilder.() -> Unit): CompanionObjectBuilder {
throwIfAlreadyInitialized(companionObject, "companionObject", "ClassBuilder")
val companionObjectBuilder = CompanionObjectBuilder()
companionObject = companionObjectBuilder.apply(init)
return companionObjectBuilder
}
fun method(init: MethodBuilder.() -> Unit): MethodBuilder {
val methodBuilder = MethodBuilder()
methods += methodBuilder.apply(init)
return methodBuilder
}
override fun build(): String {
return buildString {
this.printDocumentationAndAnnotations()
append("public ")
if (isFinal) append("final ")
appendLine("class $name private constructor(${constructorParam?.build() ?: ""}) : Number(), Comparable<$name> {")
companionObject?.let { appendLine(it.build().shift()) }
appendLine(methods.joinToString(separator = END_LINE + END_LINE) { it.build().shift() })
appendLine("}")
}
}
}
internal class CompanionObjectBuilder : AnnotatedAndDocumented(), PrimitiveBuilder {
var isPublic: Boolean = false
private val properties: MutableList<PropertyBuilder> = mutableListOf()
fun property(init: PropertyBuilder.() -> Unit): PropertyBuilder {
val propertyBuilder = PropertyBuilder()
properties += propertyBuilder.apply(init)
return propertyBuilder
}
override fun build(): String {
return buildString {
printDocumentationAndAnnotations()
if (isPublic) append("public ")
appendLine("companion object {")
appendLine(properties.joinToString(separator = END_LINE + END_LINE) { it.build().shift() })
appendLine("}")
}
}
}
internal class MethodSignatureBuilder : PrimitiveBuilder {
var isExternal: Boolean = false
var visibility: MethodVisibility = MethodVisibility.PUBLIC
var isOverride: Boolean = false
var isInline: Boolean = false
var isInfix: Boolean = false
var isOperator: Boolean = false
var methodName: String? = null
private var parameter: MethodParameterBuilder? = null
var returnType: String? = null
val parameterName: String
get() = parameter?.name ?: throwNotInitialized("name", "MethodParameterBuilder")
val parameterType: String
get() = parameter?.type ?: throwNotInitialized("type", "MethodParameterBuilder")
fun parameter(init: MethodParameterBuilder.() -> Unit): MethodParameterBuilder {
throwIfAlreadyInitialized(parameter, "parameter", "MethodSignatureBuilder")
val argBuilder = MethodParameterBuilder()
parameter = argBuilder.apply(init)
return argBuilder
}
override fun build(): String {
throwIfWasNotInitialized(methodName, "methodName", "MethodSignatureBuilder")
throwIfWasNotInitialized(returnType, "returnType", "MethodSignatureBuilder")
return buildString {
if (isExternal) append("external ")
append("${visibility.name.lowercase()} ")
if (isOverride) append("override ")
if (isInline) append("inline ")
if (isInfix) append("infix ")
if (isOperator) append("operator ")
append("fun $methodName(${parameter?.build() ?: ""}): $returnType")
}
}
}
internal enum class MethodVisibility {
PUBLIC, INTERNAL, PRIVATE
}
internal class MethodParameterBuilder : PrimitiveBuilder {
var name: String? = null
var type: String? = null
override fun build(): String {
throwIfWasNotInitialized(name, "name", "MethodParameterBuilder")
throwIfWasNotInitialized(type, "type", "MethodParameterBuilder")
return "$name: $type"
}
}
internal class MethodBuilder : AnnotatedAndDocumented(), PrimitiveBuilder {
private var signature: MethodSignatureBuilder? = null
private var body: String? = null
val methodName: String
get() = signature?.methodName ?: throwNotInitialized("methodName", "MethodSignatureBuilder")
val returnType: String
get() = signature?.returnType ?: throwNotInitialized("returnType", "MethodSignatureBuilder")
val parameterName: String
get() = signature?.parameterName ?: throwNotInitialized("name", "MethodParameterBuilder")
val parameterType: String
get() = signature?.parameterType ?: throwNotInitialized("type", "MethodParameterBuilder")
fun signature(init: MethodSignatureBuilder.() -> Unit): MethodSignatureBuilder {
throwIfAlreadyInitialized(signature, "signature", "MethodBuilder")
val signatureBuilder = MethodSignatureBuilder()
signature = signatureBuilder.apply(init)
return signatureBuilder
}
fun modifySignature(modify: MethodSignatureBuilder.() -> Unit) {
throwIfWasNotInitialized(signature, "signature", "MethodBuilder")
signature!!.apply(modify)
}
override fun build(): String {
throwIfWasNotInitialized(signature, "signature", "MethodBuilder")
return buildString {
printDocumentationAndAnnotations()
append(signature!!.build())
append(body ?: "")
}
}
fun String.addAsSingleLineBody(bodyOnNewLine: Boolean = false) {
val skip = if (bodyOnNewLine) "$END_LINE " else " "
body = " =$skip$this"
}
fun String.addAsMultiLineBody() {
body = " {$END_LINE${this.shift()}$END_LINE}"
}
}
internal class PropertyBuilder : AnnotatedAndDocumented(), PrimitiveBuilder {
var name: String? = null
var type: String? = null
var value: String? = null
override fun build(): String {
throwIfWasNotInitialized(name, "name", "PropertyBuilder")
throwIfWasNotInitialized(type, "type", "PropertyBuilder")
throwIfWasNotInitialized(value, "value", "PropertyBuilder")
return buildString {
printDocumentationAndAnnotations(forceMultiLineDoc = true)
append("public const val $name: $type = $value")
}
}
}