<commit_before>package ch.usi.inf.l3.sana


// import ch.usi.inf.l3.sana.core.SyntaxComponent
import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros


object dsl {
  def generateComponents[T, R](trees: String,
    commonName: String, callback: String,
    excluded: String): List[PartialFunction[T, R]] =
    macro MacroImpls.generateComponentsImpl[T, R]

  // def generateFamilies[T <: SyntaxComponent, R](trees: String,
  //   commonName: String, callback: String): List[TransformationComponent[T, R]] =
  //   macro MacroImpls.generateComponentsImpl[T, R]
  //

  def defines(id: Any, tpe: String): Boolean = macro MacroImpls.definesImpl
}


object MacroImpls {

  def definesImpl(c: Context)(id: c.Expr[Any],
                              tpe: c.Expr[String]): c.Expr[Boolean] = {
    import c.universe._
    val Literal(Constant(nme: String))   = tpe.tree
    val tnme                             = TypeName(nme)

    val expr = q"""
    $id match {
      case _: $tnme       => true
      case _              => false
    }
    """
    c.Expr[Boolean](expr)
  }

  def generateComponentsImpl[T : c.WeakTypeTag,
      R: c.WeakTypeTag](c: Context)
      (trees: c.Expr[String], commonName: c.Expr[String],
      callback: c.Expr[String],
      excluded: c.Expr[String]): c.Expr[List[PartialFunction[T, R]]] = {

    import c.universe._

    val Literal(Constant(commonNameString: String))   = commonName.tree
    val Literal(Constant(callbackString: String))     = callback.tree
    val treeList                                      = {
      val duplicated = trees.tree.duplicate
      val constant   = c.Expr[String](c.untypecheck(duplicated))
      c.eval[String](constant).split(",").map(_.trim)
    }.toList
    val excludedTrees                                 = {
      val duplicated = excluded.tree.duplicate
      val constant   = c.Expr[String](c.untypecheck(duplicated))
      c.eval[String](constant).split(",").map(_.trim)
    }.toList

    val components = for {
      tree <- treeList if !excludedTrees.contains(tree)
    } yield {
      val cbName    = TermName(callbackString)
      val clazzName = TypeName(tree + commonNameString)<commit_msg>Add @component macro to generate component traits<commit_after>package ch.usi.inf.l3.sana


// import ch.usi.inf.l3.sana.core.SyntaxComponent
import scala.reflect.macros.blackbox.Context
import scala.annotation.{StaticAnnotation,compileTimeOnly}
import scala.language.experimental.macros


object dsl {
  def generateComponents[T, R](trees: String,
    commonName: String, callback: String,
    excluded: String): List[PartialFunction[T, R]] =
    macro MacroImpls.generateComponentsImpl[T, R]

  // def generateFamilies[T <: SyntaxComponent, R](trees: String,
  //   commonName: String, callback: String): List[TransformationComponent[T, R]] =
  //   macro MacroImpls.generateComponentsImpl[T, R]
  //

  def defines(id: Any, tpe: String): Boolean = macro MacroImpls.definesImpl


  @compileTimeOnly("Enable macro paradise to expand macro annotations")
  class component extends StaticAnnotation {
    def macroTransform(annottees: Any*): Any = macro MacroImpls.componentsImpl
  }
}


object MacroImpls {

  def definesImpl(c: Context)(id: c.Expr[Any],
                              tpe: c.Expr[String]): c.Expr[Boolean] = {
    import c.universe._
    val Literal(Constant(nme: String))   = tpe.tree
    val tnme                             = TypeName(nme)

  def componentsImpl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    val inputs = annottees.map(_.tree).toList
    val expandee = inputs match {
      case (clazz: ClassDef) :: Nil =>
        val impl = clazz.impl.body.flatMap { mthd =>
          mthd match {
            case pf@Function(List(param), rhs) =>
              val app = q"""
                def apply(p: Input): Output = p match {
                  case p: ${param.tpt} => ${pf}.apply(p)
                }
              """
              val isDefinedAt = q"""
                def isDefinedAt(p: Input): Boolean = p match {
                  case p: ${param.tpt} => true
                  case _               => false
                }
              """
              List(app, isDefinedAt)
            case m                             => List(m)
          }
        }.filter { mthd =>
          mthd match {
            case mt: DefDef    =>
              mt.name != TermName("$init$")
            case _             =>
              true
          }
        }
        q"""
        ${clazz.mods} trait ${clazz.name} extends ..${clazz.impl.parents} {
          ..$impl
        }"""
    }
    c.Expr[Any](expandee)
  }

  def generateComponentsImpl[T : c.WeakTypeTag,
      R: c.WeakTypeTag](c: Context)
      (trees: c.Expr[String], commonName: c.Expr[String],
      callback: c.Expr[String],
      excluded: c.Expr[String]): c.Expr[List[PartialFunction[T, R]]] = {

    import c.universe._

    val Literal(Constant(commonNameString: String))   = commonName.tree
    val Literal(Constant(callbackString: String))     = callback.tree
    val treeList                                      = {
      val duplicated = trees.tree.duplicate
      val constant   = c.Expr[String](c.untypecheck(duplicated))
      c.eval[String](constant).split(",").map(_.trim)
    }.toList
    val excludedTrees                                 = {
      val duplicated = excluded.tree.duplicate
      val constant   = c.Expr[String](c.untypecheck(duplicated))
      c.eval[String](constant).split(",").map(_.trim)
    }.toList

    val components = for {
      tree <- treeList if !excludedTrees.contains(tree)
    } yield {
      val cbName    = TermName(callbackString)
      val clazzName = TypeName(tree + commonNameString)
{'fraction_non_alphanumeric': 0.12419774501300954, 'fraction_numerical': 0.0006938421509106678, 'mean_word_length': 2.2086811352253757, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5917653', 'n_tokens_mistral': 1797, 'n_tokens_neox': 1729, 'n_words': 366}