Skip to content
Béguet Eric edited this page Jan 25, 2015 · 14 revisions
Table of Contents
TQL provides a way to query data structures in a way similar to Scala collections via expansion methods. This page assume complete knowledge of the [TQL combinator library](https://github.com/begeric/TQL-scalameta/wiki/Combinators).

The libray is implemented through two different evaluation stategies:

  • Methods which return an Evaluator, which mean that they only define a traversal strategy and so can be queried afterward.
  • Methods which return a result.

The API can be used on data of type T (the data structure), Option[T] and List[T]. In the case of Option[T] and List[T] every result is then boxed in an Option or a List.

For example, if (tree : T).transform{..} returns a result of type T, then _(optTree: Option[T]).transform{..} retuns an Option[T].

note: All examples refer to the following code spinnet which we name tree:

val a = 5
val c = 3
c = 5
if (3 == 17) {
    val c = {
      val d = "hey"
      22
    }
}
else 
    "2"
5
Those function allow to chose the traversal strategy, if none is specified _topDown_ is used by default.

Definition

def topDown: EvaluatorMeta
def topDownBreak: EvaluatorMeta
def bottomUp: EvaluatorMeta
def bottomUpBreak: EvaluatorMeta

Example

val r1 = tree.collect{
  case Defn.Val(_, List(name: Term.Name), _, _) => name
}
r1:List[Term.Name] = List(a, c, c, d)

val r2 = tree.topDown.collect{
  case Defn.Val(_, List(name: Term.Name), _, _) => name
} //equiv to the above
r2:List[Term.Name] = List(a, c, c, d)

val r3 = tree.topDownBreak.collect{
  case Defn.Val(_, List(name: Term.Name), _, _) => name
}
r3:List[Term.Name] = List(a, c, c)

val r4 = tree.bottomUp.collect{
  case Defn.Val(_, List(name: Term.Name), _, _) => name
}
r4:List[Term.Name] = List(a, c, d, c)

val r5 = tree.bottomUpBreak.collect{
  case Defn.Val(_, List(name: Term.Name), _, _) => name
}
r5:List[Term.Name] = List(a, c, d)
__Definition__ ```scala def collect[C[_]] = new { def apply[A](f: PartialFunction[T, A]): C[A] //or List[A] if C[_] is infered to Nothing } ``` __Example__ ```scala val r1 = tree.collect[Set]{case Lit.Int(a) => a} r1: Set[Int] = Set(5, 3, 17, 22) val r2 = tree.collect{case Lit.Int(a) => a} r2: List[Int] = List(5, 3, 5, 3, 17, 22, 5) ``` __Definition__ ```scala def focus(f: PartialFunction[T, Boolean]):EvaluatorAndThen[V, A] ```

Example

val l: EvaluatorAndThen[Term.If, Term.If] = tree.focus{case Term.If(a, b, c) => true}

Collect all Integer literals inside a Term.If.

val l = tree.focus{case Term.If(a, b, c) => true}
            .topDown
            .collect{case Lit.Int(a) => a}
l: List[Int] = List(3, 17, 22)

Expands to:

def guard[U <: T : ClassTag](f: PartialFunction[U, Boolean]):EvaluatorAndThen[U]
__Definition__ ```scala def transform(f: PartialFunction[T, (T, A)]): MatcherResult[(T, A)] ```

As with the combinators a transformation can go with a result.

Example

val (t, a) = tree.transform{
    case Defn.Val(a, b, c, d) => 
      Defn.Var(a,b,c,Some(d)) andCollect b.toString)
}
t: scala.meta.Tree = {
  var a = 5
  var c = 3
  c = 5
  if (3 == 17) {
    var c = {
      var d = "hey"
      22
   }
 } else "2"
  5
}
a: List[String] = List(a, c, c, d)
val t = tree.transform{
    case Lit.Int(a) => Lit.Int(a * 2)
}
t: scala.meta.Tree = {
  val a = 10
  val c = 6
  c = 10
  if (6 == 34) {
    val c = {
      val d = "hey"
      44
    }
  } else "2"
  10
}

Expands to:

def transformWithResult[I <: T : ClassTag, O <: T, A : Monoid]
                       (f: PartialFunction[I, (O, A)]): MatcherResult[(T, A)]
__Definition__ ```scala def combine[B](x: Matcher[B]): EvaluatorAndThen[V, B] ```

Provides a way to combine the collection-like UI with normal combinators.

Example

val r1: EvaluatorAndThen[scala.meta.Tree, List[Int]] = 
  x.focus({case Term.If(_,_,_) => true})
   .combine(topDown(collect{case Lit.Int(a) => a}))
r2 = r1.result //The result is lazily computed, so we need to force the result to have it.
r2: List[Int] = List(3, 17, 1, 78, 14, 85, 2)
Clone this wiki locally