[FIR] Add FIR tree generator

This commit is contained in:
Dmitriy Novozhilov
2019-10-09 17:42:24 +03:00
parent 807050b159
commit d6d4b3329b
17 changed files with 3114 additions and 0 deletions
@@ -16,6 +16,10 @@ runtimeOnly.extendsFrom(compileOnly)
dependencies {
compile(project(":compiler:psi"))
compile(project(":compiler:frontend.common"))
compile(project(":core:descriptors"))
compile(project(":compiler:fir:cones"))
compile(project(":compiler:ir.tree"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) }
compileOnly(intellijDep()) {
@@ -25,6 +29,7 @@ dependencies {
Platform[192].orHigher {
runtimeOnly(intellijCoreDep()) { includeJars("jdom") }
}
implementation(kotlin("reflect"))
}
val writeCopyright by task<WriteCopyrightToFile> {
@@ -0,0 +1,79 @@
/*
* 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.FirTreeBuilder.annotationCall
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.block
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.controlFlowGraphReference
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.declaration
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.declarationStatus
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.expression
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.reference
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeParameter
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeProjection
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeRef
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.valueParameter
import org.jetbrains.kotlin.fir.tree.generator.context.type
import org.jetbrains.kotlin.fir.tree.generator.model.*
object FieldSets {
val calleeReference = field("calleeReference", reference)
val receivers = fieldSet(
field("explicitReceiver", expression, nullable = true).withTransform(),
field("dispatchReceiver", expression).withTransform(),
field("extensionReceiver", expression).withTransform()
)
val typeArguments =
fieldList("typeArguments", typeProjection)
val arguments =
fieldList("arguments", expression)
val declarations = fieldList(declaration)
val annotations =
fieldList("annotations", annotationCall)
fun symbolWithPackage(packageName: String?, symbolClassName: String, argument: String? = null): Field {
return field("symbol", type(packageName, symbolClassName), argument)
}
fun symbol(symbolClassName: String, argument: String? = null): Field =
symbolWithPackage("fir.symbols.impl", symbolClassName, argument)
fun body(nullable: Boolean = false) =
field("body", block, nullable)
val returnTypeRef =
field("returnTypeRef", typeRef)
val typeRefField =
field(typeRef, withReplace = true)
fun receiverTypeRef(nullable: Boolean = false) = field("receiverTypeRef", typeRef, nullable)
val valueParameters = fieldList(valueParameter)
val typeParameters = fieldList(typeParameter)
val name = field(nameType)
val initializer = field("initializer", expression, nullable = true)
fun superTypeRefs(withReplace: Boolean = false) = fieldList("superTypeRefs", typeRef, withReplace)
val classKind = field(classKindType)
val status = field("status", declarationStatus)
val controlFlowGraphReferenceField = field("controlFlowGraphReference", controlFlowGraphReference)
val visibility = field(visibilityType)
val modality = field(modalityType, nullable = true)
}
@@ -0,0 +1,132 @@
/*
* 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.Element.Kind.*
object FirTreeBuilder : AbstractFirTreeBuilder() {
val annotationContainer = element("AnnotationContainer", Other)
val typeRef = element("TypeRef", TypeRef, annotationContainer)
val reference = element("Reference", Reference)
val label = element("Label", Other)
val import = element("Import", Declaration)
val resolvedImport = element("ResolvedImport", Declaration, import)
val symbolOwner = element("SymbolOwner", Other)
val resolvable = element("Resolvable", Expression)
val controlFlowGraphOwner = element("ControlFlowGraphOwner", Other)
val targetElement = element("TargetElement", Other)
val declarationStatus = element("DeclarationStatus", Declaration)
val resolvedDeclarationStatus = element("ResolvedDeclarationStatus", Declaration, declarationStatus)
val statement = element("Statement", Expression, annotationContainer)
val expression = element("Expression", Expression, statement)
val declaration = element("Declaration", Declaration)
val anonymousInitializer = element("AnonymousInitializer", Declaration, declaration)
val typedDeclaration = element("TypedDeclaration", Declaration, declaration, annotationContainer)
val callableDeclaration = element("CallableDeclaration", Declaration, typedDeclaration, symbolOwner)
val namedDeclaration = element("NamedDeclaration", Declaration, declaration)
val typeParameter = element("TypeParameter", Declaration, namedDeclaration, symbolOwner, annotationContainer)
val typeParametersOwner = element("TypeParametersOwner", Declaration)
val memberDeclaration = element("MemberDeclaration", Declaration, namedDeclaration, annotationContainer)
val callableMemberDeclaration = element("CallableMemberDeclaration", Declaration, callableDeclaration, memberDeclaration)
val variable = element("Variable", Declaration, callableDeclaration, namedDeclaration, statement)
val valueParameter = element("ValueParameter", Declaration, variable)
val property = element("Property", Declaration, variable, controlFlowGraphOwner, typeParametersOwner, callableMemberDeclaration)
val field = element("Field", Declaration, variable, callableMemberDeclaration) // TODO: add noImpl
val klass = element("Class", Declaration, declaration, statement, annotationContainer)
val classLikeDeclaration = element("ClassLikeDeclaration", Declaration, statement, memberDeclaration, symbolOwner, typeParametersOwner)
val regularClass = element("RegularClass", Declaration, namedDeclaration, classLikeDeclaration, klass)
val typeAlias = element("TypeAlias", Declaration, classLikeDeclaration)
val enumEntry = element("EnumEntry", Declaration, regularClass)
val function = element("Function", Declaration, callableDeclaration, controlFlowGraphOwner, targetElement, annotationContainer, typeParametersOwner, statement)
val memberFunction = element("MemberFunction", Declaration, function, callableMemberDeclaration)
val simpleFunction = element("SimpleFunction", Declaration, memberFunction)
val propertyAccessor = element("PropertyAccessor", Declaration, function)
val constructor = element("Constructor", Declaration, memberFunction)
val file = element("File", Declaration, annotationContainer, declaration)
val anonymousFunction = element("AnonymousFunction", Declaration, function, expression)
val anonymousObject = element("AnonymousObject", Declaration, klass, expression)
val loop = element("Loop", Expression, statement, targetElement, annotationContainer)
val doWhileLoop = element("DoWhileLoop", Expression, loop)
val whileLoop = element("WhileLoop", Expression, loop)
val block = element("Block", Expression, expression)
val binaryLogicExpression = element("BinaryLogicExpression", Expression, expression)
val jump = element("Jump", Expression, expression)
val loopJump = element("LoopJump", Expression, jump)
val breakExpression = element("BreakExpression", Expression, loopJump)
val continueExpression = element("ContinueExpression", Expression, loopJump)
val catchClause = element("Catch", Expression)
val tryExpression = element("TryExpression", Expression, expression, resolvable)
val constExpression = element("ConstExpression", Expression, expression)
val typeProjection = element("TypeProjection", TypeRef)
val starProjection = element("StarProjection", TypeRef, typeProjection)
val typeProjectionWithVariance = element("TypeProjectionWithVariance", TypeRef, typeProjection)
val call = element("Call", Expression, statement) // TODO: may smth like `CallWithArguments` or `ElementWithArguments`?
val annotationCall = element("AnnotationCall", Expression, expression, call)
val operatorCall = element("OperatorCall", Expression, expression, call)
val typeOperatorCall = element("TypeOperatorCall", Expression, expression, call)
val whenExpression = element("WhenExpression", Expression, expression, resolvable)
val whenBranch = element("WhenBranch", Expression)
val delegatedConstructorCall = element("DelegatedConstructorCall", Expression, call)
val qualifiedAccessWithoutCallee = element("QualifiedAccessWithoutCallee", Expression, statement)
val qualifiedAccess = element("QualifiedAccess", Expression, qualifiedAccessWithoutCallee, resolvable)
val arrayOfCall = element("ArrayOfCall", Expression, expression, call)
val arraySetCall = element("ArraySetCall", Expression, qualifiedAccess, call)
val classReferenceExpression = element("ClassReferenceExpression", Expression, expression)
val errorExpression = element("ErrorExpression", Expression, expression)
val errorFunction = element("ErrorFunction", Declaration, function)
val qualifiedAccessExpression = element("QualifiedAccessExpression", Expression, expression, qualifiedAccess)
val functionCall = element("FunctionCall", Expression, qualifiedAccessExpression, call)
val componentCall = element("ComponentCall", Expression, functionCall)
val callableReferenceAccess = element("CallableReferenceAccess", Expression, qualifiedAccessExpression)
val thisReceiverExpression = element("ThisReceiverExpression", Expression, qualifiedAccessExpression)
val expressionWithSmartcast = element("ExpressionWithSmartcast", Expression, qualifiedAccessExpression)
val getClassCall = element("GetClassCall", Expression, expression, call)
val wrappedExpression = element("WrappedExpression", Expression, expression)
val wrappedArgumentExpression = element("WrappedArgumentExpression", Expression, wrappedExpression)
val lambdaArgumentExpression = element("LambdaArgumentExpression", Expression, wrappedArgumentExpression)
val spreadArgumentExpression = element("SpreadArgumentExpression", Expression, wrappedArgumentExpression)
val namedArgumentExpression = element("NamedArgumentExpression", Expression, wrappedArgumentExpression)
val resolvedQualifier = element("ResolvedQualifier", Expression, expression)
val returnExpression = element("ReturnExpression", Expression, jump)
val stringConcatenationCall = element("StringConcatenationCall", Expression, call, expression)
val throwExpression = element("ThrowExpression", Expression, expression)
val variableAssignment = element("VariableAssignment", Expression, qualifiedAccess)
val whenSubjectExpression = element("WhenSubjectExpression", Expression, expression)
val wrappedDelegateExpression = element("WrappedDelegateExpression", Expression, wrappedExpression)
val namedReference = element("NamedReference", Reference, reference)
val errorNamedReference = element("ErrorNamedReference", Reference, namedReference)
val superReference = element("SuperReference", Reference, reference)
val thisReference = element("ThisReference", Reference, reference)
val controlFlowGraphReference = element("ControlFlowGraphReference", Reference, reference)
val resolvedCallableReference = element("ResolvedCallableReference", Reference, namedReference)
val delegateFieldReference = element("DelegateFieldReference", Reference, resolvedCallableReference)
val backingFieldReference = element("BackingFieldReference", Reference, resolvedCallableReference)
val resolvedTypeRef = element("ResolvedTypeRef", TypeRef, typeRef)
val errorTypeRef = element("ErrorTypeRef", TypeRef, resolvedTypeRef)
val delegatedTypeRef = element("DelegatedTypeRef", TypeRef, typeRef)
val typeRefWithNullability = element("TypeRefWithNullability", TypeRef, typeRef)
val userTypeRef = element("UserTypeRef", TypeRef, typeRefWithNullability)
val dynamicTypeRef = element("DynamicTypeRef", TypeRef, typeRefWithNullability)
val functionTypeRef = element("FunctionTypeRef", TypeRef, typeRefWithNullability)
val resolvedFunctionTypeRef = element("ResolvedFunctionTypeRef", TypeRef, resolvedTypeRef, functionTypeRef)
val implicitTypeRef = element("ImplicitTypeRef", TypeRef, typeRef)
}
@@ -0,0 +1,625 @@
/*
* Copyright 2000-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.AbstractFirTreeImplementationConfigurator
import org.jetbrains.kotlin.fir.tree.generator.model.Implementation
import org.jetbrains.kotlin.fir.tree.generator.model.Implementation.Kind.*
object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() {
private lateinit var abstractAnnotatedElement: Implementation
fun configureImplementations() {
configure()
generateDefaultImplementations(FirTreeBuilder)
configureAllImplementations()
}
private fun configure() = with(FirTreeBuilder) {
val callWithArgumentList = impl(call, "FirCallWithArgumentList") {
kind = Interface
}
abstractAnnotatedElement = impl(annotationContainer, "FirAbstractAnnotatedElement") {
kind = Interface
}
val modifiableTypeParametersOwner = impl(typeParametersOwner, "FirModifiableTypeParametersOwner") {
kind = Interface
}
val modifiableConstructor = impl(constructor, "FirModifiableConstructor") {
kind = Interface
parents += modifiableTypeParametersOwner
}
impl(constructor) {
kind = OpenClass
parents += modifiableConstructor
defaultNull("delegatedConstructor")
defaultNull("body")
default("name", "Name.special(\"<init>\")")
default("isPrimary") {
value = "false"
withGetter = true
}
default("typeParameters") {
needAcceptAndTransform = false
}
}
noImpl(declarationStatus)
noImpl(resolvedDeclarationStatus)
noImpl(field)
val modifiableClass = impl(klass, "FirModifiableClass") {
kind = Interface
}
impl(regularClass, "FirClassImpl") {
parents += modifiableClass
parents += modifiableTypeParametersOwner
defaultNull("companionObject")
defaultSupertypesComputationStatus()
}
impl(anonymousObject) {
parents += modifiableClass
default("classKind") {
value = "ClassKind.OBJECT"
withGetter = true
}
}
impl(enumEntry) {
parents += modifiableClass
parents += modifiableTypeParametersOwner
default("status", "FirDeclarationStatusImpl(Visibilities.UNKNOWN, Modality.FINAL)")
default("classKind") {
value = "ClassKind.ENUM_ENTRY"
withGetter = true
}
default("companionObject") {
value = "null"
withGetter = true
}
default("typeRef", "session.builtinTypes.enumType")
defaultSupertypesComputationStatus()
useTypes(visibilitiesType, modalityType)
}
impl(typeAlias) {
parents += modifiableTypeParametersOwner
defaultSupertypesComputationStatus()
}
impl(import)
impl(resolvedImport) {
delegateFields(listOf("aliasName", "importedFqName", "isAllUnder"), "delegate")
default("psi") {
delegate = "delegate"
}
default("resolvedClassId") {
delegate = "relativeClassName"
delegateCall = "let { ClassId(packageFqName, it, false) }"
withGetter = true
}
default("importedName") {
delegate = "importedFqName"
delegateCall = "shortName()"
withGetter = true
}
default("delegate") {
needAcceptAndTransform = false
}
}
impl(breakExpression) {
lateinit("target")
}
impl(continueExpression) {
lateinit("target")
}
impl(annotationCall) {
parents += callWithArgumentList
default("typeRef") {
value = "annotationTypeRef"
withGetter = true
}
}
impl(arrayOfCall) {
parents += callWithArgumentList
}
val modifiableQualifiedAccess = impl(qualifiedAccessWithoutCallee, "FirModifiableQualifiedAccess") {
kind = Interface
isMutable("safe")
}
impl(arraySetCall) {
parents += modifiableQualifiedAccess
lateinit("calleeReference")
default("arguments") {
value = "indexes + rValue"
withGetter = true
}
default("lValue") {
value = "calleeReference"
customSetter = "calleeReference = value"
}
default("safe", "false")
defaultNoReceivers()
}
impl(callableReferenceAccess) {
parents += modifiableQualifiedAccess
defaultNull("explicitReceiver")
default("safe", "false")
defaultNoReceivers()
lateinit("calleeReference")
}
impl(componentCall) {
parents += callWithArgumentList // modifiableQualifiedAccess
default("safe") {
value = "false"
withGetter = true
}
listOf("dispatchReceiver", "extensionReceiver").forEach {
default(it) {
value = "FirNoReceiverExpression"
withGetter = true
}
}
default("calleeReference", "FirSimpleNamedReference(psi, Name.identifier(\"component\$componentIndex\"), null)")
useTypes(simpleNamedReferenceType, nameType, noReceiverExpressionType)
}
val abstractLoop = impl(loop, "FirAbstractLoop") {
kind = Interface
}
impl(whileLoop) {
parents += abstractLoop
defaultNull("label")
lateinit("block")
}
impl(doWhileLoop) {
parents += abstractLoop
defaultNull("label")
lateinit("block")
}
impl(delegatedConstructorCall) {
parents += callWithArgumentList
default(
"calleeReference",
"if (isThis) FirExplicitThisReference(psi, null) else FirExplicitSuperReference(psi, constructedTypeRef)"
)
default("isSuper") {
value = "!isThis"
withGetter = true
}
useTypes(explicitThisReferenceType, explicitSuperReferenceType)
}
impl(expression, "FirElseIfTrueCondition") {
default("typeRef", "FirImplicitBooleanTypeRef(psi)")
useTypes(implicitBooleanTypeRefType)
}
impl(block) {
}
val emptyExpressionBlock = impl(block, "FirEmptyExpressionBlock") {
// TODO: make statements immutable
defaultNull("psi")
}
impl(errorExpression)
impl(loop, "FirErrorLoop") {
default("block", "FirEmptyExpressionBlock()")
default("condition", "FirErrorExpressionImpl(psi, \"error loop\")")
defaultNull("label")
useTypes(emptyExpressionBlock)
}
impl(expression, "FirExpressionStub")
impl(functionCall) {
parents += modifiableQualifiedAccess
parents += callWithArgumentList
defaultFalse("safe")
lateinit("calleeReference")
defaultNoReceivers()
}
impl(qualifiedAccessExpression) {
parents += modifiableQualifiedAccess
defaultFalse("safe")
lateinit("calleeReference")
defaultNoReceivers()
}
noImpl(expressionWithSmartcast)
impl(getClassCall) {
parents += callWithArgumentList
default("argument") {
value = "arguments.first()"
withGetter = true
}
}
val modifiableVariable = impl(variable, "FirModifiableVariable") {
kind = Interface
}
impl(property) {
parents += modifiableVariable.withArg(property)
parents += modifiableTypeParametersOwner
default("isVal") {
value = "!isVar"
withGetter = true
}
default("backingFieldSymbol", "FirBackingFieldSymbol(symbol.callableId)")
default("delegateFieldSymbol", "delegate?.let { FirDelegateFieldSymbol(symbol.callableId) }")
defaultNull("getter", "setter")
default("resolvePhase") {
value = "if (isLocal) FirResolvePhase.DECLARATIONS else FirResolvePhase.RAW_FIR"
}
useTypes(backingFieldSymbolType, delegateFieldSymbolType)
}
impl(namedArgumentExpression) {
default("typeRef") {
delegate = "expression"
}
}
impl(lambdaArgumentExpression) {
default("isSpread") {
value = "false"
withGetter = true
}
default("typeRef") {
delegate = "expression"
}
}
impl(spreadArgumentExpression) {
default("isSpread") {
value = "true"
withGetter = true
}
default("typeRef") {
delegate = "expression"
}
}
impl(operatorCall) {
parents += callWithArgumentList
default("typeRef", """
|if (operation in FirOperation.BOOLEANS) {
| FirImplicitBooleanTypeRef(null)
| } else {
| FirImplicitTypeRefImpl(null)
| }
""".trimMargin())
useTypes(implicitTypeRefType, implicitBooleanTypeRefType)
}
impl(typeOperatorCall) {
parents += callWithArgumentList
}
impl(resolvedQualifier) {
isMutable("packageFqName", "relativeClassFqName")
default("classId") {
value = """
|relativeClassFqName?.let {
| ClassId(packageFqName, it, false)
|}
""".trimMargin()
withGetter = true
}
}
impl(returnExpression) {
lateinit("target")
default("typeRef", "FirImplicitNothingTypeRef(psi)")
useTypes(implicitNothingTypeRefType)
}
impl(stringConcatenationCall) {
parents += callWithArgumentList
default("typeRef", "FirImplicitStringTypeRef(psi)")
useTypes(implicitStringTypeRefType)
}
impl(throwExpression) {
default("typeRef", "FirImplicitNothingTypeRef(psi)")
useTypes(implicitNothingTypeRefType)
}
impl(thisReceiverExpression) {
parents += modifiableQualifiedAccess
default("safe") {
value = "false"
withGetter = true
}
defaultNoReceivers()
}
impl(tryExpression) {
default("calleeReference", "FirStubReference()")
useTypes(stubReferenceType)
}
impl(expression, "FirUnitExpression") {
default("typeRef", "FirImplicitUnitTypeRef(psi)")
useTypes(implicitUnitTypeRefType)
}
impl(variableAssignment) {
parents += modifiableQualifiedAccess
isMutable("operation")
lateinit("calleeReference")
defaultNoReceivers()
default("lValue") {
value = "calleeReference"
customSetter = "calleeReference = value"
}
}
val modifiableFunction = impl(function, "FirModifiableFunction") {
kind = Interface
}
impl(anonymousFunction) {
parents += modifiableFunction.withArg(anonymousFunction)
defaultNull("invocationKind", "label", "body")
default("resolvePhase", "FirResolvePhase.DECLARATIONS")
}
impl(propertyAccessor) {
parents += modifiableFunction.withArg(propertyAccessor)
default("receiverTypeRef") {
value = "null"
withGetter = true
}
default("isSetter") {
value = "!isGetter"
withGetter = true
}
defaultNull("body")
useTypes(modalityType)
kind = OpenClass
}
impl(whenExpression) {
default("calleeReference", "FirStubReference()")
useTypes(stubReferenceType)
}
impl(whenSubjectExpression) {
default("typeRef") {
value = "whenSubject.whenExpression.subject!!.typeRef"
withGetter = true
}
}
impl(wrappedDelegateExpression) {
lateinit("delegateProvider")
default("typeRef") {
delegate = "expression"
}
}
impl(resolvedCallableReference) {
defaultNull("candidateSymbol", withGetter = true)
}
impl(resolvedCallableReference, "FirPropertyFromParameterCallableReference") {
defaultNull("candidateSymbol", withGetter = true)
}
impl(namedReference, "FirSimpleNamedReference") {
kind = OpenClass
}
impl(delegateFieldReference) {
default("name") {
value = "Name.identifier(\"\\\$delegate\")"
withGetter = true
}
}
impl(backingFieldReference) {
default("name") {
value = "Name.identifier(\"\\\$field\")"
withGetter = true
}
}
impl(thisReference, "FirExplicitThisReference") {
default("boundSymbol") {
value = "null"
isMutable = true
}
}
impl(thisReference, "FirImplicitThisReference") {
defaultNull("psi")
default("labelName") {
value = "null"
withGetter = true
}
}
impl(superReference, "FirExplicitSuperReference")
impl(controlFlowGraphReference, "FirEmptyControlFlowGraphReference") {
noPsi()
}
impl(resolvedTypeRef)
val errorTypeRefImpl = impl(errorTypeRef) {
default("type", "ConeClassErrorType(reason)")
useTypes(coneClassErrorTypeType)
}
impl(errorFunction) {
defaultNull("receiverTypeRef", "body", withGetter = true)
default("returnTypeRef", "FirErrorTypeRefImpl(null, reason)")
useTypes(errorTypeRefImpl)
}
impl(functionTypeRef)
impl(implicitTypeRef) {
defaultEmptyList("annotations")
}
impl(implicitTypeRef, "FirComputingImplicitTypeRef") {
kind = Object
defaultNull("psi", withGetter = true)
}
impl(reference, "FirStubReference") {
default("psi") {
value = "null"
withGetter = true
}
}
impl(errorNamedReference) {
default("name", "Name.special(\"<\$errorReason>\")")
defaultNull("candidateSymbol", withGetter = true)
}
impl(typeProjection, "FirTypePlaceholderProjection") {
kind = Object
defaultNull("psi")
}
val abstractLoopJump = impl(loopJump, "FirAbstractLoopJump") {
kind = Interface
lateinit("target")
}
impl(breakExpression) {
parents += abstractLoopJump
default("typeRef", "FirImplicitNothingTypeRef(psi)")
useTypes(implicitNothingTypeRefType)
}
impl(continueExpression) {
parents += abstractLoopJump
default("typeRef", "FirImplicitNothingTypeRef(psi)")
useTypes(implicitNothingTypeRefType)
}
impl(valueParameter) {
kind = OpenClass
parents += modifiableVariable.withArg(valueParameter)
defaultTrue("isVal", true)
defaultFalse("isVar", withGetter = true)
defaultNull("getter", "setter", "initializer", "delegate", "receiverTypeRef", "delegateFieldSymbol", withGetter = true)
}
impl(valueParameter, "FirDefaultSetterValueParameter") {
default("name", "Name.identifier(\"value\")")
defaultNull("defaultValue", "initializer", "delegate", "receiverTypeRef", "delegateFieldSymbol", "getter", "setter")
defaultFalse("isCrossinline", "isNoinline", "isVararg", "isVar")
defaultTrue("isVal")
}
impl(simpleFunction) {
kind = OpenClass
parents += modifiableFunction.withArg(simpleFunction)
parents += modifiableTypeParametersOwner
defaultNull("body")
}
impl(delegatedTypeRef) {
listOf("psi", "annotations").forEach {
default(it) {
delegate = "typeRef"
}
}
}
noImpl(userTypeRef)
}
private fun findImplementationsWithAnnotations(implementationPredicate: (Implementation) -> Boolean): Collection<Implementation> {
return FirTreeBuilder.elements.flatMap { it.allImplementations }.mapNotNullTo(mutableSetOf()) {
if (!implementationPredicate(it)) return@mapNotNullTo null
var hasAnnotations = false
if (it.element == FirTreeBuilder.annotationContainer) return@mapNotNullTo null
it.element.traverseParents {
if (it == FirTreeBuilder.annotationContainer) {
hasAnnotations = true
}
}
it.takeIf { hasAnnotations }
}
}
private fun configureAllImplementations() {
configureFieldInAllImplementations("controlFlowGraphReference") {
default(it, "FirEmptyControlFlowGraphReference()")
useTypes(emptyCfgReferenceType)
}
configureFieldInAllImplementations(
field = "typeRef",
implementationPredicate = { it.type !in listOf("FirDelegatedTypeRefImpl", "FirTypeProjectionWithVarianceImpl") },
fieldPredicate = { it.defaultValue == null }
) {
default(it, "FirImplicitTypeRefImpl(null)")
useTypes(implicitTypeRefType)
}
configureFieldInAllImplementations(
field = "resolvePhase",
fieldPredicate = { it.defaultValue == null }
) {
default(it, "FirResolvePhase.RAW_FIR")
}
configureFieldInAllImplementations(
field = "containerSource"
) {
default(it) {
value = "null"
isMutable = true
}
}
findImplementationsWithAnnotations {
it.type !in setOf("FirDelegatedTypeRefImpl", "FirImplicitTypeRefImpl")
}.forEach {
it.addParent(abstractAnnotatedElement)
}
}
}
@@ -0,0 +1,94 @@
/*
* 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
fun main(args: Array<String>) {
val generationPath = args.firstOrNull()?.let { if (!it.endsWith("/")) "$it/" else it }
if (generationPath == null) {
println("Not enough arguments")
return
}
NodeConfigurator.configureFields()
detectBaseTransformerTypes(FirTreeBuilder)
ImplementationConfigurator.configureImplementations()
removePreviousGeneratedFiles(generationPath)
printElements(FirTreeBuilder, generationPath)
// printTable(FirTreeBuilder)
}
fun Element.traverseParents(block: (Element) -> Unit) {
block(this)
parents.forEach { it.traverseParents(block) }
}
private fun detectBaseTransformerTypes(builder: AbstractFirTreeBuilder) {
val usedAsFieldType = mutableMapOf<AbstractElement, Boolean>().withDefault { false }
for (element in builder.elements) {
for (field in element.allFirFields) {
val fieldElement = when (field) {
is FirField -> field.element
is FieldList -> field.baseType as Element
else -> throw IllegalArgumentException()
}
usedAsFieldType[fieldElement] = true
}
}
for (element in builder.elements) {
element.traverseParents {
if (usedAsFieldType.getValue(it)) {
element.baseTransformerType = it
return@traverseParents
}
}
}
}
private fun removePreviousGeneratedFiles(generationPath: String) {
File(generationPath).walkTopDown().forEach {
if (it.isFile && it.readText().contains(GENERATED_MESSAGE)) {
it.delete()
}
}
}
private fun printTable(builder: AbstractFirTreeBuilder) {
val elements = builder.elements.filter { it.allImplementations.isNotEmpty() }
val fields = elements.flatMapTo(mutableSetOf()) { it.allFields }
val mapping = mutableMapOf<Element, Set<Field>>()
val fieldsCount = mutableMapOf<Field, Int>()
for (element in elements) {
val containingFields = mutableSetOf<Field>()
for (field in fields) {
if (field in element.allFields) {
containingFields += field
fieldsCount[field] = fieldsCount.getOrDefault(field, 0) + 1
}
}
mapping[element] = containingFields
}
val sortedFields = fields.sortedByDescending { fieldsCount[it] }
File("compiler/fir/tree/table.csv").printWriter().use { printer ->
with(printer) {
val delim = ","
print(delim)
println(sortedFields.joinToString(delim) { "${it.name}:${fieldsCount.getValue(it)}" })
for (element in elements) {
print(element.name + delim)
val containingFields = mapping.getValue(element)
println(sortedFields.joinToString(delim) { if (it in containingFields) "+" else "-" })
}
}
}
}
@@ -0,0 +1,517 @@
/*
* 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.FieldSets.annotations
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.arguments
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.body
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.calleeReference
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.classKind
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.controlFlowGraphReferenceField
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.declarations
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.initializer
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.modality
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.name
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.receivers
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.returnTypeRef
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.status
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.superTypeRefs
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.symbol
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.symbolWithPackage
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.typeArguments
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.typeParameters
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.typeRefField
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.valueParameters
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.visibility
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFieldConfigurator
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.model.*
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
object NodeConfigurator : AbstractFieldConfigurator() {
fun configureFields() = with(FirTreeBuilder) {
AbstractFirTreeBuilder.baseFirElement.configure {
+field("psi", psiElementType, nullable = true)
}
annotationContainer.configure {
+annotations
}
symbolOwner.configure {
withArg("E", symbolOwner, declaration)
+symbolWithPackage("fir.symbols", "AbstractFirBasedSymbol", "E")
}
controlFlowGraphOwner.configure {
+controlFlowGraphReferenceField.withTransform()
}
typeParametersOwner.configure {
+typeParameters
}
resolvable.configure {
+field("calleeReference", reference).withTransform()
}
declaration.configure {
+field("session", firSessionType)
+field("resolvePhase", resolvePhaseType, withReplace = true).apply { isMutable = true }
}
typedDeclaration.configure {
+field("returnTypeRef", typeRef).withTransform()
}
callableDeclaration.configure {
withArg("F", "FirCallableDeclaration<F>")
parentArg(symbolOwner, "E", "F")
+field("receiverTypeRef", typeRef, nullable = true)
+symbol("FirCallableSymbol", "F")
}
callableMemberDeclaration.configure {
withArg("F", "FirCallableMemberDeclaration<F>")
parentArg(callableDeclaration, "F", "F")
+field("containerSource", type(DeserializedContainerSource::class), nullable = true)
}
namedDeclaration.configure {
+name
}
function.configure {
withArg("F", "FirFunction<F>")
parentArg(callableDeclaration, "F", "F")
+symbol("FirFunctionSymbol", "F")
+valueParameters.withTransform()
+body(nullable = true)
}
errorFunction.configure {
parentArg(function, "F", errorFunction)
+stringField("reason")
+symbol("FirErrorFunctionSymbol")
}
memberDeclaration.configure {
+typeParameters
+status
}
expression.configure {
+typeRefField
+annotations
}
call.configure {
+arguments.withTransform()
}
block.configure {
+fieldList(statement)
+typeRefField
}
binaryLogicExpression.configure {
+field("leftOperand", expression).withTransform()
+field("rightOperand", expression).withTransform()
+field("kind", operationKindType)
needTransformOtherChildren()
}
jump.configure {
withArg("E", targetElement)
+field("target", jumpTargetType.withArgs("E"))
}
loopJump.configure {
parentArg(jump, "E", loop)
}
returnExpression.configure {
parentArg(jump, "E", function.withArgs("F" to "*"))
+field("result", expression)
}
label.configure {
+stringField("name")
}
loop.configure {
+field(block).withTransform()
+field("condition", expression).withTransform()
+field(label, nullable = true)
needTransformOtherChildren()
}
whileLoop.configure {
+field("condition", expression).withTransform()
+field(block).withTransform()
}
catchClause.configure {
+field("parameter", valueParameter).withTransform()
+field(block).withTransform()
needTransformOtherChildren()
}
tryExpression.configure {
+field("tryBlock", block).withTransform()
+fieldList("catches", catchClause).withTransform()
+field("finallyBlock", block, nullable = true).withTransform()
needTransformOtherChildren()
}
qualifiedAccessWithoutCallee.configure {
+booleanField("safe")
+receivers
}
constExpression.configure {
withArg("T")
+field("kind", constKindType.withArgs("T"))
+field("value", "T", null)
}
functionCall.configure {
+typeArguments
+field("calleeReference", namedReference)
}
operatorCall.configure {
+field("operation", operationType)
}
typeOperatorCall.configure {
+field("operation", operationType)
+field("conversionTypeRef", typeRef)
}
whenBranch.configure {
+field("condition", expression).withTransform()
+field("result", block).withTransform()
needTransformOtherChildren()
}
klass.configure {
+classKind
+superTypeRefs(withReplace = true)
+declarations
+annotations
}
classLikeDeclaration.configure {
withArg("F", "FirClassLikeDeclaration<F>")
parentArg(symbolOwner, "F", "F")
+field("supertypesComputationStatus", type("fir.declarations", "SupertypesComputationStatus"), withReplace = true).apply { isMutable = true }
+symbol("FirClassLikeSymbol", "F")
}
regularClass.configure {
parentArg(classLikeDeclaration, "F", regularClass)
+symbol("FirClassSymbol")
+field("companionObject", regularClass, nullable = true)
+superTypeRefs(withReplace = true)
}
typeAlias.configure {
parentArg(classLikeDeclaration, "F", typeAlias)
+symbol("FirTypeAliasSymbol")
+field("expandedTypeRef", typeRef, withReplace = true)
+annotations
}
enumEntry.configure {
+arguments.withTransform()
+field(typeRef)
}
anonymousFunction.configure {
parentArg(function, "F", anonymousFunction)
+symbol("FirAnonymousFunctionSymbol")
+field(label, nullable = true)
+field(invocationKindType, nullable = true, withReplace = true).apply {
isMutable = true
}
}
typeParameter.configure {
parentArg(symbolOwner, "F", typeParameter)
+symbol("FirTypeParameterSymbol")
+field(varianceType)
+booleanField("isReified")
+fieldList("bounds", typeRef)
+annotations
}
memberFunction.configure {
withArg("F", memberFunction)
parentArg(function, "F", "F")
parentArg(callableMemberDeclaration, "F", "F")
+symbol("FirFunctionSymbol", "F")
+annotations
}
simpleFunction.configure {
parentArg(memberFunction, "F", simpleFunction)
}
property.configure {
parentArg(variable, "F", property)
parentArg(callableMemberDeclaration, "F", property)
+symbol("FirPropertySymbol")
+field("backingFieldSymbol", backingFieldSymbolType)
+booleanField("isLocal")
+typeParameters
+status
}
propertyAccessor.configure {
parentArg(function, "F", propertyAccessor)
+symbol("FirPropertyAccessorSymbol")
+booleanField("isGetter")
+booleanField("isSetter")
+status
+annotations
}
declarationStatus.configure {
+visibility
+modality
generateBooleanFields(
"expect", "actual", "override", "operator", "infix", "inline", "tailRec",
"external", "const", "lateInit", "inner", "companion", "data", "suspend", "static"
)
}
constructor.configure {
parentArg(memberFunction, "F", constructor)
+symbol("FirConstructorSymbol")
+field("delegatedConstructor", delegatedConstructorCall, nullable = true)
+booleanField("isPrimary")
}
delegatedConstructorCall.configure {
+field("constructedTypeRef", typeRef)
generateBooleanFields("this", "super")
+calleeReference.withTransform()
}
valueParameter.configure {
parentArg(variable, "F", valueParameter)
+field("defaultValue", expression, nullable = true)
generateBooleanFields("crossinline", "noinline", "vararg")
}
variable.configure {
withArg("F", variable)
parentArg(callableDeclaration, "F", "F")
+symbol("FirVariableSymbol", "F")
+initializer
+field("delegate", expression, nullable = true)
+field("delegateFieldSymbol", delegateFieldSymbolType, "F", nullable = true)
generateBooleanFields("var", "val")
+field("getter", propertyAccessor, nullable = true).withTransform()
+field("setter", propertyAccessor, nullable = true).withTransform()
+annotations
needTransformOtherChildren()
}
field.configure {
parentArg(variable, "F", field)
parentArg(callableMemberDeclaration, "F", field)
}
anonymousInitializer.configure {
+body(nullable = true)
}
file.configure {
+fieldList(import)
+declarations
+stringField("name")
+field("packageFqName", fqNameType)
}
import.configure {
+field("importedFqName", fqNameType, nullable = true)
+booleanField("isAllUnder")
+field("aliasName", nameType, nullable = true)
}
resolvedImport.configure {
+field("delegate", import)
+field("packageFqName", fqNameType)
+field("relativeClassName", fqNameType, nullable = true)
+field("resolvedClassId", classIdType, nullable = true)
+field(
"importedName",
nameType,
nullable = true
)
}
annotationCall.configure {
+field("useSiteTarget", annotationUseSiteTargetType, nullable = true)
+field("annotationTypeRef", typeRef)
}
arraySetCall.configure {
+field("rValue", expression).withTransform()
+field("operation", operationType)
+field("lValue", reference)
+fieldList("indexes", expression).withTransform()
}
classReferenceExpression.configure {
+field("classTypeRef", typeRef)
}
componentCall.configure {
+field("explicitReceiver", expression)
+intField("componentIndex")
}
errorExpression.configure {
+stringField("reason")
}
expressionWithSmartcast.configure {
+field("originalExpression", qualifiedAccessExpression)
+field("typesFromSmartcast", "Collection<ConeKotlinType>", null, customType = coneKotlinTypeType)
+field("originalType", typeRef)
}
getClassCall.configure {
+field("argument", expression)
}
wrappedArgumentExpression.configure {
+booleanField("isSpread")
}
namedArgumentExpression.configure {
+name
}
resolvedQualifier.configure {
+field("packageFqName", fqNameType)
+field("relativeClassFqName", fqNameType, nullable = true)
+field("classId", classIdType, nullable = true)
}
stringConcatenationCall.configure {
}
throwExpression.configure {
+field("exception", expression)
}
variableAssignment.configure {
+field("lValue", reference)
+field("rValue", expression).withTransform()
+field("operation", operationType)
}
whenSubjectExpression.configure {
+field("whenSubject", whenSubjectType)
}
wrappedExpression.configure {
+field(expression)
}
wrappedDelegateExpression.configure {
+field("delegateProvider", expression)
}
namedReference.configure {
+name
+field("candidateSymbol", abstractFirBasedSymbolType, "*", nullable = true)
}
resolvedCallableReference.configure {
+field("resolvedSymbol", abstractFirBasedSymbolType, "*")
}
delegateFieldReference.configure {
+field("resolvedSymbol", delegateFieldSymbolType.withArgs("*"))
}
backingFieldReference.configure {
+field("resolvedSymbol", backingFieldSymbolType)
}
superReference.configure {
+field("superTypeRef", typeRef, withReplace = true)
}
thisReference.configure {
+stringField("labelName", nullable = true)
+field("boundSymbol", abstractFirBasedSymbolType, "*", nullable = true, withReplace = true)
}
typeRef.configure {
+annotations
}
resolvedTypeRef.configure {
+field("type", coneKotlinTypeType)
}
errorTypeRef.configure {
+stringField("reason")
}
delegatedTypeRef.configure {
+field("delegate", expression, nullable = true)
+field(typeRef)
}
typeRefWithNullability.configure {
+booleanField("isMarkedNullable")
}
userTypeRef.configure {
+fieldList("qualifier", firQualifierPartType)
}
functionTypeRef.configure {
+field("receiverTypeRef", typeRef, nullable = true)
+valueParameters
+returnTypeRef
}
thisReceiverExpression.configure {
+field("calleeReference", thisReference)
}
whenExpression.configure {
+field("subject", expression, nullable = true).withTransform()
+field("subjectVariable", variable.withArgs("F" to "*"), nullable = true)
+fieldList("branches", whenBranch).withTransform()
needTransformOtherChildren()
}
typeProjectionWithVariance.configure {
+field(typeRef)
+field(varianceType)
}
errorNamedReference.configure {
+stringField("errorReason")
}
}
}
private fun Element.withArgs(vararg replacements: Pair<String, String>): AbstractElement {
val replaceMap = replacements.toMap()
val newArguments = typeArguments.map { replaceMap[it.name]?.let { SimpleTypeArgument(it, null) } ?: it }
return ElementWithArguments(this, newArguments)
}
@@ -0,0 +1,725 @@
/*
* 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.*
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: String) {
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<Element>, generationPath: String) {
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<out R, in D> {")
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<Element>, generationPath: String) {
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<Unit, Nothing?>() {")
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: String) {
val dir = File(generationPath + 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: String) {
val dir = File(generationPath + 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)
}
}
}
fun Implementation.collectImports(): List<String> {
return element.collectImportsInternal(
listOf(element.fullQualifiedName) + usedTypes.mapNotNull { it.fullQualifiedName } + parents.mapNotNull { it.fullQualifiedName },
isImpl = true
)
}
fun Element.collectImports(): List<String> {
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!!
}
return collectImportsInternal(
baseTypes,
isImpl = false
)
}
fun Element.collectImportsInternal(base: List<String>, isImpl: Boolean): List<String> {
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 }
if (kind != Implementation.Kind.Interface && fieldsWithoutDefault.isNotEmpty()) {
println("(")
fieldsWithoutDefault.forEachIndexed { i, field ->
val end = if (i == fieldsWithoutDefault.size - 1) "" else ","
printField(field, isImplementation = true, override = true, end = end)
}
print(")")
}
print(" : ${element.typeWithArguments}")
parents.forEach {
print(", ${it.typeWithArguments}")
}
println(" {")
if (kind == Implementation.Kind.Interface) {
allFields.forEach { printField(it, isImplementation = true, override = true, end = "") }
} else {
fieldsWithDefault.forEach {
printFieldWithDefaultInImplementation(it)
}
if (fieldsWithDefault.isNotEmpty()) {
println()
}
}
element.allFields.filter { it.type.contains("Symbol") }
.takeIf { it.isNotEmpty() && kind != Implementation.Kind.Interface && !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()
}
indent(1)
print("override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {")
fun Field.acceptString(): String = "${name}${call()}accept(visitor, data)"
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 == "FirClassImpl" && 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()
println("override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): $typeWithArguments {")
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 == "FirClassImpl" && 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<FirRegularClass>().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("}")
for (field in allFields) {
if (!field.needsSeparateTransform) continue
println()
indent()
print("override ${field.transformFunctionDeclaration(typeWithArguments)} {")
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()
println("override fun <D> transformOtherChildren(transformer: FirTransformer<D>, data: D): $typeWithArguments {")
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()
print("override ${field.replaceFunctionDeclaration()} {")
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("}")
}
print("}")
}
}
fun Field.transformFunctionDeclaration(returnType: String): String {
return transformFunctionDeclaration(name.capitalize(), returnType)
}
fun transformFunctionDeclaration(transformName: String, returnType: String): String {
return "fun <D> transform$transformName(transformer: FirTransformer<D>, data: D): $returnType"
}
fun Field.replaceFunctionDeclaration(): String {
val capName = name.capitalize()
return "fun replace$capName(new$capName: $typeWithArgumentsWithoutNullablity)"
}
fun printTransformer(elements: List<Element>, generationPath: String) {
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<in D> : FirVisitor<CompositeTransformResult<FirElement>, D>() {")
println()
indent()
println("abstract fun <E : FirElement> transformElement(element: E, data: D): CompositeTransformResult<E>")
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) {
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<TypeArgumentWithMultipleUpperBounds>().takeIf { it.isNotEmpty() }?.let { arguments ->
val upperBoundsList = arguments.joinToString(", ", postfix = " ") { argument ->
argument.upperBounds.joinToString(", ") { upperBound -> "${argument.name} : ${upperBound.typeWithArguments}" }
}
" where $upperBoundsList"
} ?: " "
}
fun PrintWriter.printElement(element: Element) {
fun Element.override() {
indent()
if (this != AbstractFirTreeBuilder.baseFirElement) {
print("override ")
}
}
with(element) {
print("interface $type")
if (typeArguments.isNotEmpty()) {
print(typeArguments.joinToString(", ", "<", ">") { it.toString() })
}
if (parents.isNotEmpty()) {
print(" : ")
print(parents.joinToString(", ") {
var result = it.type
parentsArguments[it]?.let { arguments ->
result += arguments.values.joinToString(", ", "<", ">") { it.typeWithArguments }
}
result
})
}
print(multipleUpperBoundsList())
println("{")
allFields.forEach {
printField(it, isImplementation = false, override = it.fromParent, end = "")
}
if (allFields.isNotEmpty()) {
println()
}
override()
println("fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visit$name(this, data)")
fields.filter { it.withReplace }.forEach {
println()
indent()
if (it.fromParent) print("override ")
println(it.replaceFunctionDeclaration())
}
for (field in allFields) {
if (!field.needsSeparateTransform) continue
println()
indent()
if (field.fromParent) {
print("override ")
}
println(field.transformFunctionDeclaration(typeWithArguments))
}
if (needTransformOtherChildren) {
println()
indent()
if (element.parents.any { it.needTransformOtherChildren }) {
print("override ")
}
println(transformFunctionDeclaration("OtherChildren", typeWithArguments))
}
if (element == AbstractFirTreeBuilder.baseFirElement) {
println()
indent()
println("fun accept(visitor: FirVisitorVoid) = accept(visitor, null)")
println()
indent()
println("fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D)")
println()
indent()
println("fun acceptChildren(visitor: FirVisitorVoid) = acceptChildren(visitor, null)")
println()
indent()
println("@Suppress(\"UNCHECKED_CAST\")")
indent()
println("fun <E : FirElement, D> transform(visitor: FirTransformer<D>, data: D): CompositeTransformResult<E> =")
indent(2)
println("accept(visitor, data) as CompositeTransformResult<E>")
println()
indent()
println("fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement")
}
print("}")
}
}
// --------------------------------------- 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(",", "<", ">") ?: ""
@@ -0,0 +1,61 @@
/*
* 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 com.intellij.psi.PsiElement
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.tree.generator.context.generatedType
import org.jetbrains.kotlin.fir.tree.generator.context.type
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
val psiElementType = type(PsiElement::class)
val jumpTargetType = type("fir", "FirTarget")
val constKindType = type(IrConstKind::class)
val operationType = type("fir.expressions", "FirOperation")
val classKindType = type(ClassKind::class)
val invocationKindType = type(InvocationKind::class)
val varianceType = type(Variance::class)
val nameType = type(Name::class)
val visibilityType = type(Visibility::class)
val visibilitiesType = type(Visibilities::class)
val modalityType = type(Modality::class)
val fqNameType = type(FqName::class)
val classIdType = type(ClassId::class)
val annotationUseSiteTargetType = type(AnnotationUseSiteTarget::class)
val operationKindType = type("fir.expressions", "LogicOperationKind")
val coneKotlinTypeType = type(ConeKotlinType::class)
val whenSubjectType = type("fir", "FirWhenSubject")
val firSessionType = type("fir", "FirSession")
val emptyCfgReferenceType = generatedType("references.impl", "FirEmptyControlFlowGraphReference")
val noReceiverExpressionType = generatedType("expressions.impl", "FirNoReceiverExpression")
val implicitTypeRefType = generatedType("types.impl", "FirImplicitTypeRefImpl")
val firQualifierPartType = type("fir.types", "FirQualifierPart")
val coneClassErrorTypeType = type(ConeClassErrorType::class)
val simpleNamedReferenceType = generatedType("references.impl", "FirSimpleNamedReference")
val explicitThisReferenceType = generatedType("references.impl", "FirExplicitThisReference")
val explicitSuperReferenceType = generatedType("references.impl", "FirExplicitSuperReference")
val implicitBooleanTypeRefType = generatedType("types.impl", "FirImplicitBooleanTypeRef")
val implicitNothingTypeRefType = generatedType("types.impl", "FirImplicitNothingTypeRef")
val implicitStringTypeRefType = generatedType("types.impl", "FirImplicitStringTypeRef")
val implicitUnitTypeRefType = generatedType("types.impl", "FirImplicitUnitTypeRef")
val resolvePhaseType = type("fir.declarations", "FirResolvePhase")
val stubReferenceType = generatedType("references.impl", "FirStubReference")
val compositeTransformResultType = type("fir.visitors", "CompositeTransformResult")
val abstractFirBasedSymbolType = type("fir.symbols", "AbstractFirBasedSymbol")
val backingFieldSymbolType = type("fir.symbols.impl", "FirBackingFieldSymbol")
val delegateFieldSymbolType = type("fir.symbols.impl", "FirDelegateFieldSymbol")
@@ -0,0 +1,80 @@
/*
* 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.context
import org.jetbrains.kotlin.fir.tree.generator.model.*
abstract class AbstractFieldConfigurator {
inner class ConfigureContext(val element: Element) {
operator fun FieldSet.unaryPlus() {
element.fields.addAll(this.map { it.copy() })
}
operator fun Field.unaryPlus() {
val doesNotContains = element.fields.add(this.copy())
require(doesNotContains) {
"$element already contains field $this}"
}
}
fun generateBooleanFields(vararg names: String) {
names.forEach {
+booleanField("is${it.capitalize()}")
}
}
fun withArg(name: String, vararg upperBounds: String) {
withArg(name, upperBounds.map { Type(null, it) })
}
fun withArg(name: String, upperBound: Importable, vararg upperBounds: Importable) {
val allUpperBounds = mutableListOf(upperBound).apply { this += upperBounds }
withArg(name, allUpperBounds)
}
private fun withArg(name: String, upperBounds: List<Importable>) {
element.typeArguments += when (upperBounds.size) {
in 0..1 -> SimpleTypeArgument(name, upperBounds.firstOrNull())
else -> TypeArgumentWithMultipleUpperBounds(name, upperBounds.toList())
}
}
fun parentArg(parent: Element, argument: String, type: String) {
parentArg(parent, Type(null, argument), Type(null, type))
}
fun parentArg(parent: Element, argument: String, type: Importable) {
parentArg(parent, Type(null, argument), type)
}
fun parentArg(parent: Element, argument: Importable, type: Importable) {
require(parent in element.parents) {
"$parent is not parent of $element"
}
val argMap = element.parentsArguments.getOrPut(parent) { mutableMapOf() }
require(argument !in argMap) {
"Argument $argument already defined for parent $parent of $element"
}
argMap[argument] = type
}
fun Type.withArgs(vararg args: Importable): Pair<Type, List<Importable>> {
return this to args.toList()
}
fun Type.withArgs(vararg args: String): Pair<Type, List<Importable>> {
return this to args.map { Type(null, it) }
}
fun needTransformOtherChildren() {
element._needTransformOtherChildren = true
}
}
inline fun Element.configure(block: ConfigureContext.() -> Unit) {
ConfigureContext(this).block()
}
}
@@ -0,0 +1,55 @@
/*
* 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.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 kotlin.reflect.KClass
abstract class AbstractFirTreeBuilder {
companion object {
val baseFirElement = Element(
"Element",
Element.Kind.Other
)
const val string = "String"
const val boolean = "Boolean"
const val int = "Int"
}
val elements = mutableListOf(baseFirElement)
protected fun element(name: String, kind: Element.Kind, vararg dependencies: Element, init: Element.() -> Unit = {}): Element =
Element(name, kind).apply(init).also {
if (dependencies.isEmpty()) {
it.parents.add(baseFirElement)
}
it.parents.addAll(dependencies)
elements += it
}
}
fun generatedType(type: String): Type = generatedType("", type)
fun generatedType(packageName: String, type: String): Type {
val realPackage = BASE_PACKAGE + if (packageName.isNotBlank()) ".$packageName" else ""
return type(realPackage, type, exactPackage = true)
}
fun type(packageName: String?, type: String, exactPackage: Boolean = false): Type {
val realPackage = if (exactPackage) packageName else packageName?.let { "org.jetbrains.kotlin.$it" }
return Type(realPackage, type)
}
fun type(type: String): Type = type(null, type)
fun type(klass: KClass<*>): Type {
val fqn = klass.qualifiedName!!
val name = klass.simpleName!!
return type(fqn.dropLast(name.length + 1), name, exactPackage = true)
}
@@ -0,0 +1,235 @@
/*
* 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.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
abstract class AbstractFirTreeImplementationConfigurator {
private val elementsWithImpl = mutableSetOf<Element>()
fun noImpl(element: Element) {
element.doesNotNeedImplementation = true
}
fun impl(element: Element, name: String? = null, config: ImplementationContext.() -> Unit = {}): Implementation {
val implementation = if (name == null) {
element.defaultImplementation
} else {
element.customImplementations.firstOrNull { it.name == name }
} ?: Implementation(element, name)
val context = ImplementationContext(implementation)
context.apply(config)
implementation.updateMutabilityAccordingParents()
elementsWithImpl += element
return implementation
}
protected fun generateDefaultImplementations(builder: AbstractFirTreeBuilder) {
collectLeafsWithoutImplementation(builder).forEach {
impl(it)
}
}
protected fun configureFieldInAllImplementations(
field: String,
implementationPredicate: ((Implementation) -> Boolean)? = null,
fieldPredicate: ((Field) -> Boolean)? = null,
init: ImplementationContext.(field: String) -> Unit
) {
for (element in elementsWithImpl) {
for (implementation in element.allImplementations) {
if (implementationPredicate != null && !implementationPredicate(implementation)) continue
if (!implementation.allFields.any { it.name == field }) continue
if (fieldPredicate != null && !fieldPredicate(implementation.getField(field))) continue
ImplementationContext(implementation).init(field)
}
}
}
private fun collectLeafsWithoutImplementation(builder: AbstractFirTreeBuilder): Set<Element> {
val elements = builder.elements.toMutableSet()
builder.elements.forEach {
elements.removeAll(it.parents)
}
elements.removeAll(elementsWithImpl)
return elements
}
private fun Implementation.getField(name: String): FieldWithDefault {
val result = allFields.firstOrNull { it.name == name }
requireNotNull(result) {
"Field \"$name\" not found in fields of ${element}\nExisting fields:\n" +
allFields.joinToString(separator = "\n ", prefix = " ") { it.name }
}
return result
}
inner class ImplementationContext(private val implementation: Implementation) {
private fun getField(name: String): FieldWithDefault {
return implementation.getField(name)
}
inner class ParentsHolder {
operator fun plusAssign(parent: Implementation) {
implementation.addParent(parent)
}
operator fun plusAssign(parent: ImplementationWithArg) {
implementation.addParent(parent.implementation, parent.argument)
parent.argument?.let { useTypes(it) }
}
}
val parents = ParentsHolder()
fun Implementation.withArg(argument: Importable): ImplementationWithArg = ImplementationWithArg(this, argument)
fun useTypes(vararg types: Importable) {
types.forEach { implementation.usedTypes += it }
}
fun lateinit(vararg fields: String) {
for (fieldName in fields) {
val field = getField(fieldName)
require(field.origin !is FieldList)
field.isLateinit = true
field.isMutable = true
}
}
fun isMutable(vararg fields: String) {
fields.forEach {
val field = getField(it)
field.isMutable = true
}
}
fun defaultNoReceivers() {
defaultNull("explicitReceiver")
default("dispatchReceiver", "FirNoReceiverExpression")
default("extensionReceiver", "FirNoReceiverExpression")
useTypes(noReceiverExpressionType)
}
fun default(field: String, value: String) {
default(field) {
this.value = value
}
}
fun defaultTrue(field: String, withGetter: Boolean = false) {
default(field) {
value = "true"
this.withGetter = withGetter
}
}
fun defaultFalse(vararg fields: String, withGetter: Boolean = false) {
for (field in fields) {
default(field) {
value = "false"
this.withGetter = withGetter
}
}
}
fun defaultNull(vararg fields: String, withGetter: Boolean = false) {
for (field in fields) {
default(field) {
value = "null"
this.withGetter = withGetter
}
require(getField(field).nullable) {
"$field is not nullable field"
}
}
}
fun noPsi() {
defaultNull("psi")
}
fun defaultEmptyList(field: String) {
require(getField(field).origin is FieldList) {
"$field is list field"
}
default(field) {
value = "emptyList()"
withGetter = true
}
}
fun defaultSupertypesComputationStatus() {
default("supertypesComputationStatus", "SupertypesComputationStatus.NOT_COMPUTED")
}
fun default(field: String, init: DefaultValueContext.() -> Unit) {
DefaultValueContext(getField(field)).apply(init).applyConfiguration()
}
fun delegateFields(fields: List<String>, delegate: String) {
for (field in fields) {
default(field) {
this.delegate = delegate
}
}
}
var kind: Implementation.Kind
get() = implementation.kind
set(value) {
implementation.kind = value
}
inner class DefaultValueContext(private val field: FieldWithDefault) {
var value: String? = null
var delegate: String? = null
set(value) {
field = value
if (value != null) {
withGetter = true
}
}
var delegateCall: String? = null
var isMutable: Boolean? = null
var withGetter: Boolean = false
set(value) {
field = value
if (value) {
isMutable = customSetter != null
}
}
var customSetter: String? = null
set(value) {
field = value
isMutable = true
withGetter = true
}
var needAcceptAndTransform: Boolean = true
fun applyConfiguration() {
field.withGetter = withGetter
field.customSetter = customSetter
isMutable?.let { field.isMutable = it }
field.needAcceptAndTransform = needAcceptAndTransform
when {
value != null -> field.defaultValue = value
delegate != null -> {
val actualDelegateField = getField(delegate!!)
val name = delegateCall ?: field.name
field.defaultValue = "${actualDelegateField.name}${actualDelegateField.call()}$name"
}
}
}
}
}
}
@@ -0,0 +1,147 @@
/*
* 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.model
import org.jetbrains.kotlin.fir.tree.generator.BASE_PACKAGE
import org.jetbrains.kotlin.fir.tree.generator.typeWithArguments
interface FieldContainer {
val allFields: List<Field>
operator fun get(fieldName: String): Field?
}
interface AbstractElement : FieldContainer, Importable {
val fields: Set<Field>
val parents: List<AbstractElement>
val typeArguments: List<TypeArgument>
val parentsArguments: Map<AbstractElement, Map<Importable, Importable>>
val baseTransformerType: AbstractElement?
val transformerType: AbstractElement
val doesNotNeedImplementation: Boolean
val needTransformOtherChildren: Boolean
val allImplementations: List<Implementation>
val allFirFields: List<Field>
val defaultImplementation: Implementation?
val customImplementations: List<Implementation>
}
class Element(val name: String, kind: Kind) : AbstractElement {
override val fields = mutableSetOf<Field>()
override val type: String = "Fir$name"
override val packageName: String = BASE_PACKAGE + kind.packageName.let { if (it.isBlank()) it else "." + it }
override val fullQualifiedName: String get() = super.fullQualifiedName!!
override val parents = mutableListOf<Element>()
override var defaultImplementation: Implementation? = null
override val customImplementations = mutableListOf<Implementation>()
override val typeArguments = mutableListOf<TypeArgument>()
override val parentsArguments = mutableMapOf<AbstractElement, MutableMap<Importable, Importable>>()
var _needTransformOtherChildren: Boolean = false
override var baseTransformerType: Element? = null
override val transformerType: Element get() = baseTransformerType ?: this
override var doesNotNeedImplementation: Boolean = false
override val needTransformOtherChildren: Boolean get() = _needTransformOtherChildren || parents.any { it.needTransformOtherChildren }
override val allImplementations: List<Implementation> by lazy {
if (doesNotNeedImplementation) {
emptyList<Implementation>()
} else {
val implementations = customImplementations.toMutableList()
defaultImplementation?.let { implementations += it }
implementations
}
}
override val allFields: List<Field> by lazy {
val result = LinkedHashSet<Field>()
result.addAll(fields.toList().asReversed())
for (field in parentFields.asReversed()) {
val overrides = !result.add(field)
if (overrides) {
val existingField = result.first { it == field }
if (field.name != "symbol" && field.type == existingField.type) println("Duplicate [element: $this, field: $field]")
existingField.fromParent = true
existingField.needsSeparateTransform = existingField.needsSeparateTransform || field.needsSeparateTransform
}
}
result.toList().asReversed()
}
val parentFields: List<Field> by lazy {
val result = LinkedHashSet<Field>()
parents.forEach { parent ->
val fields = parent.allFields.map { field ->
val copy = (field as? SimpleField)?.let { simpleField ->
parentsArguments[parent]?.get(Type(null, simpleField.type))?.let {
simpleField.replaceType(Type(it.packageName, it.type))
}
} ?: field.copy()
copy.apply {
arguments.replaceAll {
parentsArguments[parent]?.get(it) ?: it
}
fromParent = true
}
}
result.addAll(fields)
}
result.toList()
}
override val allFirFields: List<Field> by lazy {
allFields.filter { it.isFirType }
}
override fun toString(): String {
return typeWithArguments
}
override fun get(fieldName: String): Field? {
return allFields.firstOrNull { it.name == fieldName }
}
enum class Kind(val packageName: String) {
Expression("expressions"),
Declaration("declarations"),
Reference("references"),
TypeRef("types"),
Other("")
}
}
class ElementWithArguments(val element: Element, override val typeArguments: List<TypeArgument>) : AbstractElement by element {
override fun equals(other: Any?): Boolean {
return element.equals(other)
}
override fun hashCode(): Int {
return element.hashCode()
}
}
sealed class TypeArgument(val name: String) {
abstract val upperBounds: List<Importable>
}
class SimpleTypeArgument(name: String, val upperBound: Importable?) : TypeArgument(name) {
override val upperBounds: List<Importable> = listOfNotNull(upperBound)
override fun toString(): String {
var result = name
if (upperBound != null) {
result += " : ${upperBound.typeWithArguments}"
}
return result
}
}
class TypeArgumentWithMultipleUpperBounds(name: String, override val upperBounds: List<Importable>) : TypeArgument(name) {
override fun toString(): String {
return name
}
}
@@ -0,0 +1,92 @@
/*
* 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.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
// ----------- Simple field -----------
fun field(name: String, type: String, packageName: String?, customType: Importable? = null, nullable: Boolean = false, withReplace: Boolean = false): Field {
return SimpleField(name, type, packageName, customType, nullable, withReplace)
}
fun field(name: String, type: Type, nullable: Boolean = false, withReplace: Boolean = false): Field {
return SimpleField(name, type.typeWithArguments, type.packageName, null, nullable, withReplace)
}
fun field(name: String, typeWithArgs: Pair<Type, List<Importable>>, nullable: Boolean = false, withReplace: Boolean = false): Field {
val (type, args) = typeWithArgs
return SimpleField(name, type.typeWithArguments, type.packageName, null, nullable, withReplace).apply {
arguments += args
}
}
fun field(type: Type, nullable: Boolean = false, withReplace: Boolean = false): Field {
return SimpleField(type.type.decapitalize(), type.typeWithArguments, type.packageName, null, nullable, withReplace)
}
fun booleanField(name: String): Field {
return field(name, AbstractFirTreeBuilder.boolean, null)
}
fun stringField(name: String, nullable: Boolean = false): Field {
return field(name, AbstractFirTreeBuilder.string, null, null, nullable)
}
fun intField(name: String): Field {
return field(name, AbstractFirTreeBuilder.int, null)
}
// ----------- Fir field -----------
fun field(name: String, type: Type, argument: String? = null, nullable: Boolean = false, withReplace: Boolean = false): Field {
return if (argument == null) {
field(name, type, nullable, withReplace)
} else {
field(name, type to listOf(type(argument)), nullable, withReplace)
}
}
fun field(name: String, element: AbstractElement, nullable: Boolean = false, withReplace: Boolean = false): Field {
return FirField(name, element, nullable, withReplace)
}
fun field(element: Element, nullable: Boolean = false, withReplace: Boolean = false): Field {
return FirField(element.name.decapitalize(), element, nullable, withReplace)
}
// ----------- Field list -----------
fun fieldList(name: String, type: Importable, withReplace: Boolean = false): Field {
return FieldList(name, type, withReplace)
}
fun fieldList(element: Element, withReplace: Boolean = false): Field {
return FieldList(element.name.decapitalize() + "s", element, withReplace)
}
// ----------- Field set -----------
typealias FieldSet = List<Field>
fun fieldSet(vararg fields: Field): FieldSet {
return fields.toList()
}
@JvmName("foo")
infix fun FieldSet.with(sets: List<FieldSet>): FieldSet {
return sets.flatten()
}
infix fun FieldSet.with(set: FieldSet): FieldSet {
return this + set
}
fun Field.withTransform(): Field = copy().apply { needsSeparateTransform = true }
fun FieldSet.withTransform(): FieldSet = this.map { it.withTransform() }
@@ -0,0 +1,181 @@
/*
* 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.model
import org.jetbrains.kotlin.fir.tree.generator.typeWithArguments
sealed class Field : Importable {
abstract val name: String
open val arguments = mutableListOf<Importable>()
abstract val nullable: Boolean
abstract val withReplace: Boolean
abstract val isFirType: Boolean
var fromParent: Boolean = false
open var needsSeparateTransform: Boolean = false
open val defaultValue: String? get() = null
abstract var isMutable: Boolean
open var isMutableInInterface: Boolean = false
open val withGetter: Boolean get() = false
open val isLateinit: Boolean get() = false
open val customSetter: String? get() = null
open val fromDelegate: Boolean get() = false
fun copy(): Field = internalCopy().also {
updateFieldsInCopy(it)
}
protected fun updateFieldsInCopy(copy: Field) {
copy.arguments.clear()
copy.arguments.addAll(arguments)
copy.needsSeparateTransform = needsSeparateTransform
copy.fromParent = fromParent
copy.isMutable = isMutable
}
protected abstract fun internalCopy(): Field
override fun toString(): String {
return name
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null) return false
if (javaClass != other.javaClass) return false
other as Field
return name == other.name
}
override fun hashCode(): Int {
return name.hashCode()
}
}
// ----------- Field with default -----------
class FieldWithDefault(val origin: Field) : Field() {
override val name: String get() = origin.name
override val type: String get() = origin.type
override val nullable: Boolean get() = origin.nullable
override val withReplace: Boolean get() = origin.withReplace
override val packageName: String? get() = origin.packageName
override val isFirType: Boolean get() = origin.isFirType
override var needsSeparateTransform: Boolean
get() = origin.needsSeparateTransform
set(_) {}
override val arguments: MutableList<Importable>
get() = origin.arguments
override var defaultValue: String? = origin.defaultValue
override var isMutable: Boolean = origin.isMutable
override var isMutableInInterface: Boolean = origin.isMutableInInterface
override var withGetter: Boolean = false
override var isLateinit: Boolean = false
override var customSetter: String? = null
override var fromDelegate: Boolean = false
var needAcceptAndTransform: Boolean = true
override fun internalCopy(): Field {
return FieldWithDefault(origin).also {
it.defaultValue = defaultValue
it.isMutable = isMutable
it.withGetter = withGetter
it.isLateinit = isLateinit
it.fromDelegate = fromDelegate
it.needAcceptAndTransform = needAcceptAndTransform
}
}
}
open class SimpleField(
override val name: String,
override val type: String,
override val packageName: String?,
val customType: Importable? = null,
override val nullable: Boolean,
override val withReplace: Boolean
) : Field() {
override val isFirType: Boolean = false
override val fullQualifiedName: String?
get() = customType?.fullQualifiedName ?: super.fullQualifiedName
override var isMutable: Boolean = false
override fun internalCopy(): Field {
return SimpleField(
name,
type,
packageName,
customType,
nullable,
withReplace
)
}
fun replaceType(newType: Type) = SimpleField(
name,
newType.type,
newType.packageName,
customType,
nullable,
withReplace
).also {
updateFieldsInCopy(it)
}
}
class FirField(
override val name: String,
val element: AbstractElement,
override val nullable: Boolean,
override val withReplace: Boolean
) : Field() {
override val type: String get() = element.type
override val packageName: String? get() = element.packageName
override val isFirType: Boolean = true
override var isMutable: Boolean = true
override fun internalCopy(): Field {
return FirField(
name,
element,
nullable,
withReplace
)
}
}
// ----------- Field list -----------
class FieldList(
override val name: String,
val baseType: Importable,
override val withReplace: Boolean
) : Field() {
override val defaultValue: String? get() = if (isMutable) "mutableListOf()" else "emptyListOf()"
override val packageName: String? get() = baseType.packageName
override val fullQualifiedName: String? get() = baseType.fullQualifiedName
override val type: String = "List<${baseType.typeWithArguments}>"
override val nullable: Boolean
get() = false
override var isMutable: Boolean = true
override fun internalCopy(): Field {
return FieldList(
name,
baseType,
withReplace
)
}
override val isFirType: Boolean = baseType is Element
}
@@ -0,0 +1,64 @@
/*
* 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.model
class ImplementationWithArg(
val implementation: Implementation,
val argument: Importable?
) : Importable by implementation, FieldContainer by implementation {
val element: Element get() = implementation.element
}
class Implementation(val element: Element, val name: String?) : Importable, FieldContainer {
private val _parents = mutableListOf<ImplementationWithArg>()
val parents: List<ImplementationWithArg> get() = _parents
val isDefault = name == null
override val type = name ?: element.type + "Impl"
override val allFields = element.allFields.toMutableList().mapTo(mutableListOf()) {
FieldWithDefault(it)
}
var kind: Kind = Kind.FinalClass
override val packageName = element.packageName + ".impl"
val usedTypes = mutableListOf<Importable>()
init {
if (isDefault) {
element.defaultImplementation = this
} else {
element.customImplementations += this
}
}
fun addParent(parent: Implementation, arg: Importable? = null) {
_parents += ImplementationWithArg(parent, arg)
}
override fun get(fieldName: String): FieldWithDefault? {
return allFields.firstOrNull { it.name == fieldName }
}
fun updateMutabilityAccordingParents() {
for (parent in parents) {
for (field in allFields) {
val fieldFromParent = parent[field.name] ?: continue
field.isMutable = field.isMutable || fieldFromParent.isMutable
if (field.isMutable && field.customSetter == null) {
field.withGetter = false
}
}
}
}
enum class Kind(val title: String) {
Interface("interface"),
FinalClass("class"),
OpenClass("open class"),
AbstractClass("abstract class"),
Object("object")
}
}
@@ -0,0 +1,12 @@
/*
* 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.model
interface Importable {
val type: String
val packageName: String?
val fullQualifiedName: String? get() = packageName?.let { "$it.${type.replace(Regex("<.+>"), "")}" }
}
@@ -0,0 +1,10 @@
/*
* 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.model
data class Type(override val packageName: String?, override val type: String) : Importable {
val arguments = mutableListOf<String>()
}