|
| 1 | +--- |
| 2 | +layout: doc-page |
| 3 | +title: "TASTy reflect" |
| 4 | +--- |
| 5 | + |
| 6 | +TASTy Reflect enables inspection and construction of Typed Abstract Syntax Trees (TAST). |
| 7 | +It may be used on quoted expressions (`quoted.Expr`) and quoted types (`quoted.Type`) from [Principled Meta-programming](./principled-meta-programming.html) |
| 8 | +or on full TASTy files. |
| 9 | + |
| 10 | +If you are writing macros, please first read [Principled Meta-programming](./principled-meta-programming.html). |
| 11 | +You may find all you need without using TASTy Reflect. |
| 12 | + |
| 13 | + |
| 14 | +## From quotes and splices to TASTs Reflect trees and back |
| 15 | + |
| 16 | +`quoted.Expr` and `quoted.Type` are only meant for generative meta-programming, generation of code without inspecting the ASTs. |
| 17 | +[Principled Meta-programming](./principled-meta-programming.html) provides the guarantee that the generation of code will be type-correct. |
| 18 | +Using TASTy Reflect will break these guarantees and may fail at macro expansion time, hence additional explicit check must be done. |
| 19 | + |
| 20 | + |
| 21 | +To provide reflection capabilities in macros we need to add an implicit parameter of type `scala.tasty.Reflection` and import it in the scope where it is used. |
| 22 | + |
| 23 | +```scala |
| 24 | +import scala.quoted._ |
| 25 | +import scala.tasty._ |
| 26 | + |
| 27 | +inline def natConst(x: Int): Int = ~natConstImpl('(x)) |
| 28 | + |
| 29 | +def natConstImpl(x: Expr[Int])(implicit reflection: Reflection): Expr[Int] = { |
| 30 | + import reflection._ |
| 31 | + ... |
| 32 | +} |
| 33 | +``` |
| 34 | + |
| 35 | +`import reflection._` will provide a `reflect` extension method on `quoted.Expr` and `quoted.Type` which return a `reflection.Term` and `reflection.TypeTree` respectively. |
| 36 | +It will also import all extractors and methods on TASTy Reflect trees. For example the `Term.Literal(_)` extractor used below. |
| 37 | + |
| 38 | +```scala |
| 39 | +def natConstImpl(x: Expr[Int])(implicit reflection: Reflection): Expr[Int] = { |
| 40 | + import reflection._ |
| 41 | + val xTree: Term = x.reflect |
| 42 | + xTree match { |
| 43 | + case Term.Literal(Constant.Int(n)) => |
| 44 | + if (n <= 0) |
| 45 | + throw new QuoteError("Parameter must be natural number") |
| 46 | + n.toExpr |
| 47 | + case _ => |
| 48 | + throw new QuoteError("Parameter must be a known constant") |
| 49 | + } |
| 50 | +} |
| 51 | +``` |
| 52 | + |
| 53 | +To easily know which extractors are needed, the `reflection.Term.show` method returns the string representation of the extractors. |
| 54 | + |
| 55 | +The method `reflection.Term.reify[T]` provides a way to to go back to a `quoted.Expr`. |
| 56 | +Note that the type must be set explicitly and that if it does not conform to it an exception will be thrown. |
| 57 | +In the code above we could have replaced `n.toExpr` by `xTree.reify[Int]`. |
| 58 | + |
| 59 | +## Inspect a TASTy file |
| 60 | + |
| 61 | +To inspect the TASTy Reflect trees of a TASTy file a consumer can be defined in the following way. |
| 62 | + |
| 63 | +```scala |
| 64 | +class Consumer extends TastyConsumer { |
| 65 | + final def apply(reflect: Reflection)(root: reflect.Tree): Unit = { |
| 66 | + import reflect._ |
| 67 | + // Do somthing with the tree |
| 68 | + } |
| 69 | +} |
| 70 | +``` |
| 71 | + |
| 72 | +Then the consumer can be instantiated with the following code to get the tree of the class `foo.Bar` for a foo in the classpath. |
| 73 | + |
| 74 | +```scala |
| 75 | +object Test { |
| 76 | + def main(args: Array[String]): Unit = { |
| 77 | + ConsumeTasty("", List("foo.Bar"), new Consumer) |
| 78 | + } |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +## TASTy Reflect API |
| 83 | + |
| 84 | +TASTy Reflect provides the following types: |
| 85 | + |
| 86 | +```none |
| 87 | ++- Tree -+- PackageClause |
| 88 | + +- Import |
| 89 | + +- Statement -+- Definition --+- PackageDef |
| 90 | + | +- ClassDef |
| 91 | + | +- TypeDef |
| 92 | + | +- DefDef |
| 93 | + | +- ValDef |
| 94 | + | |
| 95 | + +- Term --------+- Ident |
| 96 | + +- Select |
| 97 | + +- Literal |
| 98 | + +- This |
| 99 | + +- New |
| 100 | + +- NamedArg |
| 101 | + +- Apply |
| 102 | + +- TypeApply |
| 103 | + +- Super |
| 104 | + +- Typed |
| 105 | + +- Assign |
| 106 | + +- Block |
| 107 | + +- Lambda |
| 108 | + +- If |
| 109 | + +- Match |
| 110 | + +- Try |
| 111 | + +- Return |
| 112 | + +- Repeated |
| 113 | + +- Inlined |
| 114 | + +- SelectOuter |
| 115 | + +- While |
| 116 | +
|
| 117 | +
|
| 118 | + +- TypeTree ----+- Synthetic |
| 119 | + | +- Ident |
| 120 | + | +- Select |
| 121 | + | +- Project |
| 122 | + | +- Singleton |
| 123 | ++- TypeOrBoundsTree ---+ +- Refined |
| 124 | + | +- Applied |
| 125 | + | +- Annotated |
| 126 | + | +- And |
| 127 | + | +- Or |
| 128 | + | +- MatchType |
| 129 | + | +- ByName |
| 130 | + | +- LambdaTypeTree |
| 131 | + | +- Bind |
| 132 | + | |
| 133 | + +- TypeBoundsTree |
| 134 | + +- SyntheticBounds |
| 135 | +
|
| 136 | ++- CaseDef |
| 137 | ++- TypeCaseDef |
| 138 | +
|
| 139 | ++- Pattern --+- Value |
| 140 | + +- Bind |
| 141 | + +- Unapply |
| 142 | + +- Alternative |
| 143 | + +- TypeTest |
| 144 | +
|
| 145 | +
|
| 146 | + +- NoPrefix |
| 147 | ++- TypeOrBounds -+- TypeBounds |
| 148 | + | |
| 149 | + +- Type -------+- ConstantType |
| 150 | + +- SymRef |
| 151 | + +- TermRef |
| 152 | + +- TypeRef |
| 153 | + +- SuperType |
| 154 | + +- Refinement |
| 155 | + +- AppliedType |
| 156 | + +- AnnotatedType |
| 157 | + +- AndType |
| 158 | + +- OrType |
| 159 | + +- MatchType |
| 160 | + +- ByNameType |
| 161 | + +- ParamRef |
| 162 | + +- ThisType |
| 163 | + +- RecursiveThis |
| 164 | + +- RecursiveType |
| 165 | + +- LambdaType[ParamInfo <: TypeOrBounds] -+- MethodType |
| 166 | + +- PolyType |
| 167 | + +- TypeLambda |
| 168 | +
|
| 169 | ++- ImportSelector -+- SimpleSelector |
| 170 | + +- RenameSelector |
| 171 | + +- OmitSelector |
| 172 | +
|
| 173 | ++- Id |
| 174 | +
|
| 175 | ++- Signature |
| 176 | +
|
| 177 | ++- Position |
| 178 | +
|
| 179 | ++- Constant |
| 180 | +
|
| 181 | ++- Symbol --+- PackageSymbol |
| 182 | + +- ClassSymbol |
| 183 | + +- TypeSymbol |
| 184 | + +- DefSymbol |
| 185 | + +- ValSymbol |
| 186 | + +- BindSymbol |
| 187 | + +- NoSymbol |
| 188 | +
|
| 189 | +Aliases: |
| 190 | + # TermOrTypeTree = Term | TypeTree |
| 191 | +``` |
| 192 | + |
| 193 | +## More Examples |
| 194 | + |
| 195 | +* Start experimenting with TASTy Reflect ([link](https://github.com/nicolasstucki/tasty-reflection-exercise)) |
| 196 | + |
0 commit comments