From f9a4b8f9cb2b6103786165aff66552bbe24636f1 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 30 Jan 2020 14:37:23 +0300 Subject: [PATCH] [FIR] Split printer in tree generator to several files Also use smart printer instead of `PrintWriter` --- .../kotlin/fir/tree/generator/Main.kt | 2 + .../kotlin/fir/tree/generator/Printer.kt | 814 ------------------ .../context/AbstractFirTreeBuilder.kt | 2 +- ...stractFirTreeImplementationConfigurator.kt | 2 +- .../fir/tree/generator/model/Element.kt | 4 +- .../fir/tree/generator/model/ElementUtils.kt | 2 +- .../kotlin/fir/tree/generator/model/Field.kt | 2 +- .../tree/generator/printer/SmartPrinter.kt | 51 ++ .../fir/tree/generator/printer/element.kt | 132 +++ .../fir/tree/generator/printer/field.kt | 61 ++ .../tree/generator/printer/implementation.kt | 329 +++++++ .../kotlin/fir/tree/generator/printer/main.kt | 46 + .../fir/tree/generator/printer/transformer.kt | 65 ++ .../fir/tree/generator/printer/utils.kt | 131 +++ .../fir/tree/generator/printer/visitor.kt | 86 ++ 15 files changed, 909 insertions(+), 820 deletions(-) delete mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Printer.kt create mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/SmartPrinter.kt create mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt create mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt create mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt create mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/main.kt create mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/transformer.kt create mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt create mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/visitor.kt diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt index 36669dce018..25d15dc82a4 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt @@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.tree.generator import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder import org.jetbrains.kotlin.fir.tree.generator.model.* +import org.jetbrains.kotlin.fir.tree.generator.printer.GENERATED_MESSAGE +import org.jetbrains.kotlin.fir.tree.generator.printer.printElements import java.io.File diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Printer.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Printer.kt deleted file mode 100644 index 3b9408beb0f..00000000000 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Printer.kt +++ /dev/null @@ -1,814 +0,0 @@ -/* - * Copyright 2010-2019 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.fir.tree.generator - -import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder -import org.jetbrains.kotlin.fir.tree.generator.model.* -import java.io.File -import java.io.PrintWriter -import java.util.* -import kotlin.math.abs - -val COPYRIGHT = """ -/* - * Copyright 2010-${GregorianCalendar()[Calendar.YEAR]} 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. - */ -""".trimIndent() - -const val BASE_PACKAGE = "org.jetbrains.kotlin.fir" -//const val BASE_PATH = "compiler/fir/tree/src/" -private const val VISITOR_PACKAGE = "org.jetbrains.kotlin.fir.visitors" -private const val INDENT = " " -val GENERATED_MESSAGE = """ - /* - * This file was generated automatically - * DO NOT MODIFY IT MANUALLY - */ - """.trimIndent() - -fun printElements(builder: AbstractFirTreeBuilder, generationPath: File) { - builder.elements.forEach { it.generateCode(generationPath) } - builder.elements.flatMap { it.allImplementations }.forEach { it.generateCode(generationPath) } - - printVisitor(builder.elements, generationPath) - printVisitorVoid(builder.elements, generationPath) - printTransformer(builder.elements, generationPath) -} - -fun PrintWriter.printCopyright() { - println(COPYRIGHT) - println() -} - -fun PrintWriter.printGeneratedMessage() { - println(GENERATED_MESSAGE) - println() -} - -fun printVisitor(elements: List, generationPath: File) { - val dir = File(generationPath, VISITOR_PACKAGE.replace(".", "/")) - dir.mkdirs() - File(dir, "FirVisitor.kt").printWriter().use { printer -> - with(printer) { - printCopyright() - println("package $VISITOR_PACKAGE") - println() - elements.forEach { println("import ${it.fullQualifiedName}") } - println() - printGeneratedMessage() - - println("abstract class FirVisitor {") - - indent() - println("abstract fun visitElement(element: FirElement, data: D): R") - println() - for (element in elements) { - if (element == AbstractFirTreeBuilder.baseFirElement) continue - with(element) { - indent() - val varName = safeDecapitalizedName - println("open fun ${typeParameters}visit$name($varName: $typeWithArguments, data: D): R${multipleUpperBoundsList()} = visitElement($varName, data)") - println() - } - } - println("}") - } - } -} - -fun printVisitorVoid(elements: List, generationPath: File) { - val dir = File(generationPath, VISITOR_PACKAGE.replace(".", "/")) - dir.mkdirs() - File(dir, "FirVisitorVoid.kt").printWriter().use { printer -> - with(printer) { - printCopyright() - println("package $VISITOR_PACKAGE") - println() - elements.forEach { println("import ${it.fullQualifiedName}") } - println() - printGeneratedMessage() - - println("abstract class FirVisitorVoid : FirVisitor() {") - - indent() - println("abstract fun visitElement(element: FirElement)") - println() - for (element in elements) { - if (element == AbstractFirTreeBuilder.baseFirElement) continue - with(element) { - indent() - val varName = safeDecapitalizedName - println("open fun ${typeParameters}visit$name($varName: $typeWithArguments)${multipleUpperBoundsList()}{") - indent(2) - println("visitElement($varName)") - indent() - println("}") - println() - } - } - - for (element in elements) { - with(element) { - indent() - val varName = safeDecapitalizedName - println("final override fun ${typeParameters}visit$name($varName: $typeWithArguments, data: Nothing?)${multipleUpperBoundsList()}{") - indent(2) - println("visit$name($varName)") - indent() - println("}") - println() - } - } - println("}") - } - } -} - -fun Element.generateCode(generationPath: File) { - val dir = generationPath.resolve(packageName.replace(".", "/")) - dir.mkdirs() - val file = File(dir, "$type.kt") - file.printWriter().use { printer -> - with(printer) { - printCopyright() - println("package $packageName") - println() - val imports = collectImports() - imports.forEach { println("import $it") } - if (imports.isNotEmpty()) { - println() - } - printGeneratedMessage() - printElement(this@generateCode) - } - } -} - -fun Implementation.generateCode(generationPath: File) { - val dir = generationPath.resolve(packageName.replace(".", "/")) - dir.mkdirs() - val file = File(dir, "$type.kt") - file.printWriter().use { printer -> - with(printer) { - printCopyright() - println("package $packageName") - println() - val imports = collectImports() - imports.forEach { println("import $it") } - if (imports.isNotEmpty()) { - println() - } - printGeneratedMessage() - printImplementation(this@generateCode) - } - } -} - -val KindOwner.needPureAbstractElement: Boolean get() = (kind != Implementation.Kind.Interface) && !allParents.any { it.kind == Implementation.Kind.AbstractClass } - -fun Implementation.collectImports(): List { - return element.collectImportsInternal( - listOf( - element.fullQualifiedName) - + usedTypes.mapNotNull { it.fullQualifiedName } + parents.mapNotNull { it.fullQualifiedName } - + listOfNotNull(pureAbstractElementType.fullQualifiedName?.takeIf { needPureAbstractElement } - ), - isImpl = true - ) -} - -fun Element.collectImports(): List { - val baseTypes = parents.mapTo(mutableListOf()) { it.fullQualifiedName } - baseTypes += parentsArguments.values.flatMap { it.values }.mapNotNull { it.fullQualifiedName } - val isBaseFirElement = this == AbstractFirTreeBuilder.baseFirElement - if (isBaseFirElement) { - baseTypes += compositeTransformResultType.fullQualifiedName!! - } - if (needPureAbstractElement) { - baseTypes += pureAbstractElementType.fullQualifiedName!! - } - return collectImportsInternal( - baseTypes, - isImpl = false - ) -} - -fun Element.collectImportsInternal(base: List, isImpl: Boolean): List { - val fqns = base + allFields.mapNotNull { it.fullQualifiedName } + - allFields.flatMap { it.arguments.mapNotNull { it.fullQualifiedName } } + - typeArguments.flatMap { it.upperBounds.mapNotNull { it.fullQualifiedName } } - val realPackageName = if (isImpl) "$packageName.impl." else "$packageName." - return fqns.filter { fqn -> - fqn.dropLastWhile { it != '.' } != realPackageName - }.distinct().sorted() + "$VISITOR_PACKAGE.*" -} - -val Field.isVal: Boolean get() = this is FieldList || (this is FieldWithDefault && origin is FieldList) || !isMutable - -fun PrintWriter.printFieldWithDefaultInImplementation(field: Field) { - val defaultValue = field.defaultValue - indent() - print("override ") - if (field.isLateinit) { - print("lateinit ") - } - if (field.isVal) { - print("val") - } else { - print("var") - } - print(" ${field.name}: ${field.mutableType}") - if (field.isLateinit) { - println() - return - } else { - print(" ") - } - if (field.withGetter) { - if (field.customSetter != null) { - println() - indent(2) - } - print("get() ") - } - requireNotNull(defaultValue) { - "No default value for $field" - } - println("= $defaultValue") - field.customSetter?.let { - indent(2) - println("set(value) {") - indent(3) - println(it) - indent(2) - println("}") - } -} - -fun PrintWriter.printImplementation(implementation: Implementation) { - fun Field.transform() { - when (this) { - is FieldWithDefault -> origin.transform() - - is FirField -> - println("$name = ${name}${call()}transformSingle(transformer, data)") - - is FieldList -> { - println("${name}.transformInplace(transformer, data)") - } - - else -> throw IllegalStateException() - } - } - - with(implementation) { - print("${kind!!.title} $type") - print(element.typeParameters) - val fieldsWithoutDefault = allFields.filter { it.defaultValue == null && !it.isLateinit } - val fieldsWithDefault = allFields.filter { it.defaultValue != null || it.isLateinit } - - val isInterface = kind == Implementation.Kind.Interface - val isAbstract = kind == Implementation.Kind.AbstractClass - - fun abstract() { - if (isAbstract) { - print("abstract ") - } - } - - if (!isInterface && !isAbstract && fieldsWithoutDefault.isNotEmpty()) { - println("(") - fieldsWithoutDefault.forEachIndexed { i, field -> - val end = if (i == fieldsWithoutDefault.size - 1) "" else "," - printField(field, isImplementation = true, override = true, end = end, withIndent = true) - } - print(")") - } - - print(" : ") - if (!isInterface && !allParents.any { it.kind == Implementation.Kind.AbstractClass }) { - print("${pureAbstractElementType.type}(), ") - } -// print(element.typeWithArguments) - print(allParents.joinToString { "${it.typeWithArguments}${it.kind.braces()}" }) - println(" {") - - if (isInterface || isAbstract) { - allFields.forEach { - indent() - abstract() - printField(it, isImplementation = true, override = true, end = "", withIndent = false) - } - } else { - fieldsWithDefault.forEach { - printFieldWithDefaultInImplementation(it) - } - if (fieldsWithDefault.isNotEmpty()) { - println() - } - } - - element.allFields.filter { it.type.contains("Symbol") && it !is FieldList } - .takeIf { it.isNotEmpty() && !isInterface && !isAbstract && !element.type.contains("Reference")} - ?.let { symbolFields -> - indent(1) - println("init {") - for (symbolField in symbolFields) { - indent(2) - println("${symbolField.name}${symbolField.call()}bind(this)") - } - indent(1) - println("}") - println() - } - - fun Field.acceptString(): String = "${name}${call()}accept(visitor, data)" - if (!isInterface && !isAbstract) { - - indent(1) - print("override fun acceptChildren(visitor: FirVisitor, data: D) {") - - - if (element.allFirFields.isNotEmpty()) { - println() - for (field in allFields.filter { it.isFirType }) { - if (field.withGetter || !field.needAcceptAndTransform) continue - when (field.name) { - "explicitReceiver" -> { - val explicitReceiver = implementation["explicitReceiver"]!! - val dispatchReceiver = implementation["dispatchReceiver"]!! - val extensionReceiver = implementation["extensionReceiver"]!! - println( - """ - | ${explicitReceiver.acceptString()} - | if (dispatchReceiver !== explicitReceiver) { - | ${dispatchReceiver.acceptString()} - | } - | if (extensionReceiver !== explicitReceiver && extensionReceiver !== dispatchReceiver) { - | ${extensionReceiver.acceptString()} - | } - """.trimMargin() - ) - } - - "dispatchReceiver", "extensionReceiver", "subjectVariable" -> { - } - "companionObject" -> { - } - - else -> { - if (type in setOf("FirClassImpl", "FirSealedClassImpl") && field.name == "declarations") { - indent(2) - println("(declarations.firstOrNull { it is FirConstructorImpl } as? FirConstructorImpl)?.typeParameters?.forEach { it.accept(visitor, data) }") - } - if (type == "FirWhenExpressionImpl" && field.name == "subject") { - println( - """ - | if (subjectVariable != null) { - | subjectVariable.accept(visitor, data) - | } else { - | subject?.accept(visitor, data) - | } - """.trimMargin() - ) - } else { - indent(2) - when (field.origin) { - is FirField -> { - println(field.acceptString()) - } - - is FieldList -> { - println("${field.name}.forEach { it.accept(visitor, data) }") - } - - else -> throw IllegalStateException() - } - } - } - - } - } - indent() - } - println("}") - println() - } - - indent() - abstract() - print("override fun transformChildren(transformer: FirTransformer, data: D): $typeWithArguments") - if (!isInterface && !isAbstract) { - println(" {") - for (field in allFields) { - when { - !field.isMutable || !field.isFirType || field.withGetter || !field.needAcceptAndTransform -> { - } - field.name == "explicitReceiver" -> { - val explicitReceiver = implementation["explicitReceiver"]!! - val dispatchReceiver = implementation["dispatchReceiver"]!! - val extensionReceiver = implementation["extensionReceiver"]!! - if (explicitReceiver.isMutable) { - indent(2) - println("explicitReceiver = explicitReceiver${explicitReceiver.call()}transformSingle(transformer, data)") - } - if (dispatchReceiver.isMutable) { - println( - """ - | if (dispatchReceiver !== explicitReceiver) { - | dispatchReceiver = dispatchReceiver.transformSingle(transformer, data) - | } - """.trimMargin() - ) - } - if (extensionReceiver.isMutable) { - println( - """ - | if (extensionReceiver !== explicitReceiver && extensionReceiver !== dispatchReceiver) { - | extensionReceiver = extensionReceiver.transformSingle(transformer, data) - | } - """.trimMargin() - ) - } - } - field.name in setOf("dispatchReceiver", "extensionReceiver") -> { - } - type in setOf("FirClassImpl", "FirSealedClassImpl") && field.name == "declarations" -> { - indent(2) - println("(declarations.firstOrNull { it is FirConstructorImpl } as? FirConstructorImpl)?.typeParameters?.transformInplace(transformer, data)") - indent(2) - println("declarations.transformInplace(transformer, data)") - } - field.name == "companionObject" -> { - indent(2) - println("companionObject = declarations.asSequence().filterIsInstance().firstOrNull { it.status.isCompanion }") - } - field.needsSeparateTransform -> { - indent(2) - println("transform${field.name.capitalize()}(transformer, data)") - } - !element.needTransformOtherChildren -> { - indent(2) - field.transform() - } - else -> { - } - } - } - if (element.needTransformOtherChildren) { - indent(2) - println("transformOtherChildren(transformer, data)") - } - indent(2) - println("return this") - indent() - println("}") - } else { - println() - } - - for (field in allFields) { - if (!field.needsSeparateTransform) continue - println() - indent() - abstract() - print("override ${field.transformFunctionDeclaration(typeWithArguments)}") - if (isInterface || isAbstract) { - println() - continue - } - println(" {") - if (field.isMutable && field.isFirType) { - // TODO: replace with smth normal - if (type == "FirWhenExpressionImpl" && field.name == "subject") { - println(""" - | if (subjectVariable != null) { - | subjectVariable = subjectVariable?.transformSingle(transformer, data) - | } else { - | subject = subject?.transformSingle(transformer, data) - | } - """.trimMargin()) - } else { - indent(2) - field.transform() - } - } - indent(2) - println("return this") - indent() - println("}") - } - - if (element.needTransformOtherChildren) { - println() - indent() - abstract() - print("override fun transformOtherChildren(transformer: FirTransformer, data: D): $typeWithArguments") - if (isInterface || isAbstract) { - println() - } else { - println(" {") - for (field in allFields) { - if (!field.isMutable || !field.isFirType || field.name == "subjectVariable") continue - if (!field.needsSeparateTransform) { - indent(2) - field.transform() - } - } - indent(2) - println("return this") - indent() - println("}") - } - } - - for (field in allFields.filter { it.withReplace }) { - println() - indent() - abstract() - print("override ${field.replaceFunctionDeclaration()}") - if (isInterface || isAbstract) { - println() - continue - } - print(" {") - if (!field.isMutable) { - println("}") - continue - } - println() - indent(2) - val newValue = "new${field.name.capitalize()}" - when { - field.withGetter -> { - } - - field.origin is FieldList -> { - println("${field.name}.clear()") - indent(2) - println("${field.name}.addAll($newValue)") - } - - else -> { - println("${field.name} = $newValue") - } - } - indent() - println("}") - } - - println("}") - } -} - -fun Field.transformFunctionDeclaration(returnType: String): String { - return transformFunctionDeclaration(name.capitalize(), returnType) -} - -fun transformFunctionDeclaration(transformName: String, returnType: String): String { - return "fun transform$transformName(transformer: FirTransformer, data: D): $returnType" -} - -fun Field.replaceFunctionDeclaration(): String { - val capName = name.capitalize() - return "fun replace$capName(new$capName: $typeWithArgumentsWithoutNullablity)" -} - -fun printTransformer(elements: List, generationPath: File) { - val dir = File(generationPath, VISITOR_PACKAGE.replace(".", "/")) - dir.mkdirs() - File(dir, "FirTransformer.kt").printWriter().use { printer -> - with(printer) { - printCopyright() - println("package $VISITOR_PACKAGE") - println() - elements.forEach { println("import ${it.fullQualifiedName}") } - println("import ${compositeTransformResultType.fullQualifiedName}") - println() - printGeneratedMessage() - - println("abstract class FirTransformer : FirVisitor, D>() {") - println() - indent() - println("abstract fun transformElement(element: E, data: D): CompositeTransformResult") - println() - for (element in elements) { - if (element == AbstractFirTreeBuilder.baseFirElement) continue - indent() - val varName = element.safeDecapitalizedName - print("open fun ") - element.typeParameters.takeIf { it.isNotBlank() }?.let { print(it) } - println("transform${element.name}($varName: ${element.typeWithArguments}, data: D): CompositeTransformResult<${element.transformerType.typeWithArguments}>${element.multipleUpperBoundsList()}{") - indent(2) - println("return transformElement($varName, data)") - indent() - println("}") - println() - } - - for (element in elements) { - indent() - val varName = element.safeDecapitalizedName - print("final override fun ") - element.typeParameters.takeIf { it.isNotBlank() }?.let { print(it) } - - println("visit${element.name}($varName: ${element.typeWithArguments}, data: D): CompositeTransformResult<${element.transformerType.typeWithArguments}>${element.multipleUpperBoundsList()}{") - indent(2) - println("return transform${element.name}($varName, data)") - indent() - println("}") - println() - } - println("}") - } - } -} - -fun PrintWriter.printField(field: Field, isImplementation: Boolean, override: Boolean, end: String, withIndent: Boolean) { - if (withIndent) { - indent() - } - if (override) { - print("override ") - } - if (!isImplementation || field.isVal) { - print("val") - } else { - print("var") - } - val type = if (isImplementation) field.mutableType else field.typeWithArguments - println(" ${field.name}: $type$end") -} - -val Field.mutableType: String get() = when (this) { - is FieldList -> if (isMutable) "Mutable$typeWithArguments" else typeWithArguments - is FieldWithDefault -> if (isMutable) origin.mutableType else typeWithArguments - else -> typeWithArguments -} - -fun Field.call(): String = if (nullable) "?." else "." - -fun Element.multipleUpperBoundsList(): String { - return typeArguments.filterIsInstance().takeIf { it.isNotEmpty() }?.let { arguments -> - val upperBoundsList = arguments.joinToString(", ", postfix = " ") { argument -> - argument.upperBounds.joinToString(", ") { upperBound -> "${argument.name} : ${upperBound.typeWithArguments}" } - } - " where $upperBoundsList" - } ?: " " -} - -fun Implementation.Kind?.braces(): String = when (this) { - Implementation.Kind.Interface -> "" - Implementation.Kind.OpenClass, Implementation.Kind.AbstractClass -> "()" - else -> throw IllegalStateException(this.toString()) -} - -fun PrintWriter.printElement(element: Element) { - with(element) { - val isInterface = kind == Implementation.Kind.Interface - - fun abstract() { - indent() - if (!isInterface) { - print("abstract ") - } - } - - fun override() { - if (this != AbstractFirTreeBuilder.baseFirElement) { - print("override ") - } - } - - print("${kind!!.title} $type") - if (typeArguments.isNotEmpty()) { - print(typeArguments.joinToString(", ", "<", ">") { it.toString() }) - } - val needPureAbstractElement = !isInterface && !allParents.any { it.kind == Implementation.Kind.AbstractClass } - - if (parents.isNotEmpty() || needPureAbstractElement) { - print(" : ") - if (needPureAbstractElement) { - print("${pureAbstractElementType.type}()") - if (parents.isNotEmpty()) { - print(", ") - } - } - print(parents.joinToString(", ") { - var result = it.type - parentsArguments[it]?.let { arguments -> - result += arguments.values.joinToString(", ", "<", ">") { it.typeWithArguments } - } - result + it.kind.braces() - }) - } - print(multipleUpperBoundsList()) - println("{") - allFields.forEach { - abstract() - printField(it, isImplementation = false, override = it.fromParent, end = "", withIndent = false) - } - if (allFields.isNotEmpty()) { - println() - } - - indent() - override() - println("fun accept(visitor: FirVisitor, data: D): R = visitor.visit$name(this, data)") - - fields.filter { it.withReplace }.forEach { - println() - abstract() - if (it.fromParent) print("override ") - println(it.replaceFunctionDeclaration()) - } - - for (field in allFields) { - if (!field.needsSeparateTransform) continue - println() - abstract() - if (field.fromParent) { - print("override ") - } - println(field.transformFunctionDeclaration(typeWithArguments)) - } - if (needTransformOtherChildren) { - println() - abstract() - if (element.parents.any { it.needTransformOtherChildren }) { - print("override ") - } - println(transformFunctionDeclaration("OtherChildren", typeWithArguments)) - } - - if (element == AbstractFirTreeBuilder.baseFirElement) { - require(isInterface) - println() - indent() - println("fun accept(visitor: FirVisitorVoid) = accept(visitor, null)") - println() - indent() - println("fun acceptChildren(visitor: FirVisitor, data: D)") - println() - indent() - println("fun acceptChildren(visitor: FirVisitorVoid) = acceptChildren(visitor, null)") - println() - indent() - println("@Suppress(\"UNCHECKED_CAST\")") - indent() - println("fun transform(visitor: FirTransformer, data: D): CompositeTransformResult =") - indent(2) - println("accept(visitor, data) as CompositeTransformResult") - println() - indent() - println("fun transformChildren(transformer: FirTransformer, data: D): FirElement") - } - println("}") - } -} - -// --------------------------------------- Helpers --------------------------------------- - -fun PrintWriter.indent(n: Int = 1) { - print(INDENT.repeat(n)) -} - -val Element.safeDecapitalizedName: String get() = if (name == "Class") "klass" else name.decapitalize() - -val Importable.typeWithArguments: String - get() = when (this) { - is AbstractElement -> type + generics - is Implementation -> type + element.generics - is FirField -> element.typeWithArguments + if (nullable) "?" else "" - is Field -> type + generics + if (nullable) "?" else "" - is Type -> type + generics - is ImplementationWithArg -> type + generics - else -> throw IllegalArgumentException() - } - -val Importable.typeWithArgumentsWithoutNullablity: String get() = typeWithArguments.dropLastWhile { it == '?' } - -val ImplementationWithArg.generics: String - get() = argument?.let { "<${it.type}>" } ?: "" - -val AbstractElement.generics: String - get() = typeArguments.takeIf { it.isNotEmpty() } - ?.let { it.joinToString(", ", "<", ">") { it.name } } - ?: "" - -val Field.generics: String - get() = arguments.takeIf { it.isNotEmpty() } - ?.let { it.joinToString(", ", "<", ">") { it.typeWithArguments } } - ?: "" - -val Element.typeParameters: String - get() = typeArguments.takeIf { it.isNotEmpty() } - ?.joinToString(", ", "<", "> ") - ?: "" - -val Type.generics: String - get() = arguments.takeIf { it.isNotEmpty() }?.joinToString(",", "<", ">") ?: "" \ No newline at end of file diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeBuilder.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeBuilder.kt index 715324bd7de..e683d75abd3 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeBuilder.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeBuilder.kt @@ -5,9 +5,9 @@ package org.jetbrains.kotlin.fir.tree.generator.context -import org.jetbrains.kotlin.fir.tree.generator.BASE_PACKAGE import org.jetbrains.kotlin.fir.tree.generator.model.Element import org.jetbrains.kotlin.fir.tree.generator.model.Type +import org.jetbrains.kotlin.fir.tree.generator.printer.BASE_PACKAGE import kotlin.reflect.KClass abstract class AbstractFirTreeBuilder { diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt index c1de9b885fc..2f80b125499 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt @@ -5,9 +5,9 @@ package org.jetbrains.kotlin.fir.tree.generator.context -import org.jetbrains.kotlin.fir.tree.generator.call import org.jetbrains.kotlin.fir.tree.generator.model.* import org.jetbrains.kotlin.fir.tree.generator.noReceiverExpressionType +import org.jetbrains.kotlin.fir.tree.generator.printer.call abstract class AbstractFirTreeImplementationConfigurator { private val elementsWithImpl = mutableSetOf() diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt index e149039de05..bd8665c1b91 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt @@ -5,8 +5,8 @@ package org.jetbrains.kotlin.fir.tree.generator.model -import org.jetbrains.kotlin.fir.tree.generator.BASE_PACKAGE -import org.jetbrains.kotlin.fir.tree.generator.typeWithArguments +import org.jetbrains.kotlin.fir.tree.generator.printer.BASE_PACKAGE +import org.jetbrains.kotlin.fir.tree.generator.printer.typeWithArguments interface KindOwner : Importable { var kind: Implementation.Kind? diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/ElementUtils.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/ElementUtils.kt index 170727e049c..407cd68ac70 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/ElementUtils.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/ElementUtils.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.fir.tree.generator.model import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder import org.jetbrains.kotlin.fir.tree.generator.context.type -import org.jetbrains.kotlin.fir.tree.generator.typeWithArguments +import org.jetbrains.kotlin.fir.tree.generator.printer.typeWithArguments // ----------- Simple field ----------- diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt index 29f4d1fdd4b..389eb113ad6 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.fir.tree.generator.model -import org.jetbrains.kotlin.fir.tree.generator.typeWithArguments +import org.jetbrains.kotlin.fir.tree.generator.printer.typeWithArguments sealed class Field : Importable { abstract val name: String diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/SmartPrinter.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/SmartPrinter.kt new file mode 100644 index 00000000000..19254441427 --- /dev/null +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/SmartPrinter.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2020 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.fir.tree.generator.printer + +import java.io.File +import java.lang.Appendable + +class SmartPrinter(appendable: Appendable) { + private val printer = org.jetbrains.kotlin.utils.Printer(appendable) + + private var notFirstPrint: Boolean = false + + fun print(vararg objects: Any) { + if (notFirstPrint) { + printer.printWithNoIndent(*objects) + } else { + printer.print(*objects) + } + notFirstPrint = true + } + + fun println(vararg objects: Any) { + if (notFirstPrint) { + printer.printlnWithNoIndent(*objects) + } else { + printer.println(*objects) + } + notFirstPrint = false + } + + fun pushIndent() { + printer.pushIndent() + } + + fun popIndent() { + printer.popIndent() + } +} + +inline fun SmartPrinter.withIndent(block: () -> Unit) { + pushIndent() + block() + popIndent() +} + +inline fun File.useSmartPrinter(block: SmartPrinter.() -> Unit) { + writer().use { SmartPrinter(it).block() } +} \ No newline at end of file diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt new file mode 100644 index 00000000000..95f818c03b3 --- /dev/null +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt @@ -0,0 +1,132 @@ +/* + * Copyright 2010-2020 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.fir.tree.generator.printer + +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder +import org.jetbrains.kotlin.fir.tree.generator.model.Element +import org.jetbrains.kotlin.fir.tree.generator.model.Implementation +import org.jetbrains.kotlin.fir.tree.generator.pureAbstractElementType + +import java.io.File + +fun Element.generateCode(generationPath: File) { + val dir = generationPath.resolve(packageName.replace(".", "/")) + dir.mkdirs() + val file = File(dir, "$type.kt") + file.useSmartPrinter { + printCopyright() + println("package $packageName") + println() + val imports = collectImports() + imports.forEach { println("import $it") } + if (imports.isNotEmpty()) { + println() + } + printGeneratedMessage() + printElement(this@generateCode) + } +} + +fun SmartPrinter.printElement(element: Element) { + with(element) { + val isInterface = kind == Implementation.Kind.Interface + + fun abstract() { + if (!isInterface) { + print("abstract ") + } + } + + fun override() { + if (this != AbstractFirTreeBuilder.baseFirElement) { + print("override ") + } + } + + print("${kind!!.title} $type") + if (typeArguments.isNotEmpty()) { + print(typeArguments.joinToString(", ", "<", ">") { it.toString() }) + } + val needPureAbstractElement = !isInterface && !allParents.any { it.kind == Implementation.Kind.AbstractClass } + + if (parents.isNotEmpty() || needPureAbstractElement) { + print(" : ") + if (needPureAbstractElement) { + print("${pureAbstractElementType.type}()") + if (parents.isNotEmpty()) { + print(", ") + } + } + print( + parents.joinToString(", ") { + var result = it.type + parentsArguments[it]?.let { arguments -> + result += arguments.values.joinToString(", ", "<", ">") { it.typeWithArguments } + } + result + it.kind.braces() + }, + ) + } + print(multipleUpperBoundsList()) + println("{") + withIndent { + allFields.forEach { + abstract() + printField(it, isImplementation = false, override = it.fromParent, end = "") + } + if (allFields.isNotEmpty()) { + println() + } + + override() + println("fun accept(visitor: FirVisitor, data: D): R = visitor.visit$name(this, data)") + + fields.filter { it.withReplace }.forEach { + println() + abstract() + if (it.fromParent) print("override ") + println(it.replaceFunctionDeclaration()) + } + + for (field in allFields) { + if (!field.needsSeparateTransform) continue + println() + abstract() + if (field.fromParent) { + print("override ") + } + println(field.transformFunctionDeclaration(typeWithArguments)) + } + if (needTransformOtherChildren) { + println() + abstract() + if (element.parents.any { it.needTransformOtherChildren }) { + print("override ") + } + println(transformFunctionDeclaration("OtherChildren", typeWithArguments)) + } + + if (element == AbstractFirTreeBuilder.baseFirElement) { + require(isInterface) + println() + println("fun accept(visitor: FirVisitorVoid) = accept(visitor, null)") + println() + println("fun acceptChildren(visitor: FirVisitor, data: D)") + println() + println("fun acceptChildren(visitor: FirVisitorVoid) = acceptChildren(visitor, null)") + println() + println("@Suppress(\"UNCHECKED_CAST\")") + println("fun transform(visitor: FirTransformer, data: D): CompositeTransformResult =") + withIndent { + println("accept(visitor, data) as CompositeTransformResult") + } + println() + println("fun transformChildren(transformer: FirTransformer, data: D): FirElement") + } + } + println("}") + } +} diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt new file mode 100644 index 00000000000..ef0e6b63169 --- /dev/null +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2020 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.fir.tree.generator.printer + +import org.jetbrains.kotlin.fir.tree.generator.model.Field + + +fun SmartPrinter.printField(field: Field, isImplementation: Boolean, override: Boolean, end: String) { + if (override) { + print("override ") + } + if (!isImplementation || field.isVal) { + print("val") + } else { + print("var") + } + val type = if (isImplementation) field.mutableType else field.typeWithArguments + println(" ${field.name}: $type$end") +} + +fun SmartPrinter.printFieldWithDefaultInImplementation(field: Field) { + val defaultValue = field.defaultValue + print("override ") + if (field.isLateinit) { + print("lateinit ") + } + if (field.isVal) { + print("val") + } else { + print("var") + } + print(" ${field.name}: ${field.mutableType}") + if (field.isLateinit) { + println() + return + } else { + print(" ") + } + if (field.withGetter) { + if (field.customSetter != null) { + println() + pushIndent() + } + print("get() ") + } + requireNotNull(defaultValue) { + "No default value for $field" + } + println("= $defaultValue") + field.customSetter?.let { + println("set(value) {") + pushIndent() + println(it) + popIndent() + println("}") + popIndent() + } +} diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt new file mode 100644 index 00000000000..eb8a24108f2 --- /dev/null +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt @@ -0,0 +1,329 @@ +/* + * Copyright 2010-2020 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.fir.tree.generator.printer + +import org.jetbrains.kotlin.fir.tree.generator.model.* +import org.jetbrains.kotlin.fir.tree.generator.pureAbstractElementType + +import java.io.File + +fun Implementation.generateCode(generationPath: File) { + val dir = generationPath.resolve(packageName.replace(".", "/")) + dir.mkdirs() + val file = File(dir, "$type.kt") + file.useSmartPrinter { + printCopyright() + println("package $packageName") + println() + val imports = collectImports() + imports.forEach { println("import $it") } + if (imports.isNotEmpty()) { + println() + } + printGeneratedMessage() + printImplementation(this@generateCode) + } +} + +fun SmartPrinter.printImplementation(implementation: Implementation) { + fun Field.transform() { + when (this) { + is FieldWithDefault -> origin.transform() + + is FirField -> + println("$name = ${name}${call()}transformSingle(transformer, data)") + + is FieldList -> { + println("${name}.transformInplace(transformer, data)") + } + + else -> throw IllegalStateException() + } + } + + with(implementation) { + print("${kind!!.title} $type") + print(element.typeParameters) + val fieldsWithoutDefault = allFields.filter { it.defaultValue == null && !it.isLateinit } + val fieldsWithDefault = allFields.filter { it.defaultValue != null || it.isLateinit } + + val isInterface = kind == Implementation.Kind.Interface + val isAbstract = kind == Implementation.Kind.AbstractClass + + fun abstract() { + if (isAbstract) { + print("abstract ") + } + } + + if (!isInterface && !isAbstract && fieldsWithoutDefault.isNotEmpty()) { + println("(") + withIndent { + fieldsWithoutDefault.forEachIndexed { i, field -> + val end = if (i == fieldsWithoutDefault.size - 1) "" else "," + printField(field, isImplementation = true, override = true, end = end) + } + } + print(")") + } + + print(" : ") + if (!isInterface && !allParents.any { it.kind == Implementation.Kind.AbstractClass }) { + print("${pureAbstractElementType.type}(), ") + } + print(allParents.joinToString { "${it.typeWithArguments}${it.kind.braces()}" }) + println(" {") + withIndent { + if (isInterface || isAbstract) { + allFields.forEach { + abstract() + printField(it, isImplementation = true, override = true, end = "") + } + } else { + fieldsWithDefault.forEach { + printFieldWithDefaultInImplementation(it) + } + if (fieldsWithDefault.isNotEmpty()) { + println() + } + } + + element.allFields.filter { it.type.contains("Symbol") && it !is FieldList } + .takeIf { it.isNotEmpty() && !isInterface && !isAbstract && !element.type.contains("Reference") } + ?.let { symbolFields -> + println("init {") + for (symbolField in symbolFields) { + withIndent { + println("${symbolField.name}${symbolField.call()}bind(this)") + } + } + println("}") + println() + } + + fun Field.acceptString(): String = "${name}${call()}accept(visitor, data)" + if (!isInterface && !isAbstract) { + print("override fun acceptChildren(visitor: FirVisitor, data: D) {") + + if (element.allFirFields.isNotEmpty()) { + println() + withIndent { + for (field in allFields.filter { it.isFirType }) { + if (field.withGetter || !field.needAcceptAndTransform) continue + when (field.name) { + "explicitReceiver" -> { + val explicitReceiver = implementation["explicitReceiver"]!! + val dispatchReceiver = implementation["dispatchReceiver"]!! + val extensionReceiver = implementation["extensionReceiver"]!! + println( + """ + |${explicitReceiver.acceptString()} + | if (dispatchReceiver !== explicitReceiver) { + | ${dispatchReceiver.acceptString()} + | } + | if (extensionReceiver !== explicitReceiver && extensionReceiver !== dispatchReceiver) { + | ${extensionReceiver.acceptString()} + | } + """.trimMargin(), + ) + } + + "dispatchReceiver", "extensionReceiver", "subjectVariable", "companionObject" -> { + } + + else -> { + if (type in setOf("FirClassImpl", "FirSealedClassImpl") && field.name == "declarations") { + println("(declarations.firstOrNull { it is FirConstructorImpl } as? FirConstructorImpl)?.typeParameters?.forEach { it.accept(visitor, data) }") + } + if (type == "FirWhenExpressionImpl" && field.name == "subject") { + println( + """ + |if (subjectVariable != null) { + | subjectVariable.accept(visitor, data) + | } else { + | subject?.accept(visitor, data) + | } + """.trimMargin(), + ) + } else { + when (field.origin) { + is FirField -> { + println(field.acceptString()) + } + + is FieldList -> { + println("${field.name}.forEach { it.accept(visitor, data) }") + } + + else -> throw IllegalStateException() + } + } + } + + } + } + } + } + println("}") + println() + } + + abstract() + print("override fun transformChildren(transformer: FirTransformer, data: D): $typeWithArguments") + if (!isInterface && !isAbstract) { + println(" {") + withIndent { + for (field in allFields) { + when { + !field.isMutable || !field.isFirType || field.withGetter || !field.needAcceptAndTransform -> {} + + field.name == "explicitReceiver" -> { + val explicitReceiver = implementation["explicitReceiver"]!! + val dispatchReceiver = implementation["dispatchReceiver"]!! + val extensionReceiver = implementation["extensionReceiver"]!! + if (explicitReceiver.isMutable) { + println("explicitReceiver = explicitReceiver${explicitReceiver.call()}transformSingle(transformer, data)") + } + if (dispatchReceiver.isMutable) { + println( + """ + |if (dispatchReceiver !== explicitReceiver) { + | dispatchReceiver = dispatchReceiver.transformSingle(transformer, data) + | } + """.trimMargin(), + ) + } + if (extensionReceiver.isMutable) { + println( + """ + |if (extensionReceiver !== explicitReceiver && extensionReceiver !== dispatchReceiver) { + | extensionReceiver = extensionReceiver.transformSingle(transformer, data) + | } + """.trimMargin(), + ) + } + } + + field.name in setOf("dispatchReceiver", "extensionReceiver") -> {} + + type in setOf("FirClassImpl", "FirSealedClassImpl") && field.name == "declarations" -> { + println("(declarations.firstOrNull { it is FirConstructorImpl } as? FirConstructorImpl)?.typeParameters?.transformInplace(transformer, data)") + println("declarations.transformInplace(transformer, data)") + } + + field.name == "companionObject" -> { + println("companionObject = declarations.asSequence().filterIsInstance().firstOrNull { it.status.isCompanion }") + } + + field.needsSeparateTransform -> { + println("transform${field.name.capitalize()}(transformer, data)") + } + + !element.needTransformOtherChildren -> { + field.transform() + } + + else -> {} + } + } + if (element.needTransformOtherChildren) { + println("transformOtherChildren(transformer, data)") + } + println("return this") + } + println("}") + } else { + println() + } + + for (field in allFields) { + if (!field.needsSeparateTransform) continue + println() + abstract() + print("override ${field.transformFunctionDeclaration(typeWithArguments)}") + if (isInterface || isAbstract) { + println() + continue + } + println(" {") + withIndent { + if (field.isMutable && field.isFirType) { + // TODO: replace with smth normal + if (type == "FirWhenExpressionImpl" && field.name == "subject") { + println( + """ + |if (subjectVariable != null) { + | subjectVariable = subjectVariable?.transformSingle(transformer, data) + | } else { + | subject = subject?.transformSingle(transformer, data) + | } + """.trimMargin(), + ) + } else { + field.transform() + } + } + println("return this") + } + println("}") + } + + if (element.needTransformOtherChildren) { + println() + abstract() + print("override fun transformOtherChildren(transformer: FirTransformer, data: D): $typeWithArguments") + if (isInterface || isAbstract) { + println() + } else { + println(" {") + withIndent { + for (field in allFields) { + if (!field.isMutable || !field.isFirType || field.name == "subjectVariable") continue + if (!field.needsSeparateTransform) { + field.transform() + } + } + println("return this") + } + println("}") + } + } + + for (field in allFields.filter { it.withReplace }) { + println() + abstract() + print("override ${field.replaceFunctionDeclaration()}") + if (isInterface || isAbstract) { + println() + continue + } + print(" {") + if (!field.isMutable) { + println("}") + continue + } + println() + withIndent { + val newValue = "new${field.name.capitalize()}" + when { + field.withGetter -> {} + + field.origin is FieldList -> { + println("${field.name}.clear()") + println("${field.name}.addAll($newValue)") + } + + else -> { + println("${field.name} = $newValue") + } + } + } + println("}") + } + } + println("}") + } +} diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/main.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/main.kt new file mode 100644 index 00000000000..e7feb2ba34a --- /dev/null +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/main.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2020 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.fir.tree.generator.printer + +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder + +import java.io.File +import java.util.* + +private val COPYRIGHT = """ +/* + * Copyright 2010-${GregorianCalendar()[Calendar.YEAR]} 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. + */ +""".trimIndent() + +const val VISITOR_PACKAGE = "org.jetbrains.kotlin.fir.visitors" +const val BASE_PACKAGE = "org.jetbrains.kotlin.fir" +val GENERATED_MESSAGE = """ + /* + * This file was generated automatically + * DO NOT MODIFY IT MANUALLY + */ + """.trimIndent() + +fun printElements(builder: AbstractFirTreeBuilder, generationPath: File) { + builder.elements.forEach { it.generateCode(generationPath) } + builder.elements.flatMap { it.allImplementations }.forEach { it.generateCode(generationPath) } + + printVisitor(builder.elements, generationPath) + printVisitorVoid(builder.elements, generationPath) + printTransformer(builder.elements, generationPath) +} + +fun SmartPrinter.printCopyright() { + println(COPYRIGHT) + println() +} + +fun SmartPrinter.printGeneratedMessage() { + println(GENERATED_MESSAGE) + println() +} diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/transformer.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/transformer.kt new file mode 100644 index 00000000000..b9e8bd8f538 --- /dev/null +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/transformer.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2010-2020 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.fir.tree.generator.printer + +import org.jetbrains.kotlin.fir.tree.generator.compositeTransformResultType +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder +import org.jetbrains.kotlin.fir.tree.generator.model.Element + +import java.io.File + +fun printTransformer(elements: List, generationPath: File) { + val dir = File(generationPath, VISITOR_PACKAGE.replace(".", "/")) + dir.mkdirs() + File(dir, "FirTransformer.kt").useSmartPrinter { + printCopyright() + println("package $VISITOR_PACKAGE") + println() + elements.forEach { println("import ${it.fullQualifiedName}") } + println("import ${compositeTransformResultType.fullQualifiedName}") + println() + printGeneratedMessage() + + println("abstract class FirTransformer : FirVisitor, D>() {") + println() + withIndent { + println("abstract fun transformElement(element: E, data: D): CompositeTransformResult") + println() + for (element in elements) { + if (element == AbstractFirTreeBuilder.baseFirElement) continue + val varName = element.safeDecapitalizedName + print("open fun ") + element.typeParameters.takeIf { it.isNotBlank() }?.let { print(it) } + println( + "transform${element.name}($varName: ${element.typeWithArguments}, data: D): CompositeTransformResult<${element.transformerType + .typeWithArguments}>${element.multipleUpperBoundsList()}{", + ) + withIndent { + println("return transformElement($varName, data)") + } + println("}") + println() + } + + for (element in elements) { + val varName = element.safeDecapitalizedName + print("final override fun ") + element.typeParameters.takeIf { it.isNotBlank() }?.let { print(it) } + + println( + "visit${element.name}($varName: ${element.typeWithArguments}, data: D): CompositeTransformResult<${element.transformerType + .typeWithArguments}>${element.multipleUpperBoundsList()}{", + ) + withIndent { + println("return transform${element.name}($varName, data)") + } + println("}") + println() + } + } + println("}") + } +} diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt new file mode 100644 index 00000000000..7f26f91f2a7 --- /dev/null +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2010-2020 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.fir.tree.generator.printer + +import org.jetbrains.kotlin.fir.tree.generator.compositeTransformResultType +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder +import org.jetbrains.kotlin.fir.tree.generator.model.* +import org.jetbrains.kotlin.fir.tree.generator.pureAbstractElementType + + +fun Implementation.collectImports(): List { + return element.collectImportsInternal( + listOf( + element.fullQualifiedName, + ) + + usedTypes.mapNotNull { it.fullQualifiedName } + parents.mapNotNull { it.fullQualifiedName } + + listOfNotNull( + pureAbstractElementType.fullQualifiedName?.takeIf { needPureAbstractElement }, + ), + isImpl = true, + ) +} + +fun Element.collectImports(): List { + val baseTypes = parents.mapTo(mutableListOf()) { it.fullQualifiedName } + baseTypes += parentsArguments.values.flatMap { it.values }.mapNotNull { it.fullQualifiedName } + val isBaseFirElement = this == AbstractFirTreeBuilder.baseFirElement + if (isBaseFirElement) { + baseTypes += compositeTransformResultType.fullQualifiedName!! + } + if (needPureAbstractElement) { + baseTypes += pureAbstractElementType.fullQualifiedName!! + } + return collectImportsInternal( + baseTypes, + isImpl = false, + ) +} + +private fun Element.collectImportsInternal(base: List, isImpl: Boolean): List { + val fqns = base + allFields.mapNotNull { it.fullQualifiedName } + + allFields.flatMap { it.arguments.mapNotNull { it.fullQualifiedName } } + + typeArguments.flatMap { it.upperBounds.mapNotNull { it.fullQualifiedName } } + val realPackageName = if (isImpl) "$packageName.impl." else "$packageName." + return fqns.filter { fqn -> + fqn.dropLastWhile { it != '.' } != realPackageName + }.distinct().sorted() + "$VISITOR_PACKAGE.*" +} + +val KindOwner.needPureAbstractElement: Boolean + get() = (kind != Implementation.Kind.Interface) && !allParents.any { it.kind == Implementation.Kind.AbstractClass } + + +val Field.isVal: Boolean get() = this is FieldList || (this is FieldWithDefault && origin is FieldList) || !isMutable + + +fun Field.transformFunctionDeclaration(returnType: String): String { + return transformFunctionDeclaration(name.capitalize(), returnType) +} + +fun transformFunctionDeclaration(transformName: String, returnType: String): String { + return "fun transform$transformName(transformer: FirTransformer, data: D): $returnType" +} + +fun Field.replaceFunctionDeclaration(): String { + val capName = name.capitalize() + return "fun replace$capName(new$capName: $typeWithArgumentsWithoutNullablity)" +} + +val Field.mutableType: String + get() = when (this) { + is FieldList -> if (isMutable) "Mutable$typeWithArguments" else typeWithArguments + is FieldWithDefault -> if (isMutable) origin.mutableType else typeWithArguments + else -> typeWithArguments + } + +fun Field.call(): String = if (nullable) "?." else "." + +fun Element.multipleUpperBoundsList(): String { + return typeArguments.filterIsInstance().takeIf { it.isNotEmpty() }?.let { arguments -> + val upperBoundsList = arguments.joinToString(", ", postfix = " ") { argument -> + argument.upperBounds.joinToString(", ") { upperBound -> "${argument.name} : ${upperBound.typeWithArguments}" } + } + " where $upperBoundsList" + } ?: " " +} + +fun Implementation.Kind?.braces(): String = when (this) { + Implementation.Kind.Interface -> "" + Implementation.Kind.OpenClass, Implementation.Kind.AbstractClass -> "()" + else -> throw IllegalStateException(this.toString()) +} + +val Element.safeDecapitalizedName: String get() = if (name == "Class") "klass" else name.decapitalize() + +val Importable.typeWithArguments: String + get() = when (this) { + is AbstractElement -> type + generics + is Implementation -> type + element.generics + is FirField -> element.typeWithArguments + if (nullable) "?" else "" + is Field -> type + generics + if (nullable) "?" else "" + is Type -> type + generics + is ImplementationWithArg -> type + generics + else -> throw IllegalArgumentException() + } + +val Importable.typeWithArgumentsWithoutNullablity: String get() = typeWithArguments.dropLastWhile { it == '?' } + +val ImplementationWithArg.generics: String + get() = argument?.let { "<${it.type}>" } ?: "" + +val AbstractElement.generics: String + get() = typeArguments.takeIf { it.isNotEmpty() } + ?.let { it.joinToString(", ", "<", ">") { it.name } } + ?: "" + +val Field.generics: String + get() = arguments.takeIf { it.isNotEmpty() } + ?.let { it.joinToString(", ", "<", ">") { it.typeWithArguments } } + ?: "" + +val Element.typeParameters: String + get() = typeArguments.takeIf { it.isNotEmpty() } + ?.joinToString(", ", "<", "> ") + ?: "" + +val Type.generics: String + get() = arguments.takeIf { it.isNotEmpty() }?.joinToString(",", "<", ">") ?: "" \ No newline at end of file diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/visitor.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/visitor.kt new file mode 100644 index 00000000000..bad81737cc2 --- /dev/null +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/visitor.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2010-2020 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.fir.tree.generator.printer + +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder +import org.jetbrains.kotlin.fir.tree.generator.model.Element + +import java.io.File +import java.io.PrintWriter + +fun printVisitor(elements: List, generationPath: File) { + val dir = File(generationPath, VISITOR_PACKAGE.replace(".", "/")) + dir.mkdirs() + File(dir, "FirVisitor.kt").useSmartPrinter { + printCopyright() + println("package $VISITOR_PACKAGE") + println() + elements.forEach { println("import ${it.fullQualifiedName}") } + println() + printGeneratedMessage() + + println("abstract class FirVisitor {") + + pushIndent() + println("abstract fun visitElement(element: FirElement, data: D): R\n") + for (element in elements) { + if (element == AbstractFirTreeBuilder.baseFirElement) continue + with(element) { + val varName = safeDecapitalizedName + println("open fun ${typeParameters}visit$name($varName: $typeWithArguments, data: D): R${multipleUpperBoundsList()} = visitElement($varName, data)") + println() + } + } + popIndent() + println("}") + } +} + + +fun printVisitorVoid(elements: List, generationPath: File) { + val dir = File(generationPath, VISITOR_PACKAGE.replace(".", "/")) + dir.mkdirs() + File(dir, "FirVisitorVoid.kt").useSmartPrinter { + printCopyright() + println("package $VISITOR_PACKAGE") + println() + elements.forEach { println("import ${it.fullQualifiedName}") } + println() + printGeneratedMessage() + + println("abstract class FirVisitorVoid : FirVisitor() {") + + withIndent { + println("abstract fun visitElement(element: FirElement)") + println() + for (element in elements) { + if (element == AbstractFirTreeBuilder.baseFirElement) continue + with(element) { + val varName = safeDecapitalizedName + println("open fun ${typeParameters}visit$name($varName: $typeWithArguments)${multipleUpperBoundsList()}{") + withIndent { + println("visitElement($varName)") + } + println("}") + println() + } + } + + for (element in elements) { + with(element) { + val varName = safeDecapitalizedName + println("final override fun ${typeParameters}visit$name($varName: $typeWithArguments, data: Nothing?)${multipleUpperBoundsList()}{") + withIndent { + println("visit$name($varName)") + } + println("}") + println() + } + } + } + println("}") + } +}