From 8e5b76d6dda8f518211f0ab07d6f997d44caf3eb Mon Sep 17 00:00:00 2001 From: Nicolas Stucki <nicolas.stucki@gmail.com> Date: Thu, 22 Nov 2018 17:32:55 +0100 Subject: [PATCH 1/3] Add instace checks for TASTy relfect `Tree.Term`s --- .../tools/dotc/tastyreflect/TreeOpsImpl.scala | 169 +++++++++++++++++- library/src/scala/tasty/reflect/TreeOps.scala | 158 ++++++++++++++-- 2 files changed, 302 insertions(+), 25 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala index 5b786eb6543c..67b77dbaa9b5 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala @@ -13,7 +13,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers def symbol(implicit ctx: Context): Symbol = tree.symbol } - object IsPackageClause extends IsPackageClauseExtractor { + object IsPackageClause extends IsPackageClauseModule { def unapply(tree: Tree)(implicit ctx: Context): Option[PackageClause] = tree match { case x: tpd.PackageDef => Some(x) case _ => None @@ -47,7 +47,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers // ----- Definitions ---------------------------------------------- - object IsDefinition extends IsDefinitionExtractor { + object IsDefinition extends IsDefinitionModule { def unapply(tree: Tree)(implicit ctx: Context): Option[Definition] = tree match { case tree: tpd.MemberDef => Some(tree) case tree: PackageDefinition => Some(tree) @@ -61,7 +61,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers // ClassDef - object IsClassDef extends IsClassDefExtractor { + object IsClassDef extends IsClassDefModule { def unapply(tree: Tree)(implicit ctx: Context): Option[ClassDef] = tree match { case x: tpd.TypeDef if x.isClassDef => Some(x) case _ => None @@ -87,7 +87,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers // DefDef - object IsDefDef extends IsDefDefExtractor { + object IsDefDef extends IsDefDefModule { def unapply(tree: Tree)(implicit ctx: Context): Option[DefDef] = tree match { case x: tpd.DefDef => Some(x) case _ => None @@ -112,7 +112,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers // ValDef - object IsValDef extends IsValDefExtractor { + object IsValDef extends IsValDefModule { def unapply(tree: Tree)(implicit ctx: Context): Option[ValDef] = tree match { case x: tpd.ValDef => Some(x) case _ => None @@ -135,7 +135,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers // TypeDef - object IsTypeDef extends IsTypeDefExtractor { + object IsTypeDef extends IsTypeDefModule { def unapply(tree: Tree)(implicit ctx: Context): Option[TypeDef] = tree match { case x: tpd.TypeDef if !x.symbol.isClass => Some(x) case _ => None @@ -168,7 +168,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers def symbol(implicit ctx: Context): PackageSymbol = pdef.symbol } - object IsPackageDef extends IsPackageDefExtractor { + object IsPackageDef extends IsPackageDefModule { def unapply(tree: Tree)(implicit ctx: Context): Option[PackageDef] = tree match { case x: PackageDefinition => Some(x) case _ => None @@ -193,7 +193,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers def underlying(implicit ctx: Context): Term = term.underlying } - object IsTerm extends IsTermExtractor { + object IsTerm extends IsTermModule { def unapply(tree: Tree)(implicit ctx: Context): Option[Term] = if (tree.isTerm) Some(tree) else None def unapply(termOrTypeTree: TermOrTypeTree)(implicit ctx: Context, dummy: DummyImplicit): Option[Term] = @@ -202,6 +202,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers object Term extends TermModule with TermCoreModuleImpl { + object IsIdent extends IsIdentModule { + def unapply(x: Term)(implicit ctx: Context): Option[Ident] = x match { + case x: tpd.Ident if x.isTerm => Some(x) + case _ => None + } + } + object Ident extends IdentExtractor { def unapply(x: Term)(implicit ctx: Context): Option[String] = x match { case x: tpd.Ident if x.isTerm => Some(x.name.show) @@ -209,6 +216,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsSelect extends IsSelectModule { + def unapply(x: Term)(implicit ctx: Context): Option[Select] = x match { + case x: tpd.Select if x.isTerm => Some(x) + case _ => None + } + } + object Select extends SelectExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, String, Option[Signature])] = x match { case x: tpd.Select if x.isTerm => @@ -220,6 +234,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsLiteral extends IsLiteralModule { + def unapply(x: Term)(implicit ctx: Context): Option[Literal] = x match { + case x: tpd.Literal => Some(x) + case _ => None + } + } + object Literal extends LiteralExtractor { def unapply(x: Term)(implicit ctx: Context): Option[Constant] = x match { case Trees.Literal(const) => Some(const) @@ -227,6 +248,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsThis extends IsThisModule { + def unapply(x: Term)(implicit ctx: Context): Option[This] = x match { + case x: tpd.This => Some(x) + case _ => None + } + } + object This extends ThisExtractor { def unapply(x: Term)(implicit ctx: Context): Option[Option[Id]] = x match { case Trees.This(qual) => Some(optional(qual)) @@ -234,6 +262,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsNew extends IsNewModule { + def unapply(x: Term)(implicit ctx: Context): Option[New] = x match { + case x: tpd.New => Some(x) + case _ => None + } + } + object New extends NewExtractor { def unapply(x: Term)(implicit ctx: Context): Option[TypeTree] = x match { case x: tpd.New => Some(x.tpt) @@ -241,6 +276,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsNamedArg extends IsNamedArgModule { + def unapply(x: Term)(implicit ctx: Context): Option[NamedArg] = x match { + case x: tpd.NamedArg if x.name.isInstanceOf[Names.TermName] => Some(x) // TODO: Now, the name should alwas be a term name + case _ => None + } + } + object NamedArg extends NamedArgExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(String, Term)] = x match { case x: tpd.NamedArg if x.name.isInstanceOf[Names.TermName] => Some((x.name.toString, x.arg)) @@ -248,6 +290,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsApply extends IsApplyModule { + def unapply(x: Term)(implicit ctx: Context): Option[Apply] = x match { + case x: tpd.Apply => Some(x) + case _ => None + } + } + object Apply extends ApplyExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, List[Term])] = x match { case x: tpd.Apply => Some((x.fun, x.args)) @@ -255,6 +304,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsTypeApply extends IsTypeApplyModule { + def unapply(x: Term)(implicit ctx: Context): Option[TypeApply] = x match { + case x: tpd.TypeApply => Some(x) + case _ => None + } + } + object TypeApply extends TypeApplyExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, List[TypeTree])] = x match { case x: tpd.TypeApply => Some((x.fun, x.args)) @@ -262,6 +318,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsSuper extends IsSuperModule { + def unapply(x: Term)(implicit ctx: Context): Option[Super] = x match { + case x: tpd.Super => Some(x) + case _ => None + } + } + object Super extends SuperExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Option[Id])] = x match { case x: tpd.Super => Some((x.qual, if (x.mix.isEmpty) None else Some(x.mix))) @@ -269,6 +332,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsTyped extends IsTypedModule { + def unapply(x: Term)(implicit ctx: Context): Option[Typed] = x match { + case x: tpd.Typed => Some(x) + case _ => None + } + } + object Typed extends TypedExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, TypeTree)] = x match { case x: tpd.Typed => Some((x.expr, x.tpt)) @@ -276,6 +346,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsAssign extends IsAssignModule { + def unapply(x: Term)(implicit ctx: Context): Option[Assign] = x match { + case x: tpd.Assign => Some(x) + case _ => None + } + } + object Assign extends AssignExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)] = x match { case x: tpd.Assign => Some((x.lhs, x.rhs)) @@ -283,6 +360,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsBlock extends IsBlockModule { + def unapply(x: Term)(implicit ctx: Context): Option[Block] = Block.normalizedLoops(x) match { + case x: tpd.Block => Some(x) + case _ => None + } + } + object Block extends BlockExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(List[Statement], Term)] = normalizedLoops(x) match { case Trees.Block(stats, expr) => Some((stats, expr)) @@ -292,7 +376,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers * i) Put `while` and `doWhile` loops in their own blocks: `{ def while$() = ...; while$() }` * ii) Put closures in their own blocks: `{ def anon$() = ...; closure(anon$, ...) }` */ - private def normalizedLoops(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match { + private[Term] def normalizedLoops(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match { case block: tpd.Block if block.stats.size > 1 => def normalizeInnerLoops(stats: List[tpd.Tree]): List[tpd.Tree] = stats match { case (x: tpd.DefDef) :: y :: xs if needsNormalization(y) => @@ -318,6 +402,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsInlined extends IsInlinedModule { + def unapply(x: Term)(implicit ctx: Context): Option[Inlined] = x match { + case x: tpd.Inlined => Some(x) + case _ => None + } + } + object Inlined extends InlinedExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Option[TermOrTypeTree], List[Statement], Term)] = x match { case x: tpd.Inlined => @@ -326,6 +417,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsLambda extends IsLambdaModule { + def unapply(x: Term)(implicit ctx: Context): Option[Lambda] = x match { + case x: tpd.Closure => Some(x) + case _ => None + } + } + object Lambda extends LambdaExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Option[TypeTree])] = x match { case x: tpd.Closure => Some((x.meth, optional(x.tpt))) @@ -333,6 +431,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsIf extends IsIfModule { + def unapply(x: Term)(implicit ctx: Context): Option[If] = x match { + case x: tpd.If => Some(x) + case _ => None + } + } + object If extends IfExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term, Term)] = x match { case x: tpd.If => Some((x.cond, x.thenp, x.elsep)) @@ -340,6 +445,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsMatch extends IsMatchModule { + def unapply(x: Term)(implicit ctx: Context): Option[Match] = x match { + case x: tpd.Match => Some(x) + case _ => None + } + } + object Match extends MatchExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, List[CaseDef])] = x match { case x: tpd.Match => Some((x.selector, x.cases)) @@ -347,6 +459,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsTry extends IsTryModule { + def unapply(x: Term)(implicit ctx: Context): Option[Try] = x match { + case x: tpd.Try => Some(x) + case _ => None + } + } + object Try extends TryExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, List[CaseDef], Option[Term])] = x match { case x: tpd.Try => Some((x.expr, x.cases, optional(x.finalizer))) @@ -354,6 +473,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsReturn extends IsReturnModule { + def unapply(x: Term)(implicit ctx: Context): Option[Return] = x match { + case x: tpd.Return => Some(x) + case _ => None + } + } + object Return extends ReturnExtractor { def unapply(x: Term)(implicit ctx: Context): Option[Term] = x match { case x: tpd.Return => Some(x.expr) @@ -361,6 +487,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsRepeated extends IsRepeatedModule { + def unapply(x: Term)(implicit ctx: Context): Option[Repeated] = x match { + case x: tpd.SeqLiteral => Some(x) + case _ => None + } + } + object Repeated extends RepeatedExtractor { def unapply(x: Term)(implicit ctx: Context): Option[List[Term]] = x match { case x: tpd.SeqLiteral => Some(x.elems) @@ -368,6 +501,17 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsSelectOuter extends IsSelectOuterModule { + def unapply(x: Term)(implicit ctx: Context): Option[SelectOuter] = x match { + case x: tpd.Select => + x.name match { + case NameKinds.OuterSelectName(_, _) => Some(x) + case _ => None + } + case _ => None + } + } + object SelectOuter extends SelectOuterExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Int, Type)] = x match { case x: tpd.Select => @@ -379,6 +523,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object IsWhile extends IsWhileModule { + def unapply(x: Term)(implicit ctx: Context): Option[While] = x match { + case x: tpd.WhileDo => Some(x) + case _ => None + } + } + object While extends WhileExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)] = x match { case x: tpd.WhileDo => Some((x.cond, x.body)) diff --git a/library/src/scala/tasty/reflect/TreeOps.scala b/library/src/scala/tasty/reflect/TreeOps.scala index e53b9ae61d34..a398ed45c258 100644 --- a/library/src/scala/tasty/reflect/TreeOps.scala +++ b/library/src/scala/tasty/reflect/TreeOps.scala @@ -11,8 +11,8 @@ trait TreeOps extends Core { } implicit def TreeDeco(tree: Tree): TreeAPI - val IsPackageClause: IsPackageClauseExtractor - abstract class IsPackageClauseExtractor { + val IsPackageClause: IsPackageClauseModule + abstract class IsPackageClauseModule { def unapply(tree: Tree)(implicit ctx: Context): Option[PackageClause] } @@ -41,8 +41,8 @@ trait TreeOps extends Core { // ----- Definitions ---------------------------------------------- - val IsDefinition: IsDefinitionExtractor - abstract class IsDefinitionExtractor { + val IsDefinition: IsDefinitionModule + abstract class IsDefinitionModule { def unapply(tree: Tree)(implicit ctx: Context): Option[Definition] } @@ -53,8 +53,8 @@ trait TreeOps extends Core { // ClassDef - val IsClassDef: IsClassDefExtractor - abstract class IsClassDefExtractor { + val IsClassDef: IsClassDefModule + abstract class IsClassDefModule { def unapply(tree: Tree)(implicit ctx: Context): Option[ClassDef] } @@ -75,8 +75,8 @@ trait TreeOps extends Core { // DefDef - val IsDefDef: IsDefDefExtractor - abstract class IsDefDefExtractor { + val IsDefDef: IsDefDefModule + abstract class IsDefDefModule { def unapply(tree: Tree)(implicit ctx: Context): Option[DefDef] } @@ -97,8 +97,8 @@ trait TreeOps extends Core { // ValDef - val IsValDef: IsValDefExtractor - abstract class IsValDefExtractor { + val IsValDef: IsValDefModule + abstract class IsValDefModule { def unapply(tree: Tree)(implicit ctx: Context): Option[ValDef] } @@ -117,8 +117,8 @@ trait TreeOps extends Core { // TypeDef - val IsTypeDef: IsTypeDefExtractor - abstract class IsTypeDefExtractor { + val IsTypeDef: IsTypeDefModule + abstract class IsTypeDefModule { def unapply(tree: Tree)(implicit ctx: Context): Option[TypeDef] } @@ -135,8 +135,8 @@ trait TreeOps extends Core { // PackageDef - val IsPackageDef: IsPackageDefExtractor - abstract class IsPackageDefExtractor { + val IsPackageDef: IsPackageDefModule + abstract class IsPackageDefModule { def unapply(tree: Tree)(implicit ctx: Context): Option[PackageDef] } @@ -162,8 +162,8 @@ trait TreeOps extends Core { } implicit def TermDeco(term: Term): TermAPI - val IsTerm: IsTermExtractor - abstract class IsTermExtractor { + val IsTerm: IsTermModule + abstract class IsTermModule { /** Matches any term */ def unapply(tree: Tree)(implicit ctx: Context): Option[Term] /** Matches any term */ @@ -174,6 +174,12 @@ trait TreeOps extends Core { val Term: TermModule abstract class TermModule extends TermCoreModule { + val IsIdent: IsIdentModule + abstract class IsIdentModule { + /** Matches any Ident and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Ident] + } + /** Scala term identifier */ val Ident: IdentExtractor abstract class IdentExtractor { @@ -181,6 +187,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[String] } + val IsSelect: IsSelectModule + abstract class IsSelectModule { + /** Matches any Select and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Select] + } + /** Scala term selection */ val Select: SelectExtractor abstract class SelectExtractor { @@ -188,12 +200,24 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, String, Option[Signature])] } + val IsLiteral: IsLiteralModule + abstract class IsLiteralModule { + /** Matches any Literal and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Literal] + } + /** Scala literal constant */ val Literal: LiteralExtractor abstract class LiteralExtractor { def unapply(tree: Tree)(implicit ctx: Context): Option[Constant] } + val IsThis: IsThisModule + abstract class IsThisModule { + /** Matches any This and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[This] + } + /** Scala `this` or `this[id]` */ val This: ThisExtractor abstract class ThisExtractor { @@ -201,6 +225,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Option[Id]] } + val IsNew: IsNewModule + abstract class IsNewModule { + /** Matches any New and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[New] + } + /** Scala `new` */ val New: NewExtractor abstract class NewExtractor { @@ -208,6 +238,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[TypeTree] } + val IsNamedArg: IsNamedArgModule + abstract class IsNamedArgModule { + /** Matches any NamedArg and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[NamedArg] + } + /** Scala named argument `x = y` in argument position */ val NamedArg: NamedArgExtractor abstract class NamedArgExtractor { @@ -215,6 +251,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(String, Term)] } + val IsApply: IsApplyModule + abstract class IsApplyModule { + /** Matches any Apply and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Apply] + } + /** Scala parameter application */ val Apply: ApplyExtractor abstract class ApplyExtractor { @@ -222,6 +264,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, List[Term])] } + val IsTypeApply: IsTypeApplyModule + abstract class IsTypeApplyModule { + /** Matches any TypeApply and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[TypeApply] + } + /** Scala type parameter application */ val TypeApply: TypeApplyExtractor abstract class TypeApplyExtractor { @@ -229,6 +277,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, List[TypeTree])] } + val IsSuper: IsSuperModule + abstract class IsSuperModule { + /** Matches any Super and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Super] + } + /** Scala `x.super` or `x.super[id]` */ val Super: SuperExtractor abstract class SuperExtractor { @@ -236,6 +290,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, Option[Id])] } + val IsTyped: IsTypedModule + abstract class IsTypedModule { + /** Matches any Typed and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Typed] + } + /** Scala ascription `x: T` */ val Typed: TypedExtractor abstract class TypedExtractor { @@ -243,6 +303,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, TypeTree)] } + val IsAssign: IsAssignModule + abstract class IsAssignModule { + /** Matches any Assign and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Assign] + } + /** Scala assign `x = y` */ val Assign: AssignExtractor abstract class AssignExtractor { @@ -250,6 +316,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, Term)] } + val IsBlock: IsBlockModule + abstract class IsBlockModule { + /** Matches any Block and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Block] + } + /** Scala code block `{ stat0; ...; statN; expr }` term */ val Block: BlockExtractor abstract class BlockExtractor { @@ -257,11 +329,23 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(List[Statement], Term)] } + val IsLambda: IsLambdaModule + abstract class IsLambdaModule { + /** Matches any Lambda and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Lambda] + } + val Lambda: LambdaExtractor abstract class LambdaExtractor { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, Option[TypeTree])] } + val IsIf: IsIfModule + abstract class IsIfModule { + /** Matches any If and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[If] + } + /** Scala `if`/`else` term */ val If: IfExtractor abstract class IfExtractor { @@ -269,6 +353,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, Term, Term)] } + val IsMatch: IsMatchModule + abstract class IsMatchModule { + /** Matches any Match and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Match] + } + /** Scala `match` term */ val Match: MatchExtractor abstract class MatchExtractor { @@ -276,6 +366,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, List[CaseDef])] } + val IsTry: IsTryModule + abstract class IsTryModule { + /** Matches any Try and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Try] + } + /** Scala `try`/`catch`/`finally` term */ val Try: TryExtractor abstract class TryExtractor { @@ -283,6 +379,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, List[CaseDef], Option[Term])] } + val IsReturn: IsReturnModule + abstract class IsReturnModule { + /** Matches any Return and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Return] + } + /** Scala local `return` */ val Return: ReturnExtractor abstract class ReturnExtractor { @@ -290,21 +392,45 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Term] } + val IsRepeated: IsRepeatedModule + abstract class IsRepeatedModule { + /** Matches any Repeated and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Repeated] + } + val Repeated: RepeatedExtractor abstract class RepeatedExtractor { def unapply(tree: Tree)(implicit ctx: Context): Option[List[Term]] } + val IsInlined: IsInlinedModule + abstract class IsInlinedModule { + /** Matches any Inlined and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[Inlined] + } + val Inlined: InlinedExtractor abstract class InlinedExtractor { def unapply(tree: Tree)(implicit ctx: Context): Option[(Option[TermOrTypeTree], List[Definition], Term)] } + val IsSelectOuter: IsSelectOuterModule + abstract class IsSelectOuterModule { + /** Matches any SelectOuter and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[SelectOuter] + } + val SelectOuter: SelectOuterExtractor abstract class SelectOuterExtractor { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, Int, Type)] } + val IsWhile: IsWhileModule + abstract class IsWhileModule { + /** Matches any While and returns it */ + def unapply(tree: Tree)(implicit ctx: Context): Option[While] + } + val While: WhileExtractor abstract class WhileExtractor { /** Extractor for while loops. Matches `while (<cond>) <body>` and returns (<cond>, <body>) */ From 4c9035019d92e27dd72063db3d3e3d5cd134413b Mon Sep 17 00:00:00 2001 From: Nicolas Stucki <nicolas.stucki@gmail.com> Date: Fri, 23 Nov 2018 11:32:26 +0100 Subject: [PATCH 2/3] Avoid duplicated checks for blocks --- .../tools/dotc/tastyreflect/TreeOpsImpl.scala | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala index 67b77dbaa9b5..0e987ebdd819 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala @@ -361,22 +361,16 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } object IsBlock extends IsBlockModule { - def unapply(x: Term)(implicit ctx: Context): Option[Block] = Block.normalizedLoops(x) match { + def unapply(x: Term)(implicit ctx: Context): Option[Block] = normalizedLoops(x) match { case x: tpd.Block => Some(x) case _ => None } - } - object Block extends BlockExtractor { - def unapply(x: Term)(implicit ctx: Context): Option[(List[Statement], Term)] = normalizedLoops(x) match { - case Trees.Block(stats, expr) => Some((stats, expr)) - case _ => None - } /** Normalizes non Blocks. * i) Put `while` and `doWhile` loops in their own blocks: `{ def while$() = ...; while$() }` * ii) Put closures in their own blocks: `{ def anon$() = ...; closure(anon$, ...) }` */ - private[Term] def normalizedLoops(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match { + private def normalizedLoops(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match { case block: tpd.Block if block.stats.size > 1 => def normalizeInnerLoops(stats: List[tpd.Tree]): List[tpd.Tree] = stats match { case (x: tpd.DefDef) :: y :: xs if needsNormalization(y) => @@ -402,6 +396,13 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + object Block extends BlockExtractor { + def unapply(x: Term)(implicit ctx: Context): Option[(List[Statement], Term)] = x match { + case IsBlock(x) => Some((x.stats, x.expr)) + case _ => None + } + } + object IsInlined extends IsInlinedModule { def unapply(x: Term)(implicit ctx: Context): Option[Inlined] = x match { case x: tpd.Inlined => Some(x) From d6d223639f9b02277adcce269c90706a696f905f Mon Sep 17 00:00:00 2001 From: Nicolas Stucki <nicolas.stucki@gmail.com> Date: Fri, 23 Nov 2018 13:40:48 +0100 Subject: [PATCH 3/3] Add missing Term extension methods --- .../tools/dotc/tastyreflect/TreeOpsImpl.scala | 117 +++++++++++++++- library/src/scala/tasty/reflect/TreeOps.scala | 129 +++++++++++++++++- 2 files changed, 241 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala index 0e987ebdd819..e4b701bdf20f 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala @@ -1,6 +1,6 @@ package dotty.tools.dotc.tastyreflect -import dotty.tools.dotc.ast.{Trees, tpd} +import dotty.tools.dotc.ast.{Trees, tpd, untpd} import dotty.tools.dotc.core import dotty.tools.dotc.core.Decorators._ import dotty.tools.dotc.core._ @@ -79,9 +79,9 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers def ClassDefDeco(cdef: ClassDef): ClassDefAPI = new ClassDefAPI { private def rhs = cdef.rhs.asInstanceOf[tpd.Template] def constructor(implicit ctx: Context): DefDef = rhs.constr - def parents(implicit ctx: Context): List[tpd.Tree] = rhs.parents + def parents(implicit ctx: Context): List[TermOrTypeTree] = rhs.parents def self(implicit ctx: Context): Option[tpd.ValDef] = optional(rhs.self) - def body(implicit ctx: Context): List[tpd.Tree] = rhs.body + def body(implicit ctx: Context): List[Statement] = rhs.body def symbol(implicit ctx: Context): ClassSymbol = cdef.symbol.asClass } @@ -209,6 +209,10 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def IdentDeco(x: Ident): IdentAPI = new IdentAPI { + def name(implicit ctx: Context): String = x.name.show + } + object Ident extends IdentExtractor { def unapply(x: Term)(implicit ctx: Context): Option[String] = x match { case x: tpd.Ident if x.isTerm => Some(x.name.show) @@ -223,6 +227,14 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def SelectDeco(x: Select): SelectAPI = new SelectAPI { + def qualifier(implicit ctx: Context): Term = x.qualifier + def name(implicit ctx: Context): String = x.name.toString + def signature(implicit ctx: Context): Option[Signature] = + if (x.symbol.signature == core.Signature.NotAMethod) None + else Some(x.symbol.signature) + } + object Select extends SelectExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, String, Option[Signature])] = x match { case x: tpd.Select if x.isTerm => @@ -241,6 +253,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + + def LiteralDeco(x: Literal): LiteralAPI = new LiteralAPI { + def constant(implicit ctx: Context): Constant = x.const + } + object Literal extends LiteralExtractor { def unapply(x: Term)(implicit ctx: Context): Option[Constant] = x match { case Trees.Literal(const) => Some(const) @@ -255,6 +272,10 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def ThisDeco(x: This): ThisAPI = new ThisAPI { + def id(implicit ctx: Context): Option[Id] = optional(x.qual) + } + object This extends ThisExtractor { def unapply(x: Term)(implicit ctx: Context): Option[Option[Id]] = x match { case Trees.This(qual) => Some(optional(qual)) @@ -269,6 +290,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + + def NewDeco(x: New): Term.NewAPI = new NewAPI { + def tpt(implicit ctx: Context): TypeTree = x.tpt + } + object New extends NewExtractor { def unapply(x: Term)(implicit ctx: Context): Option[TypeTree] = x match { case x: tpd.New => Some(x.tpt) @@ -283,6 +309,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def NamedArgDeco(x: NamedArg): NamedArgAPI = new NamedArgAPI { + def name(implicit ctx: Context): String = x.name.toString + def value(implicit ctx: Context): Term = x.arg + } + object NamedArg extends NamedArgExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(String, Term)] = x match { case x: tpd.NamedArg if x.name.isInstanceOf[Names.TermName] => Some((x.name.toString, x.arg)) @@ -297,6 +328,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def ApplyDeco(x: Apply): ApplyAPI = new ApplyAPI { + def fun(implicit ctx: Context): Term = x.fun + def args(implicit ctx: Context): List[Term] = x.args + } + object Apply extends ApplyExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, List[Term])] = x match { case x: tpd.Apply => Some((x.fun, x.args)) @@ -311,6 +347,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def TypeApplyDeco(x: TypeApply): TypeApplyAPI = new TypeApplyAPI { + def fun(implicit ctx: Context): Term = x.fun + def args(implicit ctx: Context): List[TypeTree] = x.args + } + object TypeApply extends TypeApplyExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, List[TypeTree])] = x match { case x: tpd.TypeApply => Some((x.fun, x.args)) @@ -325,6 +366,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def SuperDeco(x: Super): SuperAPI = new SuperAPI { + def qualifier(implicit ctx: Context): Term = x.qual + def id(implicit ctx: Context): Option[untpd.Ident] = optional(x.mix) + } + object Super extends SuperExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Option[Id])] = x match { case x: tpd.Super => Some((x.qual, if (x.mix.isEmpty) None else Some(x.mix))) @@ -339,6 +385,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def TypedDeco(x: Typed): TypedAPI = new TypedAPI { + def expr(implicit ctx: Context): Term = x.expr + def tpt(implicit ctx: Context): TypeTree = x.tpt + } + object Typed extends TypedExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, TypeTree)] = x match { case x: tpd.Typed => Some((x.expr, x.tpt)) @@ -353,6 +404,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def AssignDeco(x: Assign): AssignAPI = new AssignAPI { + def lhs(implicit ctx: Context): Term = x.lhs + def rhs(implicit ctx: Context): Term = x.rhs + } + object Assign extends AssignExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)] = x match { case x: tpd.Assign => Some((x.lhs, x.rhs)) @@ -396,6 +452,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def BlockDeco(x: Block): BlockAPI = new BlockAPI { + def statements(implicit ctx: Context): List[Statement] = x.stats + def expr(implicit ctx: Context): Term = x.expr + } + object Block extends BlockExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(List[Statement], Term)] = x match { case IsBlock(x) => Some((x.stats, x.expr)) @@ -410,6 +471,12 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def InlinedDeco(x: Inlined): InlinedAPI = new InlinedAPI { + def call(implicit ctx: Context): Option[Term] = optional(x.call) + def bindings(implicit ctx: Context): List[Definition] = x.bindings + def body(implicit ctx: Context): Term = x.expansion + } + object Inlined extends InlinedExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Option[TermOrTypeTree], List[Statement], Term)] = x match { case x: tpd.Inlined => @@ -425,6 +492,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def LambdaDeco(x: Lambda): LambdaAPI = new LambdaAPI { + def meth(implicit ctx: Context): Term = x.meth + def tptOpt(implicit ctx: Context): Option[TypeTree] = optional(x.tpt) + } + object Lambda extends LambdaExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Option[TypeTree])] = x match { case x: tpd.Closure => Some((x.meth, optional(x.tpt))) @@ -439,6 +511,12 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def IfDeco(x: If): IfAPI = new IfAPI { + def cond(implicit ctx: Context): Term = x.cond + def thenp(implicit ctx: Context): Term = x.thenp + def elsep(implicit ctx: Context): Term = x.elsep + } + object If extends IfExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term, Term)] = x match { case x: tpd.If => Some((x.cond, x.thenp, x.elsep)) @@ -453,6 +531,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def MatchDeco(x: Match): MatchAPI = new MatchAPI { + def scrutinee(implicit ctx: Context): Term = x.selector + def cases(implicit ctx: Context): List[tpd.CaseDef] = x.cases + } + object Match extends MatchExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, List[CaseDef])] = x match { case x: tpd.Match => Some((x.selector, x.cases)) @@ -467,6 +550,12 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def TryDeco(x: Try): TryAPI = new TryAPI { + def body(implicit ctx: Context): Term = x.expr + def cases(implicit ctx: Context): List[CaseDef] = x.cases + def finalizer(implicit ctx: Context): Option[Term] = optional(x.finalizer) + } + object Try extends TryExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, List[CaseDef], Option[Term])] = x match { case x: tpd.Try => Some((x.expr, x.cases, optional(x.finalizer))) @@ -481,6 +570,10 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def ReturnDeco(x: Return): ReturnAPI = new ReturnAPI { + def expr(implicit ctx: Context): Term = x.expr + } + object Return extends ReturnExtractor { def unapply(x: Term)(implicit ctx: Context): Option[Term] = x match { case x: tpd.Return => Some(x.expr) @@ -495,6 +588,10 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def RepeatedDeco(x: Repeated): RepeatedAPI = new RepeatedAPI { + def elems(implicit ctx: Context): List[Term] = x.elems + } + object Repeated extends RepeatedExtractor { def unapply(x: Term)(implicit ctx: Context): Option[List[Term]] = x match { case x: tpd.SeqLiteral => Some(x.elems) @@ -513,6 +610,15 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def SelectOuterDeco(x: SelectOuter): SelectOuterAPI = new SelectOuterAPI { + def qualifier(implicit ctx: Context): Term = x.qualifier + def level(implicit ctx: Context): Int = { + val NameKinds.OuterSelectName(_, levels) = x.name + levels + } + def tpe(implicit ctx: Context): Type = x.tpe.stripTypeVar + } + object SelectOuter extends SelectOuterExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Int, Type)] = x match { case x: tpd.Select => @@ -531,6 +637,11 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers } } + def WhileDeco(x: While): WhileAPI = new WhileAPI { + def cond(implicit ctx: Context): Term = x.cond + def body(implicit ctx: Context): Term = x.body + } + object While extends WhileExtractor { def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)] = x match { case x: tpd.WhileDo => Some((x.cond, x.body)) diff --git a/library/src/scala/tasty/reflect/TreeOps.scala b/library/src/scala/tasty/reflect/TreeOps.scala index a398ed45c258..a9d6ec7efed5 100644 --- a/library/src/scala/tasty/reflect/TreeOps.scala +++ b/library/src/scala/tasty/reflect/TreeOps.scala @@ -180,6 +180,11 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Ident] } + trait IdentAPI { + def name(implicit ctx: Context): String + } + implicit def IdentDeco(ident: Ident): IdentAPI + /** Scala term identifier */ val Ident: IdentExtractor abstract class IdentExtractor { @@ -193,10 +198,17 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Select] } + trait SelectAPI { + def qualifier(implicit ctx: Context): Term + def name(implicit ctx: Context): String + def signature(implicit ctx: Context): Option[Signature] + } + implicit def SelectDeco(select: Select): SelectAPI + /** Scala term selection */ val Select: SelectExtractor abstract class SelectExtractor { - /** Matches `<qual: Term>.<name: String>: <sig: Signature>` */ + /** Matches `<qual: Term>.<name: String>: <sig: Option[Signature]>` */ def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, String, Option[Signature])] } @@ -206,6 +218,11 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Literal] } + trait LiteralAPI { + def constant(implicit ctx: Context): Constant + } + implicit def LiteralDeco(x: Literal): LiteralAPI + /** Scala literal constant */ val Literal: LiteralExtractor abstract class LiteralExtractor { @@ -218,6 +235,11 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[This] } + trait ThisAPI { + def id(implicit ctx: Context): Option[Id] + } + implicit def ThisDeco(x: This): ThisAPI + /** Scala `this` or `this[id]` */ val This: ThisExtractor abstract class ThisExtractor { @@ -231,6 +253,11 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[New] } + trait NewAPI { + def tpt(implicit ctx: Context): TypeTree + } + implicit def NewDeco(x: New): NewAPI + /** Scala `new` */ val New: NewExtractor abstract class NewExtractor { @@ -244,6 +271,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[NamedArg] } + trait NamedArgAPI { + def name(implicit ctx: Context): String + def value(implicit ctx: Context): Term + } + implicit def NamedArgDeco(x: NamedArg): NamedArgAPI + /** Scala named argument `x = y` in argument position */ val NamedArg: NamedArgExtractor abstract class NamedArgExtractor { @@ -257,6 +290,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Apply] } + trait ApplyAPI { + def fun(implicit ctx: Context): Term + def args(implicit ctx: Context): List[Term] + } + implicit def ApplyDeco(x: Apply): ApplyAPI + /** Scala parameter application */ val Apply: ApplyExtractor abstract class ApplyExtractor { @@ -270,6 +309,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[TypeApply] } + trait TypeApplyAPI { + def fun(implicit ctx: Context): Term + def args(implicit ctx: Context): List[TypeTree] + } + implicit def TypeApplyDeco(x: TypeApply): TypeApplyAPI + /** Scala type parameter application */ val TypeApply: TypeApplyExtractor abstract class TypeApplyExtractor { @@ -283,6 +328,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Super] } + trait SuperAPI { + def qualifier(implicit ctx: Context): Term + def id(implicit ctx: Context): Option[Id] + } + implicit def SuperDeco(x: Super): SuperAPI + /** Scala `x.super` or `x.super[id]` */ val Super: SuperExtractor abstract class SuperExtractor { @@ -296,10 +347,16 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Typed] } + trait TypedAPI { + def expr(implicit ctx: Context): Term + def tpt(implicit ctx: Context): Term + } + implicit def TypedDeco(x: Typed): TypedAPI + /** Scala ascription `x: T` */ val Typed: TypedExtractor abstract class TypedExtractor { - /** Matches `<x: Term>: <tpt: Term>` */ + /** Matches `<expr: Term>: <tpt: Term>` */ def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, TypeTree)] } @@ -309,6 +366,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Assign] } + trait AssignAPI { + def lhs(implicit ctx: Context): Term + def rhs(implicit ctx: Context): Term + } + implicit def AssignDeco(x: Assign): AssignAPI + /** Scala assign `x = y` */ val Assign: AssignExtractor abstract class AssignExtractor { @@ -322,6 +385,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Block] } + trait BlockAPI { + def statements(implicit ctx: Context): List[Statement] + def expr(implicit ctx: Context): Term + } + implicit def BlockDeco(x: Block): BlockAPI + /** Scala code block `{ stat0; ...; statN; expr }` term */ val Block: BlockExtractor abstract class BlockExtractor { @@ -335,6 +404,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Lambda] } + trait LambdaAPI { + def meth(implicit ctx: Context): Term + def tptOpt(implicit ctx: Context): Option[TypeTree] + } + implicit def LambdaDeco(x: Lambda): LambdaAPI + val Lambda: LambdaExtractor abstract class LambdaExtractor { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, Option[TypeTree])] @@ -346,6 +421,13 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[If] } + trait IfAPI { + def cond(implicit ctx: Context): Term + def thenp(implicit ctx: Context): Term + def elsep(implicit ctx: Context): Term + } + implicit def IfDeco(x: If): IfAPI + /** Scala `if`/`else` term */ val If: IfExtractor abstract class IfExtractor { @@ -359,6 +441,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Match] } + trait MatchAPI { + def scrutinee(implicit ctx: Context): Term + def cases(implicit ctx: Context): List[CaseDef] + } + implicit def MatchDeco(x: Match): MatchAPI + /** Scala `match` term */ val Match: MatchExtractor abstract class MatchExtractor { @@ -372,6 +460,13 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Try] } + trait TryAPI { + def body(implicit ctx: Context): Term + def cases(implicit ctx: Context): List[CaseDef] + def finalizer(implicit ctx: Context): Option[Term] + } + implicit def TryDeco(x: Try): TryAPI + /** Scala `try`/`catch`/`finally` term */ val Try: TryExtractor abstract class TryExtractor { @@ -385,6 +480,11 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Return] } + trait ReturnAPI { + def expr(implicit ctx: Context): Term + } + implicit def ReturnDeco(x: Return): ReturnAPI + /** Scala local `return` */ val Return: ReturnExtractor abstract class ReturnExtractor { @@ -398,6 +498,11 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Repeated] } + trait RepeatedAPI { + def elems(implicit ctx: Context): List[Term] + } + implicit def RepeatedDeco(x: Repeated): RepeatedAPI + val Repeated: RepeatedExtractor abstract class RepeatedExtractor { def unapply(tree: Tree)(implicit ctx: Context): Option[List[Term]] @@ -409,6 +514,13 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[Inlined] } + trait InlinedAPI { + def call(implicit ctx: Context): Option[TermOrTypeTree] + def bindings(implicit ctx: Context): List[Definition] + def body(implicit ctx: Context): Term + } + implicit def InlinedDeco(x: Inlined): InlinedAPI + val Inlined: InlinedExtractor abstract class InlinedExtractor { def unapply(tree: Tree)(implicit ctx: Context): Option[(Option[TermOrTypeTree], List[Definition], Term)] @@ -420,6 +532,13 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[SelectOuter] } + trait SelectOuterAPI { + def qualifier(implicit ctx: Context): Term + def level(implicit ctx: Context): Int + def tpe(implicit ctx: Context): Type + } + implicit def SelectOuterDeco(x: SelectOuter): SelectOuterAPI + val SelectOuter: SelectOuterExtractor abstract class SelectOuterExtractor { def unapply(tree: Tree)(implicit ctx: Context): Option[(Term, Int, Type)] @@ -431,6 +550,12 @@ trait TreeOps extends Core { def unapply(tree: Tree)(implicit ctx: Context): Option[While] } + trait WhileAPI { + def cond(implicit ctx: Context): Term + def body(implicit ctx: Context): Term + } + implicit def WhileDeco(x: While): WhileAPI + val While: WhileExtractor abstract class WhileExtractor { /** Extractor for while loops. Matches `while (<cond>) <body>` and returns (<cond>, <body>) */