From 0c27b863b072a91a51b1b8d5ec3cf4d1c541f002 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 10 Oct 2019 15:44:27 +0300 Subject: [PATCH] [FIR] Add Readme for tree generator --- compiler/fir/tree/tree-generator/Readme.md | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 compiler/fir/tree/tree-generator/Readme.md diff --git a/compiler/fir/tree/tree-generator/Readme.md b/compiler/fir/tree/tree-generator/Readme.md new file mode 100644 index 00000000000..05abcacc0ef --- /dev/null +++ b/compiler/fir/tree/tree-generator/Readme.md @@ -0,0 +1,83 @@ +# Fir elements + +- All fir elements are listed in `FirTreeBuilder.kt` +- Syntax of new element declaration: `element(elementName, elementKind: Kind, vararg parents: Element)` + - `elementName` is a name of declared element. If `elementName = Foo` then it's type will be `FirFoo` + - kind describes target package for element. Avaliable kinds: + - `Expression` (package `fir.expression`) + - `Declaration` (package `fir.declaration`) + - `Reference` (package `fir.references`) + - `TypeRef` (package `fir.types`) + - `Other` (package `fir`) + - if no one parent element was not declaraed than generated element will be direct inheritor of `FirElement` + +# Types + +- All types, used in elements and their implementations are described with object of class `Type` +- `Type` objects are used for generating imports in generated files +- Types commonly used in configuration are listed in `Types.kt` +- There is multiple ways to describe new type: + - `type(klass: KClass<*>)` uses FQN of corresponding class + - `type(packageName: String, typeName: String, exactPackage: Boolean = false)` + - if `exactPackage = false` it's return type with default package prefix: `org.jetbrains.kotlin.packageName.typeName` + - otherwise there is no default prefix: `packageName.typeName` + - `type(typeName: String)` creates type with no package, used only for types of type parameters (**Do not use it directly**) + - `generatedType([packageName: String], typeName: String)` -- same as `type(packageName, typeName)` but with `org.jetbrains.kotlin.fir` prefix + +# Content of elements + +- Fields of elements are described in `NodeConfigurator.kt` +- Syntax: +``` +elementName.configure { + // node configuration +} +``` +- **Fields:** + - `Field` class describes field of element + - There is multiple ways of creating new fields, but they have similar syntax: `field(..., nullable: Boolean = false, withReplace: Boolean)` + - if `isNullable` is true then field type will be nullable + - if `withReplace` is true then in element will be generated method `replace...` for that field + - in place of `...` you can pass optional name (with `String` type) and `Type` or `Element` object + - if no `name` passed then it will be generated based on type + - if `Type` or `Element` has type argumetns you want to specify then you can call method `Type.withArgs(vararg types: String)` or `Element.withArgs(vararg replacements: Pair)` + - Also you can create fields with lists of some types + - Lists can holds only fir element + - Syntax: `fieldList([name: String], element: Element)` (if name no specified it will be generated based on type of `element`) + - And there are helper functions for fields of primitive types that takes name of field: `booleanField`, `intField`, `stringField` + - If you want generate `transform...` function for field you should call method `withTransform()` on it + - To add field to configuring node you should call infix `+` operator: `+fieldList("catches", catchClause).withTransform()` + - Also you can use method `symbol(symbolTypeName: String, [argument: String])` to create field named `symbol` with type lying in `org.jetbrains.kotlin.fir.symbols` package + - Some predefined fields are listed in `FieldSets.kt` +- If your node has some `tansform...` methods and you want to add methods for transforming all other children you should call `needTransformOtherChildren()` +- If your element has type parameters you should declare them using method `withArg(typeParameterName: String, [upperBound: Type/Element])` +- If element inherits element with type parameters you should match that parameters with concrete types using method `parentArg(parent: Element, typeParameterName: String, typeArgument: String/Type/Element)` +- Note that if some element contains type parameters it should be configured before it's inheritors (will be fixed later) + +# Implementations + +- If element has no inheritors then it will have default implementation. Otherwise you should declare implementation that you want +- All implementations are described in `ImplementationConfigurator.kt` +- Syntax: + - `impl(element: Element, [name: String]) {...}` describes configuration of element with name `name` (if there is no name then it would be `ElementTypeImpl`). Lambda with implementation configuration is optional. Note that this function returns object of type `Implementation` + - `noImpl(element: Element)` used when you don't want to generated implementation of `element` +- In configuration lambda you can: + - Describe kind of implementation -- `FinalClass` (default), `OpenClass`, `AbstractClass`, `Interface` using syntax `kind = Interface` + - Add parents for implementation class + - syntax: `parents += parent` + - `parent` can be only implementation with `kind = Interface` + - Configure default values for fields: + - `default(fieldName: String) { ... }` + - in configuration lambda you can describe: + - `value = _defaultValue_` + - `withGetter = true/false` (`false` by default) + - `delegate = delegateFieldName` (used for generating such fields: `val typeRef: FirTypeRef get() = expression.typeRef`) + - `delegateName = fieldNameInDelegateType` (`val expressionTypeRef: FirTypeRef get() = expression.typeRef`) + - `needAcceptAndTransform = true/false` (`true` by default) -- specify it if you don't want to accept field in `acceptChildren` + - `customSetter = setterExpresison` + - note that by default all fields with fir elements are mutable and others are immutable + - Also there is some aliases for that default: + - `default(fieldName, value)` + - `defaultNull(fieldName, [withGetter: Boolean])` + - If some fields should be `lateinit` you describe them in call `lateinit(vararg fields: String)` + - If you use some types that shoub be imported list them in method `useTypes(vararg types: Type/Element)`