scala.reflect.macros.blackbox Scala Examples

The following examples show how to use scala.reflect.macros.blackbox. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: TransactionMacros.scala    From scarango   with MIT License 5 votes vote down vote up
package com.outr.arango.transaction

import com.outr.arango.Graph

import scala.annotation.compileTimeOnly
import scala.concurrent.Future
import scala.reflect.macros.blackbox

@compileTimeOnly("Enable macro paradise to expand compile-time macros")
object TransactionMacros {
  def simple[G <: Graph, R](c: blackbox.Context)
                                (transaction: c.Expr[(G) => Future[R]])
                                (implicit g: c.WeakTypeTag[G]): c.Expr[Future[R]] = {
    import c.universe._

    c.Expr[Future[R]](
      q"""
        import com.outr.arango.transaction._
        import scribe.Execution.global


       """)

    ???
  }
} 
Example 2
Source File: GraphMacros.scala    From scarango   with MIT License 5 votes vote down vote up
package com.outr.arango

import scala.annotation.compileTimeOnly
import scala.reflect.macros.blackbox

@compileTimeOnly("Enable macro paradise to expand compile-time macros")
object GraphMacros {
  def store[T](c: blackbox.Context)
              (key: c.Expr[String])
              (implicit t: c.WeakTypeTag[T]): c.Expr[DatabaseStore[T]] = {
    import c.universe._

    val graph = c.prefix
    val tree =
      q"""
         DatabaseStore[$t]($key, $graph, Serialization.auto[$t])
       """
    c.Expr[DatabaseStore[T]](tree)
  }

  def queryBuilderAs[D](c: blackbox.Context)(implicit d: c.WeakTypeTag[D]): c.Expr[QueryBuilder[D]] = {
    import c.universe._

    val builder = c.prefix
    if (d.tpe <:< typeOf[Document[_]] && d.tpe.companion <:< typeOf[DocumentModel[_]]) {
      c.Expr[QueryBuilder[D]](q"$builder.as[$d](${d.tpe.typeSymbol.companion}.serialization)")
    } else {
      c.Expr[QueryBuilder[D]](q"$builder.as[$d](_root_.com.outr.arango.Serialization.auto[$d])")
    }
  }

  def vertex[D <: Document[D]](c: blackbox.Context)
                              (implicit d: c.WeakTypeTag[D]): c.Expr[Collection[D]] = {
    import c.universe._

    val graph = c.prefix
    val companion = d.tpe.typeSymbol.companion
    c.Expr[Collection[D]](
      q"""
         import com.outr.arango._

         new Collection[$d]($graph, $companion, CollectionType.Document, $companion.indexes, None)
       """)
  }

  def edge[D <: Document[D]](c: blackbox.Context)
                            (implicit d: c.WeakTypeTag[D]): c.Expr[Collection[D]] = {
    import c.universe._

    val graph = c.prefix
    val companion = d.tpe.typeSymbol.companion
    c.Expr[Collection[D]](
      q"""
         import com.outr.arango._

         new Collection[$d]($graph, $companion, CollectionType.Edge, $companion.indexes, None)
       """)
  }
} 
Example 3
Source File: Macros.scala    From scarango   with MIT License 5 votes vote down vote up
package com.outr.arango

import scala.annotation.compileTimeOnly
import scala.reflect.macros.blackbox

@compileTimeOnly("Enable macro paradise to expand compile-time macros")
object Macros {
  def serializationAuto[D](c: blackbox.Context)
                          (implicit d: c.WeakTypeTag[D]): c.Expr[Serialization[D]] = {
    import c.universe._

    c.Expr[Serialization[D]](
      q"""
         import _root_.com.outr.arango._
         import _root_.profig._
         import _root_.io.circe.Json

         Serialization[$d](
           doc2Json = (d: $d) => JsonUtil.toJson[$d](d),
           json2Doc = (j: Json) => JsonUtil.fromJson[$d](j)
         )
       """)
  }
} 
Example 4
Source File: FUUID.scala    From fuuid   with MIT License 5 votes vote down vote up
package io.chrisdavenport.fuuid

import cats._
import cats.implicits._
import cats.effect.Sync
import java.util.UUID

import scala.reflect.macros.blackbox

final class FUUID private (private val uuid: UUID){

  // Direct show method so people do not use toString
  def show: String = uuid.show
  // -1 less than, 0 equal to, 1 greater than
  def compare(that: FUUID): Int = this.uuid.compareTo(that.uuid)

  // Returns 0 when equal
  def eqv(that: FUUID): Boolean = compare(that) == 0

  override def equals(obj: scala.Any): Boolean = obj match {
    case that: FUUID => eqv(that)
    case _ => false
  }
  override def hashCode: Int = uuid.hashCode
  override def toString: String = uuid.toString

}

object FUUID {
  implicit val instancesFUUID: Hash[FUUID] with Order[FUUID] with Show[FUUID] =
    new Hash[FUUID] with Order[FUUID] with Show[FUUID]{
      override def show(t: FUUID): String = t.show
      override def eqv(x: FUUID, y: FUUID): Boolean = x.eqv(y)
      override def hash(x: FUUID): Int = x.hashCode
      override def compare(x: FUUID, y: FUUID): Int = x.compare(y)
    }

  def fromString(s: String): Either[Throwable, FUUID] =
    Either.catchNonFatal(new FUUID(UUID.fromString(s)))

  def fromStringOpt(s: String): Option[FUUID] = 
    fromString(s).toOption

  def fromStringF[F[_]](s: String)(implicit AE: ApplicativeError[F, Throwable]): F[FUUID] =
    fromString(s).fold(AE.raiseError, AE.pure)

  def fromUUID(uuid: UUID): FUUID = new FUUID(uuid)

  def randomFUUID[F[_]: Sync]: F[FUUID] = Sync[F].delay(
    new FUUID(UUID.randomUUID)
  )

  def fuuid(s: String): FUUID = macro Macros.fuuidLiteral

  private[FUUID] class Macros(val c: blackbox.Context) {
    import c.universe._
    def fuuidLiteral(s: c.Expr[String]): c.Expr[FUUID] =
      s.tree match {
        case Literal(Constant(s: String))=>
            fromString(s)
            .fold(
              e => c.abort(c.enclosingPosition, e.getMessage.replace("UUID", "FUUID")),
              _ => c.Expr(q"""
                @SuppressWarnings(Array("org.wartremover.warts.Throw"))
                val fuuid = _root_.io.chrisdavenport.fuuid.FUUID.fromString($s).fold(throw _, _root_.scala.Predef.identity)
                fuuid
              """)
            )
        case _ =>
          c.abort(
            c.enclosingPosition,
            s"This method uses a macro to verify that a FUUID literal is valid. Use FUUID.fromString if you have a dynamic value you want to parse as an FUUID."
          )
      }
  }

  
  object Unsafe {
    def toUUID(fuuid: FUUID): UUID = fuuid.uuid
    def withUUID[A](fuuid: FUUID)(f: UUID => A): A = f(fuuid.uuid)
  }

} 
Example 5
Source File: DisposableFunctionClientFactoryMacro.scala    From scala-json-rpc   with MIT License 5 votes vote down vote up
package io.github.shogowada.scala.jsonrpc.client

import io.github.shogowada.scala.jsonrpc.common.JSONRPCMacroUtils

import scala.concurrent.Future
import scala.reflect.macros.blackbox

class DisposableFunctionClientFactoryMacro[CONTEXT <: blackbox.Context](val c: CONTEXT) {

  import c.universe._

  private lazy val macroUtils = JSONRPCMacroUtils[c.type](c)
  private lazy val methodClientFactoryMacro = new JSONRPCMethodClientFactoryMacro[c.type](c)

  def getOrCreate(
      client: c.Tree,
      server: c.Tree,
      disposableFunctionMethodName: c.Tree,
      disposableFunctionType: c.Type
  ): c.Tree = {
    val disposableFunctionRepository = macroUtils.getDisposableFunctionRepository(server)

    val newDisposableFunction = create(client, server, disposableFunctionType, disposableFunctionMethodName)

    q"""
        $disposableFunctionRepository
            .getOrAdd($disposableFunctionMethodName, () => $newDisposableFunction)
            .asInstanceOf[$disposableFunctionType]
        """
  }

  private def create(
      client: c.Tree,
      server: c.Tree,
      disposableFunctionType: c.Type,
      disposableFunctionMethodName: c.Tree
  ): c.Tree = {
    val typeArgs: Seq[Type] = disposableFunctionType.typeArgs
    val paramTypes: Seq[Type] = typeArgs.init
    val returnType: Type = typeArgs.last
    val function = methodClientFactoryMacro.createAsFunction(client, Some(server), disposableFunctionMethodName, paramTypes, returnType)

    val disposeMethod = createDisposeMethod(server, client, disposableFunctionMethodName)

    def getApplyParameterName(index: Int) = TermName(s"v$index")

    val applyParameters: Seq[Tree] = paramTypes.zipWithIndex
        .map { case (paramType, index) =>
          val paramName = getApplyParameterName(index)
          q"$paramName: $paramType"
        }
    val applyParameterNames = paramTypes.indices
        .map(getApplyParameterName)

    q"""
        new $disposableFunctionType {
          override val identifier = $function

          override def apply(..$applyParameters) = $function(..$applyParameterNames)

          $disposeMethod
        }
        """
  }

  private def createDisposeMethod(
      server: Tree,
      client: Tree,
      disposableFunctionMethodName: Tree
  ): Tree = {
    val disposableFunctionRepository = macroUtils.getDisposableFunctionRepository(server)

    val disposeClient = methodClientFactoryMacro.createAsFunction(
      client,
      Some(server),
      q"Constants.DisposeMethodName",
      Seq(macroUtils.getType[String]),
      macroUtils.getType[Future[Unit]]
    )

    q"""
        override def dispose(): Future[Unit] = {
          $disposableFunctionRepository.remove($disposableFunctionMethodName)
          $disposeClient($disposableFunctionMethodName)
        }
        """
  }
} 
Example 6
Source File: DisposableFunctionServerFactoryMacro.scala    From scala-json-rpc   with MIT License 5 votes vote down vote up
package io.github.shogowada.scala.jsonrpc.server

import io.github.shogowada.scala.jsonrpc.common.JSONRPCMacroUtils

import scala.reflect.macros.blackbox

class DisposableFunctionServerFactoryMacro[Context <: blackbox.Context](val c: Context) {

  import c.universe._

  private lazy val macroUtils = JSONRPCMacroUtils[c.type](c)
  private lazy val requestJSONHandlerFactoryMacro = new JSONRPCRequestJSONHandlerFactoryMacro[c.type](c)

  def getOrCreate(
      client: Tree,
      server: Tree,
      disposableFunction: Tree,
      disposableFunctionType: Type
  ): Tree = {
    val requestJSONHandlerRepository = macroUtils.getRequestJSONHandlerRepository(server)
    val disposableFunctionMethodNameRepository = macroUtils.getDisposableFunctionMethodNameRepository(client)

    val disposeFunctionMethodHandler = requestJSONHandlerFactoryMacro.createDisposeFunctionMethodHandler(server, client)

    val handler = requestJSONHandlerFactoryMacro.createFromDisposableFunction(client, server, disposableFunction, disposableFunctionType)

    q"""
        $requestJSONHandlerRepository.addIfAbsent(Constants.DisposeMethodName, () => ($disposeFunctionMethodHandler))

        val methodName: String = $disposableFunctionMethodNameRepository.getOrAddAndNotify(
          $disposableFunction,
          (newMethodName) => { $requestJSONHandlerRepository.add(newMethodName, $handler) }
        )
        methodName
        """
  }
} 
Example 7
Source File: JSONRPCParameterFactory.scala    From scala-json-rpc   with MIT License 5 votes vote down vote up
package io.github.shogowada.scala.jsonrpc.common

import scala.reflect.macros.blackbox

object JSONRPCParameterFactory {
  def apply[Context <: blackbox.Context](c: Context): JSONRPCParameterFactory[c.type] =
    new JSONRPCParameterFactory[c.type](c)
}

class JSONRPCParameterFactory[Context <: blackbox.Context](val c: Context) {

  import c.universe._

  private lazy val valueFactory = JSONRPCValueFactory[c.type](c)

  def jsonRPCToScala(
      server: Tree,
      maybeClient: Option[Tree],
      argument: Tree,
      argumentType: Type
  ): Tree = {
    valueFactory.jsonRPCToScala(
      maybeClient = maybeClient,
      maybeServer = Option(server),
      argument,
      argumentType
    )
  }

  def jsonRPCType(paramTypes: Seq[c.Type]): Tree = {
    val parameterTypes: Iterable[Tree] = paramTypes
        .map(jsonRPCType)

    if (parameterTypes.size == 1) {
      val parameterType = parameterTypes.head
      tq"Tuple1[$parameterType]"
    } else {
      tq"(..$parameterTypes)"
    }
  }

  private def jsonRPCType(paramType: Type): Tree = {
    valueFactory.jsonRPCType(paramType)
  }

  def scalaToJSONRPC(
      client: Tree,
      maybeServer: Option[Tree],
      parameter: Tree,
      parameterType: Type
  ): Tree = {
    valueFactory.scalaToJSONRPC(
      maybeClient = Option(client),
      maybeServer = maybeServer,
      value = parameter,
      valueType = parameterType
    )
  }
} 
Example 8
Source File: JSONRPCResultFactory.scala    From scala-json-rpc   with MIT License 5 votes vote down vote up
package io.github.shogowada.scala.jsonrpc.common

import scala.reflect.macros.blackbox

object JSONRPCResultFactory {
  def apply[Context <: blackbox.Context](c: Context): JSONRPCResultFactory[c.type] =
    new JSONRPCResultFactory[c.type](c)
}

class JSONRPCResultFactory[Context <: blackbox.Context](val c: Context) {

  import c.universe._

  private lazy val valueFactory = JSONRPCValueFactory[c.type](c)

  def jsonRPCToScala(
      client: Tree,
      maybeServer: Option[Tree],
      result: Tree,
      resultType: Type
  ): Tree = {
    valueFactory.jsonRPCToScala(
      maybeClient = Option(client),
      maybeServer = maybeServer,
      value = result,
      valueType = resultType
    )
  }

  def jsonRPCType(resultType: Type): Tree = {
    valueFactory.jsonRPCType(resultType)
  }

  def scalaToJSONRPC(
      server: Tree,
      maybeClient: Option[Tree],
      result: Tree,
      resultType: Type
  ): Tree = {
    valueFactory.scalaToJSONRPC(
      maybeServer = Option(server),
      maybeClient = maybeClient,
      value = result,
      valueType = resultType
    )
  }
} 
Example 9
Source File: UpickleJSONSerializer.scala    From scala-json-rpc   with MIT License 5 votes vote down vote up
package io.github.shogowada.scala.jsonrpc.serializers

import upickle.Js

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

object JSONRPCPickler extends upickle.AttributeTagged {
  override implicit def OptionW[T: Writer]: Writer[Option[T]] = {
    Writer {
      case None => Js.Null
      case Some(value) => implicitly[Writer[T]].write(value)
    }
  }

  override implicit def OptionR[T: Reader]: Reader[Option[T]] = {
    Reader {
      case Js.Null => None
      case value: Js.Value => Some(implicitly[Reader[T]].read(value))
    }
  }

  implicit def IdW: Writer[Either[String, BigDecimal]] = {
    Writer[Either[String, BigDecimal]] {
      case Left(value) => writeJs(value)
      case Right(value) => writeJs(value)
    }
  }

  implicit def IdR: Reader[Either[String, BigDecimal]] = {
    Reader[Either[String, BigDecimal]] {
      case value: Js.Str => Left(readJs[String](value))
      case value: Js.Num => Right(readJs[BigDecimal](value))
    }
  }
}

class UpickleJSONSerializer extends JSONSerializer {
  override def serialize[T](value: T): Option[String] = macro UpickleJSONSerializerMacro.serialize[T]

  override def deserialize[T](json: String): Option[T] = macro UpickleJSONSerializerMacro.deserialize[T]
}

object UpickleJSONSerializer {
  def apply() = new UpickleJSONSerializer
}


object UpickleJSONSerializerMacro {
  def serialize[T](c: blackbox.Context)(value: c.Expr[T]): c.Expr[Option[String]] = {
    import c.universe._

    c.Expr[Option[String]](
      q"""
          scala.util.Try(io.github.shogowada.scala.jsonrpc.serializers.JSONRPCPickler.write($value)).toOption
          """
    )
  }

  def deserialize[T: c.WeakTypeTag](c: blackbox.Context)(json: c.Expr[String]): c.Expr[Option[T]] = {
    import c.universe._

    val deserializeType = weakTypeOf[T]

    c.Expr[Option[T]](
      q"""
          scala.util.Try(io.github.shogowada.scala.jsonrpc.serializers.JSONRPCPickler.read[$deserializeType]($json)).toOption
          """
    )
  }
} 
Example 10
Source File: CirceJSONSerializer.scala    From scala-json-rpc   with MIT License 5 votes vote down vote up
package io.github.shogowada.scala.jsonrpc.serializers

import io.circe.{Decoder, Encoder, Error, Json}

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

object CirceJSONCoder {
  def encode[T](value: T)(implicit encoder: Encoder[T]): Json = {
    encoder(value)
  }

  def decode[T](json: String)(implicit decoder: Decoder[T]): Either[Error, T] = {
    io.circe.parser.decode[T](json)
  }
}

class CirceJSONSerializer extends JSONSerializer {
  override def serialize[T](value: T): Option[String] = macro CirceJSONSerializerMacro.serialize[T]

  override def deserialize[T](json: String): Option[T] = macro CirceJSONSerializerMacro.deserialize[T]
}

object CirceJSONSerializer {
  def apply(): CirceJSONSerializer = {
    new CirceJSONSerializer
  }
}

object CirceJSONSerializerMacro {
  def serialize[T](c: blackbox.Context)(value: c.Expr[T]): c.Expr[Option[String]] = {
    import c.universe._

    c.Expr[Option[String]](
      q"""
          {
            import io.circe.generic.auto._
            scala.util.Try(io.circe.Printer.noSpaces.pretty(io.github.shogowada.scala.jsonrpc.serializers.CirceJSONCoder.encode($value))).toOption
          }
          """
    )
  }

  def deserialize[T: c.WeakTypeTag](c: blackbox.Context)(json: c.Expr[String]): c.Expr[Option[T]] = {
    import c.universe._

    val deserializeType = weakTypeOf[T]

    c.Expr[Option[T]](
      q"""
          {
            import io.circe.generic.auto._
            io.github.shogowada.scala.jsonrpc.serializers.CirceJSONCoder.decode[$deserializeType]($json).toOption
          }
          """
    )
  }
} 
Example 11
Source File: Mergeable.scala    From scalajs-react-bootstrap   with MIT License 5 votes vote down vote up
package com.acework.js.utils

import scala.reflect.macros.blackbox



trait Common {

  def getFieldNamesAndTypes(c: blackbox.Context)(tpe: c.universe.Type): Iterable[(c.universe.Name, c.universe.Type)] = {
    import c.universe._

    object CaseField {
      def unapply(trmSym: TermSymbol): Option[(Name, Type)] = {
        if (trmSym.isVal && trmSym.isCaseAccessor)
          Some((TermName(trmSym.name.toString.trim), trmSym.typeSignature))
        else
          None
      }
    }

    tpe.decls.collect {
      case CaseField(nme, tpe) =>
        (nme, tpe)
    }
  }
}

trait Mergeable[T] {
  def merge(t: T, map: Map[String, Any]): T
}

object Mergeable {

  implicit def materializeMergeable[T]: Mergeable[T] = macro materializeMergeableImpl[T]

  def materializeMergeableImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[Mergeable[T]] = {
    import c.universe._
    val tpe = weakTypeOf[T]
    val companion: Symbol = tpe.typeSymbol.companion

    // get fields from primary constructor
    val fields = tpe.decls.collectFirst {
      case m: MethodSymbol if m.isPrimaryConstructor => m
    }.get.paramLists.head

    val fromMapParams = fields.map { field =>
      val name = field.asTerm.name
      val decoded = name.decodedName.toString
      val returnType = tpe.decl(name).typeSignature
      q"map.getOrElse($decoded, t.$name).asInstanceOf[$returnType]"
    }

    //val params: Iterable[Name] = tpe.decls.collect {
    //  case param if param.isMethod && param.asMethod.isCaseAccessor => param.name
    // }

    c.Expr[Mergeable[T]] { q"""
      new Mergeable[$tpe] {
        def merge(t: $tpe, map: Map[String, Any]) = $companion(..$fromMapParams)
      }
    """
    }
  }
} 
Example 12
Source File: package.scala    From refined   with MIT License 5 votes vote down vote up
package eu.timepit.refined

import _root_.scalaz.{@@, Contravariant, Equal, MonadError, Show}
import eu.timepit.refined.api.{RefType, Validate}
import scala.reflect.macros.blackbox

package object scalaz {

  implicit val scalazTagRefType: RefType[@@] =
    new RefType[@@] {
      override def unsafeWrap[T, P](t: T): T @@ P =
        t.asInstanceOf[T @@ P]

      override def unwrap[T](tp: T @@ _): T =
        tp.asInstanceOf[T]

      override def unsafeRewrap[T, A, B](ta: T @@ A): T @@ B =
        ta.asInstanceOf[T @@ B]

      override def unsafeWrapM[T: c.WeakTypeTag, P: c.WeakTypeTag](
          c: blackbox.Context
      )(t: c.Expr[T]): c.Expr[T @@ P] =
        c.universe.reify(t.splice.asInstanceOf[T @@ P])

      override def unsafeRewrapM[T: c.WeakTypeTag, A: c.WeakTypeTag, B: c.WeakTypeTag](
          c: blackbox.Context
      )(ta: c.Expr[T @@ A]): c.Expr[T @@ B] =
        c.universe.reify(ta.splice.asInstanceOf[T @@ B])
    }

  
  implicit def refTypeShow[F[_, _], T: Show, P](implicit rt: RefType[F]): Show[F[T, P]] =
    scalaz.derivation.refTypeViaContravariant[F, Show, T, P]

  @deprecated("Generic derivation instances have been moved into the `derivation` object", "0.9.4")
  def refTypeContravariant[R[_, _], F[_], A, B](
      implicit
      C: Contravariant[F],
      R: RefType[R],
      F: F[A]
  ): F[R[A, B]] =
    scalaz.derivation.refTypeViaContravariant[R, F, A, B]

  @deprecated("Generic derivation instances have been moved into the `derivation` object", "0.9.4")
  def refTypeMonadError[R[_, _], F[_], A, B](
      implicit
      M: MonadError[F, String],
      R: RefType[R],
      V: Validate[A, B],
      F: F[A]
  ): F[R[A, B]] =
    scalaz.derivation.refTypeViaMonadError[R, F, A, B]
} 
Example 13
Source File: MacroUtils.scala    From refined   with MIT License 5 votes vote down vote up
package eu.timepit.refined.macros

import eu.timepit.refined.api.{Refined, RefType}
import scala.reflect.macros.blackbox
import scala.util.{Success, Try}
import shapeless.tag.@@

trait MacroUtils {
  val c: blackbox.Context
  import c.universe.weakTypeOf

  def abort(msg: String): Nothing =
    c.abort(c.enclosingPosition, msg)

  def eval[T](t: c.Expr[T]): T = {
    // Duplicate and untypecheck before calling `eval`, see:
    // http://www.scala-lang.org/api/2.12.0/scala-reflect/scala/reflect/macros/Evals.html#eval[T]%28expr:Evals.this.Expr[T]%29:T
    val expr = c.Expr[T](c.untypecheck(t.tree.duplicate))

    // Try evaluating expr twice before failing, see
    // https://github.com/fthomas/refined/issues/3
    tryN(2, c.eval(expr))
  }

  def tryN[T](n: Int, t: => T): T =
    Stream.fill(n)(Try(t)).collectFirst { case Success(r) => r }.getOrElse(t)

  protected def refTypeInstance[F[_, _]](rt: c.Expr[RefType[F]]): RefType[F] =
    if (rt.tree.tpe =:= weakTypeOf[RefType[Refined]])
      RefType.refinedRefType.asInstanceOf[RefType[F]]
    else if (rt.tree.tpe =:= weakTypeOf[RefType[@@]])
      RefType.tagRefType.asInstanceOf[RefType[F]]
    else
      eval(rt)
} 
Example 14
Source File: InferMacro.scala    From refined   with MIT License 5 votes vote down vote up
package eu.timepit.refined.macros

import eu.timepit.refined.api.Inference.==>
import eu.timepit.refined.api.RefType
import eu.timepit.refined.internal.Resources
import scala.reflect.macros.blackbox

class InferMacro(val c: blackbox.Context) extends MacroUtils {
  import c.universe._

  def impl[F[_, _], T: c.WeakTypeTag, A: c.WeakTypeTag, B: c.WeakTypeTag](ta: c.Expr[F[T, A]])(
      rt: c.Expr[RefType[F]],
      ir: c.Expr[A ==> B]
  ): c.Expr[F[T, B]] = {

    val inference = eval(ir)
    if (inference.notValid) {
      abort(Resources.invalidInference(weakTypeOf[A].toString, weakTypeOf[B].toString))
    }

    refTypeInstance(rt).unsafeRewrapM(c)(ta)
  }
} 
Example 15
Source File: LiteralMatchers.scala    From refined   with MIT License 5 votes vote down vote up
package eu.timepit.refined.macros

import scala.reflect.macros.blackbox

trait LiteralMatchers {
  val c: blackbox.Context
  import c.universe._

  private[macros] object BigIntMatcher {
    def unapply(expr: c.Tree): Option[BigInt] = expr match {
      case q"scala.`package`.BigInt.apply(${lit: Literal})" =>
        lit.value.value match {
          case i: Int    => Some(BigInt(i))
          case l: Long   => Some(BigInt(l))
          case s: String => scala.util.Try(BigInt(s)).toOption
          case _         => None
        }
      case _ => None
    }
  }

  private[macros] object BigDecimalMatcher {
    def unapply(expr: c.Tree): Option[BigDecimal] = {
      val constant = expr match {
        case q"scala.`package`.BigDecimal.apply(${lit: Literal})"   => Some(lit.value.value)
        case q"scala.`package`.BigDecimal.exact(${lit: Literal})"   => Some(lit.value.value)
        case q"scala.`package`.BigDecimal.valueOf(${lit: Literal})" => Some(lit.value.value)
        case _                                                      => None
      }

      constant.flatMap {
        case i: Int    => Some(BigDecimal(i))
        case l: Long   => Some(BigDecimal(l))
        case d: Double => Some(BigDecimal(d))
        case s: String => scala.util.Try(BigDecimal(s)).toOption
        case _         => None
      }
    }
  }

} 
Example 16
Source File: RefineMacro.scala    From refined   with MIT License 5 votes vote down vote up
package eu.timepit.refined.macros

import eu.timepit.refined.api.{RefType, Validate}
import eu.timepit.refined.char.{Digit, Letter, LowerCase, UpperCase, Whitespace}
import eu.timepit.refined.collection.NonEmpty
import eu.timepit.refined.internal.Resources
import eu.timepit.refined.numeric.{Negative, NonNegative, NonPositive, Positive}
import scala.reflect.macros.blackbox

class RefineMacro(val c: blackbox.Context) extends MacroUtils with LiteralMatchers {

  import c.universe._

  def impl[F[_, _], T: c.WeakTypeTag, P: c.WeakTypeTag](t: c.Expr[T])(
      rt: c.Expr[RefType[F]],
      v: c.Expr[Validate[T, P]]
  ): c.Expr[F[T, P]] = {
    val tValue: T = t.tree match {
      case Literal(Constant(value)) => value.asInstanceOf[T]
      case BigDecimalMatcher(value) => value.asInstanceOf[T]
      case BigIntMatcher(value)     => value.asInstanceOf[T]
      case _                        => abort(Resources.refineNonCompileTimeConstant)
    }

    val validate = validateInstance(v)
    val res = validate.validate(tValue)
    if (res.isFailed) {
      abort(validate.showResult(tValue, res))
    }

    refTypeInstance(rt).unsafeWrapM(c)(t)
  }

  def implApplyRef[FTP, F[_, _], T: c.WeakTypeTag, P: c.WeakTypeTag](t: c.Expr[T])(
      ev: c.Expr[F[T, P] =:= FTP],
      rt: c.Expr[RefType[F]],
      v: c.Expr[Validate[T, P]]
  ): c.Expr[FTP] =
    c.Expr[FTP](impl(t)(rt, v).tree)

  private def validateInstance[T, P](v: c.Expr[Validate[T, P]])(
      implicit
      T: c.WeakTypeTag[T],
      P: c.WeakTypeTag[P]
  ): Validate[T, P] =
    validateInstances
      .collectFirst {
        case (tpeT, instancesForT) if tpeT =:= T.tpe =>
          instancesForT.collectFirst {
            case (tpeP, validate) if tpeP =:= P.tpe =>
              validate.asInstanceOf[Validate[T, P]]
          }
      }
      .flatten
      .getOrElse(eval(v))

  private val validateInstances: List[(Type, List[(Type, Any)])] = {
    def instance[T, P](implicit P: c.WeakTypeTag[P], v: Validate[T, P]): (Type, Validate[T, P]) =
      P.tpe -> v

    List(
      weakTypeOf[Int] -> List(
        instance[Int, Positive],
        instance[Int, NonPositive],
        instance[Int, Negative],
        instance[Int, NonNegative]
      ),
      weakTypeOf[Long] -> List(
        instance[Long, Positive],
        instance[Long, NonPositive],
        instance[Long, Negative],
        instance[Long, NonNegative]
      ),
      weakTypeOf[Double] -> List(
        instance[Double, Positive],
        instance[Double, NonPositive],
        instance[Double, Negative],
        instance[Double, NonNegative]
      ),
      weakTypeOf[String] -> List(
        instance[String, NonEmpty]
      ),
      weakTypeOf[Char] -> List(
        instance[Char, Digit],
        instance[Char, Letter],
        instance[Char, LowerCase],
        instance[Char, UpperCase],
        instance[Char, Whitespace]
      )
    )
  }
} 
Example 17
Source File: virtualize.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import language.experimental.macros
import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox


    val inputs = annottees.toList
    val outputs = inputs match {
      case (a:ValDef) :: as if a.mods.hasFlag(Flag.PARAM) =>
        c.warning(c.enclosingPosition, "@virtualize cannot be used on parameters.")
        inputs
      case (_:TypeDef) :: as =>
        c.warning(c.enclosingPosition, "@virtualize cannot be used on type aliases.")
        inputs

      case a :: as => runVirtualizer(a) ::: as
      case Nil     => Nil
    }

    //info(showCode(outputs.head))

    q"..$outputs"
  }
} 
Example 18
Source File: rig.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox
import scala.language.experimental.macros

final class rig extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro rig.impl
}

object rig {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val withCtx   = ctx.impl(c)(annottees:_*)
    val withState = stateful.impl(c)(withCtx)
    withState
  }
} 
Example 19
Source File: rewrite.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import utils.tags.MacroUtils

import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox
import scala.language.experimental.macros

final class rewrite extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro rewrite.impl
}

object rewrite {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val util = new MacroUtils[c.type](c)
    import c.universe._
    import util._

    annottees.head match {
      case _:DefDef =>
      case _ => c.error(c.enclosingPosition, "Rewrite can only be used on defs")
    }
    def incorrectSignature(): Unit = {
      c.error(c.enclosingPosition, "Rewrite def must have signature 'def name(rhs: T): Unit")
    }
    def noImplicitsAllowed(): Unit = {
      c.error(c.enclosingPosition, "Rewrite def cannot have implicit parameters")
    }
    def noTypeParametersAllowed(): Unit = {
      c.error(c.enclosingPosition, "Rewrite def cannot have type parameters")
    }

    val tree = api.impl(c)(annottees:_*) match {
      case d: DefDef =>
        val paramss = d.paramss
        if (paramss.length != 2) incorrectSignature()
        else if (paramss.head.length != 1) incorrectSignature()
        else if (paramss(1).length != 2) noImplicitsAllowed()
        else if (d.tparams.nonEmpty) noTypeParametersAllowed()

        val arg0 = paramss.head.head
        val name = Literal(Constant(d.name.toString))
        d.rhs match {
          case Match(_,_) =>
          case _ => c.error(c.enclosingPosition, "Rewrite rule must be a partial function")
        }

        val pf =
          q"""val ${d.name}: PartialFunction[(Op[_],SrcCtx,State),Option[Sym[_]]] = {case (__op,__ctx,__state) =>
            val ${arg0.name} = __op.asInstanceOf[${arg0.tp.get}];
            implicit val ctx = __ctx;
            implicit val state = __state;
            val func: PartialFunction[Op[_],Sym[_]] = ${d.rhs}
            if (func.isDefinedAt(${arg0.name})) Some(func.apply(${arg0.name})) else None
          }
          """
        val add = if (!showCode(arg0.tp.get).startsWith("Op[")) {
          q"""IR.rewrites.add[${arg0.tp.get}]($name,${d.name})"""
        }
        else {
          q"""IR.rewrites.addGlobal($name,${d.name})"""
        }
        q"$pf; $add"

      case t =>
        invalidAnnotationUse("rewrite", "defs")
        t
    }
    //c.info(c.enclosingPosition, showCode(tree), force = true)
    tree
  }
} 
Example 20
Source File: stateful.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import utils.tags.MacroUtils

import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox


final class stateful extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro stateful.impl
}

private[forge] object stateful {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val util = new MacroUtils[c.type](c)
    import util._
    import c.universe._

    def injectState(df: DefDef) = df.injectImplicit("state", tq"argon.State", tq"State")

    val tree = annottees.head match {
      case df: DefDef    => injectState(df)
      case mf: ModuleDef => mf.mapMethods(injectState)
      case _ => invalidAnnotationUse("stateful", "objects", "defs")
    }
    tree
  }
} 
Example 21
Source File: ctx.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import utils.tags.MacroUtils

import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox
import scala.language.experimental.macros

final class ctx extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro ctx.impl
}

private[forge] object ctx {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val util = new MacroUtils[c.type](c)
    import util._
    import c.universe._

    val tree = annottees.head match {
      case df: DefDef => df.injectImplicit("ctx", tq"forge.SrcCtx", tq"SrcCtx")
      case _ => invalidAnnotationUse("ctx", "defs")
    }
    tree
  }
} 
Example 22
Source File: AppTag.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import language.experimental.macros
import scala.reflect.macros.blackbox

class AppTag(dsl: String, dslApp: String) {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val util = new Virtualizer[c.type](c)
    import util._
    import c.universe._

    val appType = Ident(TypeName(dslApp))
    val inputs = annottees.toList
    val outputs: List[Tree] = inputs match {
      case (a:ValDef) :: as if !a.mods.hasFlag(Flag.PARAM) =>
        runVirtualizer(a) ::: as
      case (a:DefDef) :: as =>
        runVirtualizer(a) ::: as
      case (a:ClassDef) :: as =>
        val mod = a.mixIn(appType)
        runVirtualizer(mod) ::: as
      case (a:ModuleDef) :: as =>
        val mod = a.mixIn(appType)
        runVirtualizer(mod) ::: as
      case _ => invalidAnnotationUse(dsl, "classes", "objects", "traits", "defs")
    }

    //info(showCode(outputs.head))

    q"..$outputs"
  }
} 
Example 23
Source File: curriedUpdate.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox


class curriedUpdate extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro curriedUpdate.impl
}

object curriedUpdate {
  private val updateRenamed = "update$r"

  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    import c.universe._

    annottees.head match {
      case DefDef(mods, TermName(name), tparams, vparamss, tpt, rhs) =>
        if (name.toString != "update")
          c.abort(c.enclosingPosition, "curriedUpdate can only be applied to the update method")
        if (vparamss.size != 3)
          c.abort(c.enclosingPosition, "curriedUpdate must have three argument list")
        if (vparamss.head.isEmpty)
          c.abort(c.enclosingPosition, "The first argument list must not be empty")
        if (vparamss(1).size != 1)
          c.abort(c.enclosingPosition, "The second argument list must have only one element")
        if (vparamss(2).size != 2)
          c.abort(c.enclosingPosition, "The third argument list must have two elements")

        val imprt   = q"import scala.language.experimental.macros"
        val updateR = DefDef(mods, TermName(updateRenamed), tparams, vparamss, tpt, rhs)
        val updateC = if (mods.hasFlag(Flag.OVERRIDE)) {
          q"override def update(values: Any*): Unit = macro forge.tags.curriedUpdate.updateMacroDispatcher"
        }
        else {
          q"def update(values: Any*): Unit = macro forge.tags.curriedUpdate.updateMacroDispatcher"
        }

        val result = q"$imprt ; $updateR ; $updateC"

        //c.info(c.enclosingPosition, showCode(result), true)
        result

      case _ =>
        c.abort(c.enclosingPosition, "curriedUpdate can only be applied on defs")
    }
  }

  def updateMacroDispatcher(c: blackbox.Context)(values: c.Tree*): c.Tree = {
    import c.universe._

    val inds = values.take(values.size - 3)
    val value = values(values.size - 3)
    val ctx = values(values.size - 2)
    val state = values(values.size - 1)
    val self = c.prefix.tree
    q"$self.${TermName(updateRenamed)}(..$inds)($value)($ctx, $state)"
  }
} 
Example 24
Source File: mod.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import utils.tags.MacroUtils

import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox
import scala.language.experimental.macros


final class mod extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro mod.impl
}
object mod {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val util = new MacroUtils[c.type](c)
    import c.universe._
    import util._

    val tree = annottees.head match {
      case cls: ClassDef =>
        val names = cls.constructorArgs.head.map(_.name)

        //cls.asCaseClass.injectMethod(q"final override def names = Seq(..$names)")
        cls

      case t =>
        c.error(c.enclosingPosition, "@mod annotation can only be used on classes.")
        t
    }

    c.info(c.enclosingPosition, showCode(tree), force = true)
    tree
  }
} 
Example 25
Source File: flow.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import utils.tags.MacroUtils

import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox
import scala.language.experimental.macros

final class flow extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro flow.impl
}

object flow {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val util = new MacroUtils[c.type](c)
    import c.universe._
    import util._

    annottees.head match {
      case _:DefDef =>
      case _ => c.error(c.enclosingPosition, "@flow can only be used on defs")
    }
    def incorrectSignature(): Unit = {
      c.error(c.enclosingPosition, "@flow def must have signature 'def name(lhs: Sym[_], rhs: Op[_]): Unit")
    }

    val tree = api.impl(c)(annottees:_*) match {
      case d: DefDef =>
        val paramss = d.paramss
        if (paramss.length != 2) incorrectSignature()
        else if (paramss.head.length != 2) incorrectSignature()
        val arg0 = paramss.head.apply(0)
        val arg1 = paramss.head.apply(1)
        if (!arg0.tp.exists{t => isWildcardType(t, "Sym") } || !arg1.tp.exists{t => isWildcardType(t, "Op")}) {
          incorrectSignature()
        }

        val name = Literal(Constant(d.name.toString))

        val pf =
          q"""val ${d.name}: PartialFunction[(Sym[_],Op[_],forge.SrcCtx,argon.State),Unit] = {case (__sym,__op,__ctx,__state) =>
            val ${arg0.name} = __sym;
            val ${arg1.name} = __op;
            implicit val ctx = __ctx;
            implicit val state = __state;
            ${d.rhs}
          }
          """
        val add =
          q"""
             IR.flows.add($name,${d.name})
           """
        q"$pf; $add"

      case t =>
        __c.error(__c.enclosingPosition, "@flow can only be used on defs")
        t
    }
    //c.info(c.enclosingPosition, showCode(tree), force = true)
    tree
  }
} 
Example 26
Source File: globalRewrite.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import utils.tags.MacroUtils

import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox
import scala.language.experimental.macros

final class globalRewrite extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro globalRewrite.impl
}

object globalRewrite {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val util = new MacroUtils[c.type](c)
    import c.universe._
    import util._

    annottees.head match {
      case _:DefDef =>
      case _ => c.error(c.enclosingPosition, "@globalRewrite can only be used on defs")
    }
    def incorrectSignature(): Unit = {
      c.error(c.enclosingPosition, "@globalRewrite def must have signature 'def name(rhs: T): Unit")
    }
    def noImplicitsAllowed(): Unit = {
      c.error(c.enclosingPosition, "@globalRewrite def cannot have implicit parameters")
    }
    def noTypeParametersAllowed(): Unit = {
      c.error(c.enclosingPosition, "@globalRewrite def cannot have type parameters")
    }

    val tree = api.impl(c)(annottees:_*) match {
      case d: DefDef =>
        val paramss = d.paramss
        if (paramss.length != 2) incorrectSignature()
        else if (paramss.head.length != 1) incorrectSignature()
        else if (paramss(1).length != 2) noImplicitsAllowed()
        else if (d.tparams.nonEmpty) noTypeParametersAllowed()

        val arg0 = paramss.head.head
        val name = Literal(Constant(d.name.toString))
        d.rhs match {
          case Match(_,_) =>
          case _ => c.error(c.enclosingPosition, "@globalRewrite rule must be a partial function")
        }

        val pf =
          q"""val ${d.name}: PartialFunction[(Op[_],SrcCtx,State),Option[Sym[_]]] = {case (__op,__ctx,__state) =>
            if (__op.isInstanceOf[${arg0.tp.get}]) {
              val ${arg0.name} = __op.asInstanceOf[${arg0.tp.get}];
              implicit val ctx = __ctx;
              implicit val state = __state;
              val func: PartialFunction[Op[_],Sym[_]] = ${d.rhs}
              if (func.isDefinedAt(${arg0.name})) Some(func.apply(${arg0.name})) else None
            }
            else None
          }
          """
        val add =
          q"""
             core.rewrites.addGlobal($name,${d.name})
           """
        q"$pf; $add"

      case t =>
        c.error(c.enclosingPosition, "@globalRewrite can only be used on defs")
        t
    }
    c.info(c.enclosingPosition, showCode(tree), force = true)
    tree
  }
} 
Example 27
Source File: SrcCtxMacro.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import forge.SrcCtx

import scala.reflect.macros.blackbox
import scala.language.experimental.macros

object SrcCtxMacro {
  def impl(c: blackbox.Context): c.Expr[SrcCtx] = {
    import c.universe._
    val pos = c.enclosingPosition
    val path = pos.source.path
    val filename = pos.source.file.name
    val line = pos.line
    val column = pos.column
    val lineContent = if (line > 0) Some(pos.source.lineToString(line-1)) else None

    c.Expr(q"forge.SrcCtx($path, $filename, $line, $column, $lineContent)")
  }
} 
Example 28
Source File: data.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import utils.tags.MacroUtils

import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox
import scala.language.experimental.macros

final class data extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro data.impl
}

object data {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val utils = new MacroUtils(c)
    import utils._
    import c.universe._
    annottees.head match {
      case _:ModuleDef => stateful.impl(c)(annottees:_*)
      case _ => invalidAnnotationUse("data", "objects")
    }
  }
} 
Example 29
Source File: api.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import utils.tags.MacroUtils

import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox
import scala.language.experimental.macros


final class api extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro api.impl
}

private[forge] object api {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val utils = new MacroUtils[c.type](c)
    import utils._
    import c.universe._

    annottees.head match {
      case df: DefDef =>
        val withCtx   = ctx.impl(c)(annottees:_*)
        val withState = stateful.impl(c)(withCtx)
        withState
      case _ => invalidAnnotationUse("api", "defs")
    }
  }
} 
Example 30
Source File: ref.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import utils.tags.MacroUtils

import language.experimental.macros
import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox


object ref {

  def implement(c: blackbox.Context)(cls: c.universe.ClassDef, obj: c.universe.ModuleDef): (c.universe.ClassDef, c.universe.ModuleDef) = {
    val util = new MacroUtils[c.type](c)
    import util._
    import c.universe._

    val (vargs,iargs) = cls.constructorArgs match {
      case List(v,i) if i.isImplicit => (v,i)
      case List(v) => (v, Nil)
      case _ => c.abort(c.enclosingPosition, "Ref classes can have at most one explicit and one implicit parameter list")
    }
    // TODO[5]: Should check that @ref class A mixes in Ref[?,A]

    val name = cls.name
    val tparams = cls.tparams
    val targs = cls.typeArgs
    val vnames = vargs.map(_.name)
    val inames = iargs.map(_.name)
    val cnames = vnames ++ inames
    val fullName = targsType(name, targs)

    val cls2 = cls.injectMethod(q"private def cargs: Seq[Any] = Seq(..$cnames)".asDef)
      .injectMethod(q"override protected def fresh = new $name[..$targs](..$vnames)".asDef)
      .injectField(q"override protected val __typePrefix = ${cls.nameLiteral}".asVal)
      .injectField(q"override protected val __typeArgs = cargs.collect{case t: argon.Type[_] => t}".asVal)
      .injectField(q"override protected val __typeParams = Seq(..$inames).filter{case t: argon.Type[_] => false; case _ => true}".asVal)

    val obj2 = (vargs, iargs) match {
      case (Nil,Nil) => obj.injectField(q"implicit val tp: $fullName = argon.proto(new $name[..$targs])".asVal)
      case (Nil, _)  => obj.injectMethod(q"implicit def tp[..$tparams](..$iargs): $fullName = argon.proto(new $name[..$targs]()(..$inames))".asDef)
      case (_, Nil)  => obj.injectMethod(q"def tp[..$tparams](..$vargs): $fullName = argon.proto(new $name[..$targs](..$vnames))".asDef)
      case _ =>         obj.injectMethod(q"def tp[..$tparams](..$vargs)(..$iargs): $fullName = argon.proto(new $name[..$targs](..$vnames)(..$inames))".asDef)
    }

    (cls2, obj2)
  }

  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val util = new MacroUtils[c.type](c)
    import util._
    import c.universe._

    val (cls,obj) = annottees.toList match {
      case List(cd: ClassDef, md: ModuleDef) => (cd,md)
      case List(cd: ClassDef) => (cd, q"object ${cd.nameTerm}".asObject)
      case _ => invalidAnnotationUse("ref", "classes")
    }

    val (cls2, obj2) = implement(c)(cls, obj)

    //c.info(c.enclosingPosition, showCode(cls2), force = true)
    //c.info(c.enclosingPosition, showCode(obj2), force = true)

    q"..${List(cls2,obj2)}"
  }
} 
Example 31
Source File: op.scala    From spatial   with MIT License 5 votes vote down vote up
package forge.tags

import utils.tags.MacroUtils

import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

final class op extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro op.impl
}

object op {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val util = new MacroUtils[c.type](c)
    import c.universe._
    import util._

    val (cls,obj) = annottees.toList match {
      case List(cd: ClassDef, md: ModuleDef) => (cd,md)
      case List(cd: ClassDef) => (cd, q"object ${cd.nameTerm}".asObject)
      case _ => invalidAnnotationUse("op", "classes")
    }

    val name = cls.name
    val names = cls.constructorArgs.head.map(_.name)
    val types = cls.constructorArgs.head.map(_.tp.get)
    val targs = cls.typeArgs
    val fnames = names.map{name => q"$$f($name)" }
    val updates = names.zip(fnames).map{case (name,fname) => q"$name = $fname" }

    val cls2 = cls.asCaseClass.withVarParams
      .injectMethod(q"override def mirror($$f:Tx) = new $name[..$targs](..$fnames)".asDef)
      .injectMethod(q"override def update($$f:Tx) = { ..$updates }".asDef)

    val obj2 = obj

    // TODO[5]: Not clear how this would be typed, or if its even an intuitive extractor
    

    //c.info(c.enclosingPosition, showCode(cls2), force = true)

    q"..${List(cls2,obj2)}"
  }
} 
Example 32
Source File: instrument.scala    From spatial   with MIT License 5 votes vote down vote up
package utils.tags

import scala.annotation.StaticAnnotation
import scala.reflect.macros.blackbox
import scala.language.experimental.macros

final class instrument extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro instrument.impl
}

private[utils] object instrument {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val util = new MacroUtils[c.type](c)
    import util._
    import c.universe._

    def instrument(df: DefDef): DefDef = {
      if (df.body != EmptyTree) df.modifyBody{body => q"instrument(${df.nameLiteral}){ $body }"}
      else df
    }

    val tree = annottees.head match {
      case cls: ClassDef  => cls.mapMethods(m => instrument(m)).mixIn(tq"utils.Instrumented")
      case obj: ModuleDef => obj.mapMethods(m => instrument(m)).mixIn(tq"utils.Instrumented")
      case _ => invalidAnnotationUse("@instrument", "objects", "defs")
    }
    //c.info(c.enclosingPosition, showCode(tree), force = true)
    tree
  }
} 
Example 33
Source File: StreamStructs.scala    From spatial   with MIT License 5 votes vote down vote up
package spatial.tags

import argon.tags
import argon.tags.{Arith, Bits}
import utils.tags.MacroUtils

import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox


abstract class TypeclassMacro[Ctx <: blackbox.Context](val c: Ctx) {
  import c.universe._
  def implement(cls: ClassDef, obj: ModuleDef, fields: Seq[ValDef]): (ClassDef,ModuleDef)
}


object StagedStreamStructsMacro {

  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    val typeclasses: Seq[tags.TypeclassMacro[c.type]] = Seq(
      new Bits[c.type](c),
      new Arith[c.type](c)
    )

    val utils = new MacroUtils[c.type](c)
    import c.universe._
    import utils._

    val (cls,obj) = annottees.toList match {
      case List(cd: ClassDef, md: ModuleDef) => (cd,md)
      case List(cd: ClassDef) => (cd, q"object ${cd.nameTerm}".asObject)
      case _ => invalidAnnotationUse("streamstruct", "classes")
    }

    val fields = cls.constructorArgs.head
    val methods = cls.nonConstructorMethods.filterNot{_.mods.hasFlag(Flag.CASEACCESSOR) }
    val parents: Seq[String] = cls.parents.collect{case Ident(TypeName(name)) => name }

    // TODO[5]: What to do if class has parents? Error?

    if (fields.isEmpty) abort("Classes need at least one field in order to be transformed into a @streamstruct.")
    if (methods.nonEmpty) {
      error(s"@streamstruct class had ${methods.length} disallowed methods:\n" + methods.map{method =>
        "  " + showCode(method.modifyBody(_ => EmptyTree))
      }.mkString("\n"))
      abort("@streamstruct classes with methods are not yet supported")
    }
    if (cls.tparams.nonEmpty) abort("@streamstruct classes with type parameters are not yet supported")
    if (cls.fields.exists(_.isVar)) abort("@streamstruct classes with var fields are not yet supported")

    val fieldTypes  = fields.map{field => q"${field.nameLiteral} -> argon.lang.Bits[${field.tpTree}]" }
    val fieldNames  = fields.map{field => q"${field.nameLiteral} -> ${field.name}"}
    val fieldOpts   = fields.map{field => field.withRHS(q"null") }
    val fieldOrElse = fields.map{field => q"Option(${field.name}).getOrElse{this.${field.name}(ctx,state)}" }

    var cls2 = q"class ${cls.name}[..${cls.tparams}]() extends spatial.lang.StreamStruct[${cls.fullName}]".asClass
    var obj2 = obj
    fields.foreach{field =>
      cls2 = cls2.injectMethod(
            q"""def ${field.name}(implicit ctx: forge.SrcCtx, state: argon.State): ${field.tpTree} = {
                  field[${field.tpTree}](${field.nameLiteral})(argon.lang.Bits[${field.tpTree}],ctx,state)
                }""".asDef)
    }
    cls2 = {
      cls2.injectField(q"lazy val fields = Seq(..$fieldTypes)".asVal)
          .mixIn(tq"argon.Ref[Any,${cls.fullName}]")
          .injectMethod(
            q"""def copy(..$fieldOpts)(implicit ctx: forge.SrcCtx, state: argon.State): ${cls.fullName} = {
                  ${obj2.name}.apply(..$fieldOrElse)(ctx, state)
                }""".asDef)
          .injectField(q"""override val box = implicitly[${cls.fullName} <:< (
                             spatial.lang.StreamStruct[${cls.fullName}]
                        with argon.lang.types.Bits[${cls.fullName}]
                        with argon.lang.types.Arith[${cls.fullName}]) ]""".asVal)
    }

    obj2 = {
      obj2.injectMethod(
        q"""def apply[..${cls.tparams}](..$fields)(implicit ctx: forge.SrcCtx, state: argon.State): ${cls.fullName} = {
              spatial.lang.StreamStruct[${cls.fullName}]( ..$fieldNames )(spatial.lang.StreamStruct.tp[${cls.fullName}], ctx, state)
            }
         """.asDef)
    }

    val (cls3,obj3) = typeclasses.foldRight((cls2,obj2)){case (tc, (c,o)) =>
      tc.implement(c, o, fields)
    }

    val (cls4, obj4) = forge.tags.ref.implement(c)(cls3, obj3)
    val out = q"$cls4; $obj4"

    //info(showRaw(out))
    //info(showCode(out))

    out
  }
} 
Example 34
Source File: Bits.scala    From spatial   with MIT License 5 votes vote down vote up
package argon.tags

import utils.tags.MacroUtils

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

class Bits[Ctx <: blackbox.Context](override val c: Ctx) extends TypeclassMacro[Ctx](c) {
  import c.universe._

  def implement(cls: ClassDef, obj: ModuleDef, fields: Seq[ValDef]): (ClassDef, ModuleDef) = {
    val utils = new MacroUtils[c.type](c)
    import c.universe._
    import utils._

    val fieldTypes = fields.map(_.tpTree)
    val fieldNames = fields.map(_.name)
    val bitssOpt = fieldTypes.map{tp => q"new argon.static.ExpTypeLowPriority(argon.Type[$tp]).getView[argon.lang.types.Bits]" }
    val bitss  = bitssOpt.map{bits => q"$bits.get" }
    val nbitss = bitss.map{bits => q"$bits.nbits(ctx,state)" }
    val zeros  = bitss.map{bits => q"$bits.zero(ctx,state)" }
    val ones   = bitss.map{bits => q"$bits.one(ctx,state)" }
    val maxes  = fieldNames.zip(bitss).map{case (name,bits) => q"$bits.random(max.map(_.$name(ctx,state)))(ctx,state)"}
    val clsName = cls.fullName

    val cls2 = {
      cls.mixIn(tq"Bits[$clsName]")
         .injectMethod(
           q"""private def bitsCheck(op: java.lang.String)(func: => ${cls.fullName})(implicit ctx: forge.SrcCtx, state: argon.State): ${cls.fullName} = {
                 val bitsOpt = List(..$bitssOpt)
                 if (!bitsOpt.forall(_.isDefined)) {
                    argon.error(ctx, s"$$op not defined for $${this.tp}")(state)
                    argon.error(ctx)(state)
                    argon.err[${cls.fullName}](s"$$op not defined for $${this.tp}")(argon.Type[${cls.fullName}],state)
                 }
                 else func
               }""".asDef)

         .injectMethod(
           q"""def nbits(implicit ctx: forge.SrcCtx, state: argon.State): scala.Int = {
                 val bitsOpt = List(..$bitssOpt)
                 if (!bitsOpt.forall(_.isDefined)) {
                   argon.error(ctx, s"nbits is not defined for $${this.tp}")(state)
                   argon.error(ctx)(state)
                   0
                 }
                 else List(..$nbitss).sum
               }""".asDef)
         .injectMethod(q"""def zero(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = bitsCheck("zero"){ ${obj.name}.apply(..$zeros)(ctx,state) }(ctx,state)""".asDef)
         .injectMethod(q"""def one(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = bitsCheck("one"){ ${obj.name}.apply(..$ones)(ctx,state) }(ctx,state)""".asDef)
         .injectMethod(q"""def random(max: Option[$clsName])(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = bitsCheck("random"){ ${obj.name}.apply(..$maxes)(ctx,state) }(ctx,state)""".asDef)
    }
    val obj2 = obj

    (cls2, obj2)
  }
} 
Example 35
Source File: Arith.scala    From spatial   with MIT License 5 votes vote down vote up
package argon.tags

import utils.tags.MacroUtils

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

class Arith[Ctx <: blackbox.Context](override val c: Ctx) extends TypeclassMacro[Ctx](c) {
  import c.universe._

  def implement(cls: ClassDef, obj: ModuleDef, fields: Seq[ValDef]): (ClassDef, ModuleDef) = {
    val utils = new MacroUtils[c.type](c)
    import c.universe._
    import utils._

    val fieldTypes = fields.map(_.tpTree)
    val fieldNames = fields.map(_.name)
    val arithOpt   = fieldTypes.map{tp => q"new argon.static.ExpTypeLowPriority(argon.Type[$tp]).getView[argon.lang.types.Arith]" }
    val arith      = arithOpt.map{a => q"$a.get" }
    val fieldPairs = fieldNames.zip(arith)
    val neg = fieldPairs.map{case (name,a) => q"$a.neg(this.$name(ctx,state))(ctx,state)"}
    val add = fieldPairs.map{case (name,a) => q"$a.add(this.$name(ctx,state),that.$name(ctx,state))(ctx,state)" }
    val sub = fieldPairs.map{case (name,a) => q"$a.sub(this.$name(ctx,state),that.$name(ctx,state))(ctx,state)" }
    val mul = fieldPairs.map{case (name,a) => q"$a.mul(this.$name(ctx,state),that.$name(ctx,state))(ctx,state)" }
    val div = fieldPairs.map{case (name,a) => q"$a.div(this.$name(ctx,state),that.$name(ctx,state))(ctx,state)" }
    val mod = fieldPairs.map{case (name,a) => q"$a.mod(this.$name(ctx,state),that.$name(ctx,state))(ctx,state)" }
    val abs = fieldPairs.map{case (name,a) => q"$a.abs(a.$name(ctx,state))(ctx,state)" }
    val ceil = fieldPairs.map{case (name,a) => q"$a.ceil(a.$name(ctx,state))(ctx,state)" }
    val floor = fieldPairs.map{case (name,a) => q"$a.floor(a.$name(ctx,state))(ctx,state)" }
    val clsName = cls.fullName

    val cls2 = {
      cls.mixIn(tq"Arith[$clsName]")
        .injectMethod(
          q"""private def __arith(op: java.lang.String)(func: => ${cls.fullName})(implicit ctx: forge.SrcCtx, state: argon.State): ${cls.fullName} = {
                 val arithOpt = List(..$arithOpt)
                 if (!arithOpt.forall(_.isDefined) || arithOpt.exists(_ eq null)) {
                    argon.error(ctx, op + " not defined for " + this.tp)(state)
                    argon.error(ctx)(state)
                    argon.err[${cls.fullName}](op + " not defined for " + this.tp)(argon.Type[${cls.fullName}],state)
                 }
                 else func
               }""".asDef)
        .injectMethod(q"""def unary_-()(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = __arith("negate"){ ${obj.name}.apply(..$neg)(ctx,state) }(ctx,state)""".asDef)
        .injectMethod(q"""def +(that: $clsName)(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = __arith("+"){ ${obj.name}.apply(..$add)(ctx,state) }(ctx,state)""".asDef)
        .injectMethod(q"""def -(that: $clsName)(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = __arith("-"){ ${obj.name}.apply(..$sub)(ctx,state) }(ctx,state)""".asDef)
        .injectMethod(q"""def *(that: $clsName)(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = __arith("*"){ ${obj.name}.apply(..$mul)(ctx,state) }(ctx,state)""".asDef)
        .injectMethod(q"""def /(that: $clsName)(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = __arith("/"){ ${obj.name}.apply(..$div)(ctx,state) }(ctx,state)""".asDef)
        .injectMethod(q"""def %(that: $clsName)(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = __arith("%"){ ${obj.name}.apply(..$mod)(ctx,state) }(ctx,state)""".asDef)
        .injectMethod(q"""def abs(a: $clsName)(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = __arith("abs"){ ${obj.name}.apply(..$abs)(ctx,state) }(ctx,state)""".asDef)
        .injectMethod(q"""def ceil(a: $clsName)(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = __arith("ceil"){ ${obj.name}.apply(..$ceil)(ctx,state) }(ctx,state)""".asDef)
        .injectMethod(q"""def floor(a: $clsName)(implicit ctx: forge.SrcCtx, state: argon.State): $clsName = __arith("floor"){ ${obj.name}.apply(..$floor)(ctx,state) }(ctx,state)""".asDef)
    }
    val obj2 = obj

    (cls2, obj2)
  }
} 
Example 36
Source File: ProtoMacrosCirce.scala    From scalapb-circe   with MIT License 5 votes vote down vote up
package scalapb_circe

import scalapb.{GeneratedMessage, GeneratedMessageCompanion}

import scala.reflect.macros.blackbox
import language.experimental.macros
import scala.util.Try

object ProtoMacrosCirce {

  implicit class ProtoContextCirce(private val c: StringContext) extends AnyVal {
    def struct(): com.google.protobuf.struct.Struct =
      macro ProtoMacrosCirce.protoStructInterpolation
    def value(): com.google.protobuf.struct.Value =
      macro ProtoMacrosCirce.protoValueInterpolation
  }

  implicit class FromJsonCirce[A <: GeneratedMessage](
    private val companion: GeneratedMessageCompanion[A]
  ) extends AnyVal {
    def fromJsonConstant(json: String): A =
      macro ProtoMacrosCirce.fromJsonConstantImpl0[A]

    def fromJson(json: String): A =
      macro ProtoMacrosCirce.fromJsonImpl[A]

    def fromJsonDebug(json: String): A =
      macro ProtoMacrosCirce.fromJsonDebugImpl

    def fromJsonOpt(json: String): Option[A] =
      macro ProtoMacrosCirce.fromJsonOptImpl[A]

    def fromJsonEither(json: String): Either[Throwable, A] =
      macro ProtoMacrosCirce.fromJsonEitherImpl[A]

    def fromJsonTry(json: String): Try[A] =
      macro ProtoMacrosCirce.fromJsonTryImpl[A]
  }
}

class ProtoMacrosCirce(override val c: blackbox.Context) extends scalapb_json.ProtoMacrosCommon(c) {

  import c.universe._

  override def fromJsonImpl[A: c.WeakTypeTag](json: c.Tree): c.Tree = {
    val A = weakTypeTag[A]
    q"_root_.scalapb_circe.JsonFormat.fromJsonString[$A]($json)"
  }

  override def fromJsonConstantImpl[A <: GeneratedMessage: c.WeakTypeTag: GeneratedMessageCompanion](
    string: String
  ): c.Tree = {
    val A = weakTypeTag[A]
    scalapb_circe.JsonFormat.fromJsonString[A](string)
    q"_root_.scalapb_circe.JsonFormat.fromJsonString[$A]($string)"
  }

  private[this] def parseJson(json: String): io.circe.Json = {
    io.circe.parser.parse(json).fold(throw _, identity)
  }

  override protected[this] def protoString2Struct(string: String): c.Tree = {
    val json = parseJson(string)
    val struct = StructFormat.structParser(json)
    q"$struct"
  }

  override protected[this] def protoString2Value(string: String): c.Tree = {
    val json = parseJson(string)
    val value = StructFormat.structValueParser(json)
    q"$value"
  }
} 
Example 37
Source File: StyleMacros.scala    From udash-core   with Apache License 2.0 5 votes vote down vote up
package io.udash.css.macros

import com.avsystem.commons.macros.AbstractMacroCommons

import scala.reflect.macros.blackbox

class StyleMacros(override val c: blackbox.Context) extends AbstractMacroCommons(c) {

  import c.universe._

  val Package = q"_root_.io.udash.css"
  val StyleCls = tq"$Package.CssStyle"
  val StyleNameCls = tq"$Package.CssStyleName"
  val StyleImplCls = tq"$Package.CssStyleImpl"
  val KeyframesCls = tq"$Package.CssKeyframes"
  val FontFaceCls = tq"$Package.CssFontFace"

  val Dsl = q"scalacss.internal.Dsl"
  val Compose = q"scalacss.internal.Compose"
  val FontSrcSelector = tq"scalacss.internal.FontFace.FontSrcSelector"

  private def handleScalaJs(name: Tree, other: Tree): Tree =
    if (isScalaJs) {
      q"""new $StyleNameCls($name)"""
    } else other

  private def style(name: Tree, impl: Tree*): c.Tree =
    handleScalaJs(name,
      q"""
        {
          val tmp = new $StyleImplCls($name, $Dsl.style(..$impl)($Compose.trust))
          ${c.prefix}.elementsBuffer += tmp
          tmp
        }
      """)

  def mixin(impl: Tree*): Tree = {
    val fullName = c.internal.enclosingOwner.fullName.replace('.', '-')
    handleScalaJs(q"$fullName", q"""new $StyleImplCls($fullName, $Dsl.style(..$impl)($Compose.trust))""")
  }

  def style(impl: Tree*): Tree = {
    val fullName = c.internal.enclosingOwner.fullName.replace('.', '-')
    style(q"$fullName", impl: _*)
  }

  def namedStyle(className: Tree, impl: Tree*): Tree =
    style(className, impl: _*)

  private def keyframes(name: Tree, impl: Tree*): Tree =
    handleScalaJs(name,
      q"""
        {
          val tmp = new $KeyframesCls($name,
            Seq(..$impl).map { case (p, s) =>
              (p, $Dsl.style(s: _*)($Compose.trust))
            }
          )
          ${c.prefix}.elementsBuffer += tmp
          tmp
        }
      """)

  def keyframes(impl: Tree*): Tree = {
    val fullName = c.internal.enclosingOwner.fullName.replace('.', '-')
    keyframes(q"$fullName", impl: _*)
  }

  def namedKeyframes(className: Tree, impl: Tree*): Tree =
    keyframes(className, impl: _*)

  private def fontFace(name: Tree, font: Tree): Tree =
    handleScalaJs(name,
      q"""
        {
          val tmp = new $FontFaceCls($name, $font.apply(new $FontSrcSelector(None)))
          ${c.prefix}.elementsBuffer += tmp
          tmp
        }
      """)

  def fontFace(font: Tree): Tree = {
    val fullName = c.internal.enclosingOwner.fullName.replace('.', '-')
    fontFace(q"$fullName", font)
  }

  def nameFontFace(className: Tree, font: Tree): Tree =
    fontFace(className, font)
} 
Example 38
Source File: AllValuesMacro.scala    From udash-core   with Apache License 2.0 5 votes vote down vote up
package io.udash
package macros

import com.avsystem.commons.macros.AbstractMacroCommons

import scala.reflect.macros.blackbox

// Although published within `macros` module, this macro is not intended to be used outside udash-core codebase.
private[udash] class AllValuesMacro(override val c: blackbox.Context) extends AbstractMacroCommons(c) {
  import c.universe._

  
  def ofType[V: WeakTypeTag](obj: Tree): Tree = {
    val valueType = weakTypeOf[V]
    val names = accessibleMembers(obj.tpe).iterator.filter { s =>
      (s.isMethod || s.isModule) &&
        s.typeSignature.paramLists.iterator.flatten.isEmpty &&
        s.typeSignature.typeParams.isEmpty &&
        s.typeSignatureIn(obj.tpe).finalResultType <:< valueType
    }.map(_.name.toTermName).toVector

    val objName = c.freshName(TermName("obj"))
    q"""
       val $objName = $obj
       $ListObj[$valueType](..${names.map(n => q"$objName.$n")})
     """
  }
} 
Example 39
Source File: TestMacros.scala    From udash-core   with Apache License 2.0 5 votes vote down vote up
package io.udash
package macros

import com.avsystem.commons.macros.AbstractMacroCommons

import scala.reflect.macros.{TypecheckException, blackbox}

class TestMacros(val ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {

  import c.universe._

  private def stringLiteral(tree: Tree): String = tree match {
    case StringLiteral(str) => str
    case Select(StringLiteral(str), TermName("stripMargin")) => str.stripMargin
    case _ => abort(s"expected string literal, got $tree")
  }

  def typeErrorImpl(code: Tree): Tree = {
    val codeTree = c.parse(stringLiteral(code))
    try {
      c.typecheck(codeTree)
      abort("expected typechecking error, none was raised")
    } catch {
      case TypecheckException(_, msg) => q"$msg"
    }
  }
} 
Example 40
Source File: compiletime.scala    From perf_tester   with Apache License 2.0 5 votes vote down vote up
package shapeless.test

import scala.language.experimental.macros

import scala.concurrent.duration.FiniteDuration
import scala.reflect.macros.blackbox


object compileTime {
  def apply(code: String): FiniteDuration = macro CompileTimeMacros.applyImpl
}

@macrocompat.bundle
class CompileTimeMacros(val c: blackbox.Context) {
  import c.universe._

  def applyImpl(code: Tree): Tree = {
    def wallClock(codeStr: String): Long = {
      try {
        val t1 = System.nanoTime()
        c.typecheck(c.parse(codeStr))
        val t2 = System.nanoTime()
        t2 - t1
      } catch {
        case ex: Exception => c.abort(c.enclosingPosition, ex.getMessage)
      }
    }

    val Literal(Constant(codeStr: String)) = code
    val elapsedTime = wallClock(codeStr)

    q"_root_.scala.concurrent.duration.Duration.fromNanos($elapsedTime)"
  }
} 
Example 41
Source File: MacroBase.scala    From scalajs-angulate   with MIT License 5 votes vote down vote up
// -   Project: scalajs-angulate (https://github.com/jokade/scalajs-angulate)
// Description: Provides a base class for macros with common utility functions
//
// Distributed under the MIT License (see included file LICENSE)
package biz.enef.angulate.impl

import acyclic.file
import biz.enef.angulate.named

import scala.reflect.macros.blackbox


protected[angulate] abstract class MacroBase {
  val c: blackbox.Context
  import c.universe._

  
  protected[this] def createDIArray(ct: Type) = {
    val m = getConstructor(ct)
    val deps = getDINames(m)
    val (params,args) = makeArgsList(m)
    q"""js.Array[Any](..$deps, ((..$params) => new $ct(..$args)):js.Function)"""
  }


  protected[this] def getConstructor(ct: Type) = ct.decls.filter( _.isConstructor ).collect{ case m: MethodSymbol => m}.head

  // TODO: support DI name annotations
  protected[this] def createFunctionDIArray(t: c.Tree) = {
    val (f,params) = analyzeFunction(t)
    val diNames = params.map( p => p._2.toString )
    q"js.Array[Any](..$diNames, $f:js.Function)"
  }

  protected[this] def analyzeFunction(t: c.Tree) = {
    val (m:Tree,params:List[ValDef]) = t match {
      case q"(..$params) => $body" => (t,params)
      case q"{(..$params) => $body}" => (t.children.head,params)
    }
    val args = params.map{ p =>
      val q"$mods val $name: $tpe = $rhs" = p

      (mods,name,tpe,rhs)
    }
    (m,args)
  }

} 
Example 42
Source File: LoggerMacros.scala    From log4cats   with Apache License 2.0 5 votes vote down vote up
package io.chrisdavenport.log4cats.slf4j.internal

import scala.annotation.tailrec
import scala.reflect.macros.blackbox


          loggerBySymbolName(s)
        } else {
          val typeArgs = List.fill(typeParams.length)(WildcardType)
          val typeConstructor = tq"$typeSymbol[..${typeArgs}]"
          loggerByParam(q"_root_.scala.Predef.classOf[$typeConstructor]")
        }
      }
    }

    @inline def isInnerClass(s: Symbol) =
      s.isClass && !(s.owner.isPackage)

    val instanceByName = Slf4jLoggerInternal.singletonsByName && (cls.isModule || cls.isModuleClass) || cls.isClass && isInnerClass(
      cls
    )

    if (instanceByName) {
      loggerBySymbolName(cls)
    } else {
      loggerByType(cls)
    }
  }
} 
Example 43
Source File: ScribeMacros.scala    From scribe   with MIT License 5 votes vote down vote up
package scribe

import scala.annotation.compileTimeOnly
import scala.collection.mutable.ListBuffer
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

@compileTimeOnly("Enable macros to expand")
object ScribeMacros {
  def formatter(c: blackbox.Context)(args: c.Tree*): c.Tree = {
    import c.universe._

    c.prefix.tree match {
      case Apply(_, List(Apply(_, rawParts))) => {
        val parts = rawParts map { case t @ Literal(Constant(const: String)) => (const, t.pos) }
        val list = ListBuffer.empty[c.Tree]
        val argsVector = args.toVector
        parts.zipWithIndex.foreach {
          case ((raw, _), index) => {
            if (raw.nonEmpty) {
              list += q"_root_.scribe.format.FormatBlock.RawString($raw)"
            }
            if (index < argsVector.size) {
              list += argsVector(index)
            }
          }
        }
        q"_root_.scribe.format.Formatter.fromBlocks(..$list)"
      }
      case _ => c.abort(c.enclosingPosition, "Bad usage of formatter interpolation.")
    }
  }
} 
Example 44
Source File: ShouldNotTypecheck.scala    From lagom   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.lagom.macrotestkit

import scala.language.experimental.macros
import java.util.regex.Pattern

import scala.reflect.macros.TypecheckException
import scala.reflect.macros.blackbox


object ShouldNotTypecheck {
  def apply(name: String, code: String): Unit = macro ShouldNotTypecheck.applyImplNoExp
  def apply(name: String, code: String, expected: String): Unit = macro ShouldNotTypecheck.applyImpl
}

final class ShouldNotTypecheck(val c: blackbox.Context) {
  import c.universe._

  def applyImplNoExp(name: Expr[String], code: Expr[String]): Expr[Unit] = applyImpl(name, code, c.Expr(EmptyTree))

  def applyImpl(name: Expr[String], code: Expr[String], expected: Expr[String]): Expr[Unit] = {
    val Expr(Literal(Constant(codeStr: String))) = code
    val Expr(Literal(Constant(nameStr: String))) = name
    val (expPat, expMsg) = expected.tree match {
      case EmptyTree => (Pattern.compile(".*"), "Expected some error.")
      case Literal(Constant(s: String)) =>
        (Pattern.compile(s, Pattern.CASE_INSENSITIVE), "Expected error matching: " + s)
    }

    try c.typecheck(c.parse("{ " + codeStr + " }"))
    catch {
      case e: TypecheckException =>
        val msg = e.getMessage
        if (!expPat.matcher(msg).matches) {
          c.abort(c.enclosingPosition, s"$nameStr failed in an unexpected way.\n$expMsg\nActual error: $msg")
        } else {
          println(s"$nameStr passed.")
          return reify(())
        }
    }

    c.abort(c.enclosingPosition, s"$nameStr succeeded unexpectedly.\n$expMsg")
  }
} 
Example 45
Source File: ScaladslServerMacroImpl.scala    From lagom   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.lagom.internal.scaladsl.server

import com.lightbend.lagom.internal.scaladsl.client.ScaladslClientMacroImpl
import com.lightbend.lagom.scaladsl.api.Descriptor
import com.lightbend.lagom.scaladsl.api.Service
import com.lightbend.lagom.scaladsl.server.LagomServer
import com.lightbend.lagom.scaladsl.server.LagomServiceBinder

import scala.reflect.macros.blackbox

private[lagom] class ScaladslServerMacroImpl(override val c: blackbox.Context) extends ScaladslClientMacroImpl(c) {
  import c.universe._

  val server = q"_root_.com.lightbend.lagom.scaladsl.server"

  def simpleBind[T <: Service](serviceFactory: Tree)(implicit serviceType: WeakTypeTag[T]): Expr[LagomServer] = {
    val binder = createBinder[T]
    c.Expr[LagomServer](q"""{
      $server.LagomServer.forService(
        $binder.to($serviceFactory)
      )
    }
    """)
  }

  
  def readDescriptor[T <: Service](implicit serviceType: WeakTypeTag[T]): Expr[Descriptor] = {
    val extracted = validateServiceInterface[T](serviceType)

    val serviceMethodImpls: Seq[Tree] = (extracted.serviceCalls ++ extracted.topics).map { serviceMethod =>
      val methodParams = serviceMethod.paramLists.map { paramList =>
        paramList.map(param => q"${param.name.toTermName}: ${param.typeSignature}")
      }

      q"""
        override def ${serviceMethod.name}(...$methodParams) = {
          throw new _root_.scala.NotImplementedError("Service methods and topics must not be invoked from service trait")
        }
      """
    } match {
      case Seq() => Seq(EmptyTree)
      case s     => s
    }

    c.Expr[Descriptor](q"""
      new ${serviceType.tpe} {
        ..$serviceMethodImpls
      }.descriptor
    """)
  }
} 
Example 46
Source File: DeriveMacroSupport.scala    From sangria   with Apache License 2.0 5 votes vote down vote up
package sangria.macros.derive

import scala.reflect.internal.{StdNames, SymbolTable, Definitions}
import scala.reflect.macros.blackbox

trait DeriveMacroSupport {
  val c: blackbox.Context
  val universe: c.universe.type = c.universe

  import c.universe._

  def reportErrors(errors: Seq[(Position, String)]) = {
    require(errors.nonEmpty)

    val (lastPos, lastError) = errors.last

    errors.dropRight(1).foreach{case (pos, error) => c.error(pos, error)}

    c.abort(lastPos, lastError)
  }

  protected def symbolName(annotations: List[Annotation]): Option[Tree] =
    annotations
      .map (_.tree)
      .collect {case q"new $name($arg)" if name.tpe =:= typeOf[GraphQLName] => arg}
      .headOption

  protected def symbolOutputType(annotations: List[Annotation]): Option[Tree] =
    annotations
      .map (_.tree)
      .collect {case q"new $name($arg)" if name.tpe =:= typeOf[GraphQLOutputType] => arg}
      .headOption

  protected def symbolInputType(annotations: List[Annotation]): Option[Tree] =
    annotations
      .map (_.tree)
      .collect {case q"new $name($arg)" if name.tpe =:= typeOf[GraphQLInputType] => arg}
      .headOption

  protected def symbolDescription(annotations: List[Annotation]): Option[Tree] =
    annotations
      .map (_.tree)
      .collect {case q"new $name($arg)" if name.tpe =:= typeOf[GraphQLDescription] => arg}
      .headOption

  protected def symbolDefault(annotations: List[Annotation]): Option[Tree] =
    annotations
      .map (_.tree)
      .collect {case q"new $name($arg)" if name.tpe =:= typeOf[GraphQLDefault] => arg}
      .headOption

  protected def symbolDeprecation(annotations: List[Annotation]): Option[Tree] =
    annotations
      .map (_.tree)
      .collect {case q"new $name($arg)" if name.tpe =:= typeOf[GraphQLDeprecated] => arg}
      .headOption

  protected def symbolFieldTags(annotations: List[Annotation]): Tree =
    annotations
      .map (_.tree)
      .foldLeft(q"List[sangria.execution.FieldTag]()") {
        case (acc, q"new $name(..$fieldTags)") if name.tpe =:= typeOf[GraphQLFieldTags] =>
          q"$acc ++ $fieldTags"
        case (acc, _) => acc
      }

  protected def memberExcluded(annotations: List[Annotation]): Boolean =
    annotations.find(_.tree.tpe =:= typeOf[GraphQLExclude]).fold(false)(_ => true)

  protected def memberField(annotations: List[Annotation]): Boolean =
    annotations.find(_.tree.tpe =:= typeOf[GraphQLField]).fold(false)(_ => true)

  // TODO: most probably not needed, so should be removed in future
  protected def defaultMethodArgValue(method: String, pos: Int) = {
    val defs = c.universe.asInstanceOf[Definitions with SymbolTable with StdNames]

    defs.nme.defaultGetterName(defs.newTermName(method), pos)
  }

  def checkSetting[T : WeakTypeTag](setting: Tree) = weakTypeTag[T].tpe =:= c.typecheck(setting).tpe
} 
Example 47
Source File: ParseMacro.scala    From sangria   with Apache License 2.0 5 votes vote down vote up
package sangria.macros

import sangria.parser.{SyntaxError, QueryParser}

import scala.reflect.macros.blackbox

class ParseMacro(context: blackbox.Context) extends {
  val c = context
} with MacroAstLiftable {

  import c.universe._

  def impl(args: Expr[Any]*) =
    if (args.nonEmpty)
      c.abort(c.enclosingPosition, "String interpolation is not supported for `graphql`/`gql` macro at the moment.")
    else
      c.prefix.tree match {
        // Expects a string interpolation that doesn't contain any
        // expressions, thus containing only a single tree
        case Apply(_, List(Apply(_, t :: Nil))) =>
          val q"${gql: String}" = t

          try {
            q"${QueryParser.parse(gql).get}"
          } catch {
            case error: SyntaxError => syntaxError(error)
          }
        case _ =>
          c.abort(c.enclosingPosition, "Invalid `graphql` invocation syntax.")
      }

  def implInput(args: Expr[Any]*) =
    if (args.nonEmpty)
      c.abort(c.enclosingPosition, "String interpolation is not supported for `graphqlInput`/`gqlInp` macro at the moment.")
    else
      c.prefix.tree match {
        // Expects a string interpolation that doesn't contain any
        // expressions, thus containing only a single tree
        case Apply(_, List(Apply(_, t :: Nil))) =>
          val q"${gql: String}" = t

          try {
            q"${QueryParser.parseInput(gql).get}"
          } catch {
            case error: SyntaxError => syntaxError(error)
          }
        case _ =>
          c.abort(c.enclosingPosition, "Invalid `graphql` invocation syntax.")
      }

  def implInputDoc(args: Expr[Any]*) =
    if (args.nonEmpty)
      c.abort(c.enclosingPosition, "String interpolation is not supported for `gqlInpDoc` macro at the moment.")
    else
      c.prefix.tree match {
        // Expects a string interpolation that doesn't contain any
        // expressions, thus containing only a single tree
        case Apply(_, List(Apply(_, t :: Nil))) =>
          val q"${gql: String}" = t

          try {
            q"${QueryParser.parseInputDocument(gql).get}"
          } catch {
            case error: SyntaxError => syntaxError(error)
          }
        case _ =>
          c.abort(c.enclosingPosition, "Invalid `graphql` invocation syntax.")
      }

  def syntaxError(error: SyntaxError) = {
    val errorPos = error.originalError.position
    val enclosingCol = if (errorPos.line == 1) calcStringStart else 0
    val source = c.enclosingPosition.source
    val line = source.lineToOffset(c.enclosingPosition.line + (errorPos.line - 2))
    val col = line + enclosingCol + (errorPos.column - 1)
    val pos = c.enclosingPosition.withPoint(col)

    c.abort(pos, error.formattedError(showPosition = false))
  }

  def calcStringStart: Int = {
    val source = c.enclosingPosition.source
    val content = source.lineToString(c.enclosingPosition.line - 1)
    val contentStart = content.substring(c.enclosingPosition.column - 1)
    val offset = "(\\w+\"+)".r.findFirstMatchIn(contentStart).fold(0)(_.end)

    c.enclosingPosition.column - 1 + offset
  }
} 
Example 48
Source File: MacroSupport.scala    From borer   with Mozilla Public License 2.0 5 votes vote down vote up
package io.bullet.borer.derivation.internal

import io.bullet.borer.{Decoder, Encoder}
import io.bullet.borer.deriver.DeriveWith

import scala.reflect.macros.blackbox

private[derivation] object MacroSupport {

  sealed trait Key extends Product {
    def value: Any
  }

  object Key {
    final case class String(value: java.lang.String) extends Key
    final case class Long(value: scala.Long)         extends Key
  }

  val EncoderPlaceholder = Encoder[Any]((_, _) => sys.error("Internal Error: Unresolved Encoder Placeholder"))
  val DecoderPlaceholder = Decoder[Any](_ => sys.error("Internal Error: Unresolved Decoder Placeholder"))

  def sortAndVerifyNoCollisions[T](array: Array[(Key, T)])(onCollision: (Key, T, T) => Nothing): Unit = {
    def lessThan(comp: Int, k: Key, a: T, b: T): Boolean = if (comp == 0) onCollision(k, a, b) else comp < 0
    java.util.Arrays.sort(
      array,
      Ordering.fromLessThan[(Key, T)] {
        case ((k @ Key.Long(x), a), (Key.Long(y), b))     => lessThan(java.lang.Long.compare(x, y), k, a, b)
        case ((k @ Key.String(x), a), (Key.String(y), b)) => lessThan(x compare y, k, a, b)
        case ((x, _), _)                                  => x.isInstanceOf[Key.Long] // we sort LongKeys before StringKeys
      })
  }

  def codecMacro[T: c.WeakTypeTag](c: blackbox.Context)(objectName: String, de: String, dd: String): c.Tree = {
    import c.universe._
    val tpe      = weakTypeOf[T]
    val borerPkg = c.mirror.staticPackage("_root_.io.bullet.borer")
    val prefix   = q"$borerPkg.derivation.${TermName(objectName)}"
    val encName  = TermName(c.freshName("encoder"))
    val decName  = TermName(c.freshName("decoder"))
    q"""val $encName = $prefix.${TermName(de)}[$tpe]
        val $decName = $prefix.${TermName(dd)}[$tpe]
        $borerPkg.Codec($encName, $decName)"""
  }

  def deriveAll[T: ctx.WeakTypeTag](ctx: blackbox.Context)(
      isEncoder: Boolean,
      objectName: String,
      macroName: String,
      altMacroName: String): ctx.Tree =
    DeriveWith[T](ctx) {
      new CodecDeriver[ctx.type](ctx) {
        import c.universe._

        def deriveForCaseObject(tpe: Type, module: ModuleSymbol) =
          c.abort(
            c.enclosingPosition,
            s"The `$macroName` macro can only be used on sealed traits or sealed abstract " +
              s"classes, not on case objects. Use `$altMacroName` instead!")

        def deriveForCaseClass(
            tpe: Type,
            companion: ModuleSymbol,
            params: List[CaseParam],
            annotationTrees: List[Tree],
            constructorIsPrivate: Boolean) =
          c.abort(
            c.enclosingPosition,
            s"The `$macroName` macro can only be used on sealed traits or sealed abstract " +
              s"classes, not on case classes. Use `$altMacroName` instead!")

        def deriveForSealedTrait(node: AdtTypeNode) = {
          val altMacro = q"$borerPkg.derivation.${TermName(objectName)}.${TermName(altMacroName)}"
          val tc       = if (isEncoder) encoderType else decoderType
          val subs     = subsWithoutImplicitTypeclassInstances(node, tc)

          q"""{
            ..${subs.map(x => q"implicit val ${TermName(c.freshName())} = $altMacro[${x.tpe}]")}
            $altMacro[${node.tpe}]
          }"""
        }
      }
    }
} 
Example 49
Source File: Scalac.scala    From borer   with Mozilla Public License 2.0 5 votes vote down vote up
package io.bullet.borer

import scala.reflect.macros.blackbox
import scala.util.control.NonFatal
import scala.util.matching.Regex

object Scalac {

  sealed trait TypeCheck {
    def assertErrorMsgMatches(string: String): Unit
    def assertErrorMsgMatches(regex: Regex): Unit
  }

  object TypeCheck {

    final case class Result(code: String, tpe: String) extends TypeCheck {
      def assertErrorMsgMatches(string: String): Unit = assertErrorMsgMatches(null: Regex)

      def assertErrorMsgMatches(regex: Regex): Unit =
        sys.error(s"Code Fragment compiled without error to an expression of type `$tpe`:\n\n$code")
    }

    final case class Error(msg: String) extends TypeCheck {
      def assertErrorMsgMatches(string: String): Unit = assert(msg == string, string)
      def assertErrorMsgMatches(regex: Regex): Unit   = assert(regex.findAllIn(msg).hasNext, regex)

      private def assert(value: Boolean, expected: Any): Unit =
        if (!value) sys.error(s"Expected compiler error matching [$expected] but got [$msg]")
    }
  }

  
  def typecheck(codeFragment: String): TypeCheck = macro Macro.typecheck

  private object Macro {

    def typecheck(c: blackbox.Context)(codeFragment: c.Tree): c.Tree = {
      import c.universe._

      val fragment = codeFragment match {
        case Literal(Constant(x: String)) => x
        case _                            => c.abort(c.enclosingPosition, "`codeFragment` argument must be a literal string")
      }

      try {
        val name0 = TermName(c.freshName)
        val name1 = TermName(c.freshName)
        c.typecheck(c.parse(s"object $name0 { val $name1 = { $fragment } }")) match {
          case ModuleDef(_, _, Template(_, _, List(_, valDef: ValDef, defDef: DefDef))) =>
            val tpe = defDef.symbol.asMethod.returnType.toString
            q"_root_.io.bullet.borer.Scalac.TypeCheck.Result(${showCode(valDef.rhs)}, $tpe)"
          case x => c.abort(c.enclosingPosition, s"Unexpected scalac result:\n\n${showCode(x)}")
        }
      } catch {
        case NonFatal(e) => q"_root_.io.bullet.borer.Scalac.TypeCheck.Error(${e.getMessage})"
      }
    }
  }
} 
Example 50
Source File: MacroUtil.scala    From scala-tsi   with MIT License 5 votes vote down vote up
package com.scalatsi

import scala.reflect.macros.blackbox


private[scalatsi] class MacroUtil[C <: blackbox.Context](val c: C) {

  private[this] var lookingUpList = List[c.Type]()

  // looking up implicits ourselves requires us to do our own error and divergence checking
  def lookupOptionalImplicit(T: c.Type): Option[c.Tree] = {

    val orLookingUpList = lookingUpList

    val found = try {
      if (orLookingUpList.exists(alreadyLookingUp => T <:< alreadyLookingUp)) {
        // We've entered this type before => we've entered a recursive loop and must stop
        c.universe.EmptyTree
      } else {
        lookingUpList = T :: orLookingUpList
        // look up implicit type, return EmptyTree if not found
        c.inferImplicitValue(T, silent = true)
      }
    } catch {
      case _: Exception =>
        c.universe.EmptyTree
    } finally {
      lookingUpList = orLookingUpList
    }

    Option(found)
      .filter(_ != c.universe.EmptyTree)
  }

  def lookupOptionalGenericImplicit[T: c.WeakTypeTag, F[_]](implicit tsTypeTag: c.WeakTypeTag[F[_]]): Option[c.Tree] = {
    // Get the T => F[T] function
    val typeConstructor = c.weakTypeOf[F[_]].typeConstructor
    // Construct the F[T] type we need to look up
    val lookupType = c.universe.appliedType(typeConstructor, c.weakTypeOf[T])
    lookupOptionalImplicit(lookupType)
  }
} 
Example 51
Source File: MacroUtils.scala    From tethys   with Apache License 2.0 5 votes vote down vote up
package tethys.derivation.impl

import scala.reflect.macros.blackbox


trait MacroUtils extends BaseMacroDefinitions
    with CaseClassUtils
    with LoggingUtils {
  val c: blackbox.Context
  import c.universe._

  def eval[T](expr: Expr[T]): Option[T] = {
    util.Try(c.eval(c.Expr[T](c.untypecheck(expr.tree)))).toOption
  }

  case class SelectChain(chain: Seq[String])

  implicit lazy val selectChainUnliftable: Unliftable[SelectChain] = Unliftable[SelectChain] {
    case Ident(name) => SelectChain(Seq(name.decodedName.toString))
    case select: Select =>
      def selectAllNames(s: Tree): Seq[String] = s match {
        case Select(rest, name) => selectAllNames(rest) :+ name.decodedName.toString
        case Ident(name) => Seq(name.decodedName.toString)
      }

      SelectChain(selectAllNames(select))
  }


  case class BuilderField(name: String, tpe: Type)

  implicit lazy val builderFieldUnliftable: Unliftable[BuilderField] = Unliftable[BuilderField] {
    case lambda@q"((${ValDef(_, name, _, _)}) => ${b: SelectChain})"
      if b.chain.size == 2 && name.decodedName.toString == b.chain.head =>
      val tpe = lambda match {
        case q"($_ => ${body: Tree})" => body.tpe
      }
      BuilderField(b.chain(1), tpe)
  }

  object Untyped {
    def unapply(arg: Tree): Option[Tree] = arg match {
      case Typed(t, _) => Untyped.unapply(t)
      case _ => Some(arg)
    }
  }

  implicit lazy val optionTreeUnliftable: Unliftable[Option[Tree]] = Unliftable[Option[Tree]] {
    case q"$col.Some.apply[$_](${res: Tree})" => Some(res)
    case q"$col.None" => None
  }
} 
Example 52
Source File: AutoDerivationMacro.scala    From tethys   with Apache License 2.0 5 votes vote down vote up
package tethys.derivation.impl.derivation

import tethys.commons.LowPriorityInstance
import tethys.{JsonObjectWriter, JsonReader, JsonWriter}

import scala.reflect.macros.blackbox

class AutoDerivationMacro(val c: blackbox.Context) extends WriterDerivation with ReaderDerivation {

  import c.universe._

  override protected def showError: Boolean = true

  def jsonWriter[A: WeakTypeTag]: Expr[LowPriorityInstance[JsonObjectWriter[A]]] = {
    val tpe = weakTypeOf[A]
    val clazz = classSym(tpe)
    val instance: Expr[JsonWriter[A]] = {
      if (isRecursiveDerivation) {
        fail(s"Stop recursive derivation of JsonWriter[$tpe]")
      } else if (isCaseClass(tpe)) {
        deriveWriter[A]
      } else if (clazz.isSealed) {
        deriveWriterForSealedClass[A]
      } else {
        fail(s"Can't auto derive JsonWriter[$tpe]")
      }
    }

    c.Expr[LowPriorityInstance[JsonObjectWriter[A]]] {
      c.untypecheck {
        q"new ${weakTypeOf[LowPriorityInstance[JsonObjectWriter[A]]]}($instance)"
      }
    }
  }

  def jsonReader[A: WeakTypeTag]: Expr[LowPriorityInstance[JsonReader[A]]] = {
    val tpe = weakTypeOf[A]
    if (isRecursiveDerivation) {
      fail(s"Stop recursive derivation of JsonReader[$tpe]")
    } else if (isCaseClass(tpe)) {
      val instance = deriveReader[A]
      c.Expr[LowPriorityInstance[JsonReader[A]]] {
        c.untypecheck {
          q"new ${weakTypeOf[LowPriorityInstance[JsonReader[A]]]}($instance)"
        }
      }
    } else {
      fail(s"Can't auto derive JsonReader[$tpe]")
    }
  }

  private def isRecursiveDerivation: Boolean = {
    val tpes = c.enclosingMacros.map(_.macroApplication).collect {
      case q"$_.${method: TermName}[${tt: Tree}]" => method -> tt.tpe
    }

    val counts = tpes.map {
      case (m1, t1) =>
        tpes.foldLeft(0) {
          case (count, (m2, t2)) if m1 == m2 && t1 =:= t2 => count + 1
          case (count, _) => count
        }
    }

    counts.exists(_ > 1)
  }
} 
Example 53
Source File: SemiautoDerivationMacro.scala    From tethys   with Apache License 2.0 5 votes vote down vote up
package tethys.derivation.impl.derivation

import tethys.derivation.builder._
import tethys.derivation.impl.builder.WriterBuilderCommons
import tethys.{JsonObjectWriter, JsonReader}

import scala.reflect.macros.blackbox

class SemiautoDerivationMacro(val c: blackbox.Context)
  extends WriterDerivation
  with ReaderDerivation
  with WriterBuilderCommons {

  import c.universe._

  def simpleJsonWriter[A: WeakTypeTag]: Expr[JsonObjectWriter[A]] = {
    val tpe = weakTypeOf[A]
    val clazz = classSym(tpe)
    if (isCaseClass(tpe)) {
      deriveWriter[A]
    } else if (clazz.isSealed) {
      deriveWriterForSealedClass[A]
    } else {
      abort(s"Can't auto derive JsonWriter[$tpe]")
    }
  }

  def jsonWriterWithBuilder[A: WeakTypeTag](builder: Expr[WriterBuilder[A]]): Expr[JsonObjectWriter[A]] = {
    val description = convertWriterBuilder[A](builder)
    describedJsonWriter[A](c.Expr[WriterDescription[A]](c.typecheck(description.tree)))
  }

  def jsonWriterWithConfig[A: WeakTypeTag](config: Expr[WriterDerivationConfig]): Expr[JsonObjectWriter[A]] = {
    val description = MacroWriteDescription(
      tpe = weakTypeOf[A],
      config = c.Expr[WriterDerivationConfig](c.untypecheck(config.tree)),
      operations = Seq.empty
    )
    deriveWriter[A](description)
  }

  def describedJsonWriter[A: WeakTypeTag](description: Expr[WriterDescription[A]]): Expr[JsonObjectWriter[A]] = {
    val tpe = weakTypeOf[A]
    if (!isCaseClass(tpe)) {
      abort(s"Can't auto derive JsonWriter[$tpe]")
    } else {
      deriveWriter[A](unliftWriterMacroDescription(description))
    }
  }

  def simpleJsonReader[A: WeakTypeTag]: Expr[JsonReader[A]] = {
    val tpe = weakTypeOf[A]
    if (isCaseClass(tpe)) {
      deriveReader[A]
    } else {
      fail(s"Can't auto derive JsonReader[$tpe]")
    }
  }

  def jsonReaderWithBuilder[A: WeakTypeTag](builder: Expr[ReaderBuilder[A]]): Expr[JsonReader[A]] = {
    val description = convertReaderBuilder[A](builder)
    describedJsonReader[A](c.Expr[ReaderDescription[A]](c.typecheck(description.tree)))
  }

  def describedJsonReader[A: WeakTypeTag](description: Expr[ReaderDescription[A]]): Expr[JsonReader[A]] = {
    val tpe = weakTypeOf[A]
    if (isCaseClass(tpe)) {
      deriveReader[A](unliftReaderMacroDescription(description))
    } else {
      fail(s"Can't auto derive JsonReader[$tpe]")
    }
  }

  def jsonReaderWithConfig[A: WeakTypeTag](config: Expr[ReaderDerivationConfig]): Expr[JsonReader[A]] = {
    val tpe = weakTypeOf[A]
    if (isCaseClass(tpe)) {
      deriveReader[A](ReaderMacroDescription(
        config = c.Expr[ReaderDerivationConfig](c.untypecheck(config.tree)),
        operations = Seq()
      ))
    } else {
      fail(s"Can't auto derive JsonReader[$tpe]")
    }
  }

  private def unliftWriterMacroDescription[A: WeakTypeTag](description: Expr[WriterDescription[A]]): MacroWriteDescription = {
    description.tree match {
      case Untyped(q"${description: MacroWriteDescription}") => description
    }
  }

  private def unliftReaderMacroDescription[A: WeakTypeTag](description: Expr[ReaderDescription[A]]): ReaderMacroDescription = {
    description.tree match {
      case Untyped(q"${description: ReaderMacroDescription}") => description
    }
  }
} 
Example 54
Source File: DerivationUtils.scala    From tethys   with Apache License 2.0 5 votes vote down vote up
package tethys.derivation.impl.derivation

import tethys.derivation.impl.LoggingUtils

import scala.reflect.macros.blackbox

trait DerivationUtils extends LoggingUtils {
  val c: blackbox.Context
  import c.universe._

  protected def showError: Boolean = false

  protected def fail(msg: String): Nothing = abort(msg)

  protected def collectDistinctSubtypes(tpe: Type): List[Type] = {
    val baseClass = classSym(tpe)
    val baseArgs = tpe.dealias.typeArgs

    val tpes = collectSubclasses(baseClass).map { sym =>
      def substituteArgs: List[Type] = {
        val subst = c.internal.thisType(sym).baseType(baseClass).typeArgs
        sym.typeParams.map { param =>
          val paramTpe = param.asType.toType
          val index = subst.indexWhere(_ =:= paramTpe)
          if(index != -1) baseArgs(index)
          else fail(s"$sym contains additional type parameter that can't be derived in compile time")
        }
      }

      appliedType(sym, substituteArgs)
    }

    tpes.foldLeft(List.empty[Type]) {
      case (acc, t) =>
        if(!acc.exists(_ =:= t)) t :: acc
        else acc
    }
  }

  protected def collectSubclasses(classSym: ClassSymbol): List[ClassSymbol] = {
    classSym.knownDirectSubclasses.toList.flatMap { child0 =>
      val child = child0.asClass
      child.typeSignature // Workaround for <https://issues.scala-lang.org/browse/SI-7755>
      if (child.isSealed && (child.isAbstract || child.isTrait)) collectSubclasses(child)
      else List(child)
    }
  }

  protected def classSym(tpe: Type): ClassSymbol = {
    val sym = tpe.typeSymbol
    if (!sym.isClass)
      fail(s"$sym is not a class or trait")

    val classSym = sym.asClass
    classSym.typeSignature // Workaround for <https://issues.scala-lang.org/browse/SI-7755>

    classSym
  }
} 
Example 55
Source File: ReaderBuilderUtils.scala    From tethys   with Apache License 2.0 5 votes vote down vote up
package tethys.derivation.impl.builder

import tethys.derivation.builder.ReaderDerivationConfig
import tethys.derivation.impl.MacroUtils

import scala.reflect.macros.blackbox

trait ReaderBuilderUtils extends MacroUtils {
  val c: blackbox.Context
  import c.universe._

  case class ReaderMacroDescription(config: c.Expr[ReaderDerivationConfig], operations: Seq[ReaderMacroOperation])

  sealed trait Field {
    def name: String
    def tpe: Type
  }
  object Field {
    final case class ClassField(name: String, tpe: Type) extends Field
    final case class RawField(name: String, tpe: Type) extends Field
  }

  sealed trait ReaderMacroOperation {
    def field: String
  }
  object ReaderMacroOperation {
    final case class ExtractFieldAs(field: String, tpe: Type, as: Type, fun: Tree) extends ReaderMacroOperation
    final case class ExtractFieldValue(field: String, from: Seq[Field], fun: Tree) extends ReaderMacroOperation
    final case class ExtractFieldReader(field: String, from: Seq[Field], fun: Tree) extends ReaderMacroOperation
  }

  implicit lazy val readerMacroDescriptionLiftable: Liftable[ReaderMacroDescription] = Liftable[ReaderMacroDescription] {
    case ReaderMacroDescription(config, operations) =>
      q"$buildersPack.ReaderDescription(${config.tree} ,_root_.scala.Seq(..$operations))"
  }

  implicit lazy val readerMacroDescriptionUnliftable: Unliftable[ReaderMacroDescription] = Unliftable[ReaderMacroDescription] {
    case q"$_.ReaderDescription.apply[$_](${config: Tree} ,$_.Seq.apply[$_](..${operations: Seq[ReaderMacroOperation]}))" =>
      ReaderMacroDescription(c.Expr[ReaderDerivationConfig](c.untypecheck(config)), operations)
  }

  implicit lazy val fieldLiftable: Liftable[Field] = Liftable[Field] {
    case Field.ClassField(name, tpe) =>
      q"$buildersPack.ReaderDescription.Field.ClassField[$tpe]($name)"

    case Field.RawField(name, tpe) =>
      q"$buildersPack.ReaderDescription.Field.RawField[$tpe]($name)"
  }

  implicit lazy val fieldUnliftable: Unliftable[Field] = Unliftable[Field] {
    case q"$_.ReaderDescription.Field.ClassField.apply[${tpe: Tree}](${name: String})" =>
      Field.ClassField(name, tpe.tpe)

    case q"$_.ReaderDescription.Field.RawField.apply[${tpe: Tree}](${name: String})" =>
      Field.RawField(name, tpe.tpe)

    case q"${f: BuilderField}" =>
      Field.ClassField(f.name, f.tpe)

    case q"$_.ReaderFieldStringOps(${name: String}).as[${tpe: Tree}]" =>
      Field.RawField(name, tpe.tpe)

    case q"$_.ReaderFieldSymbolOps(scala.Symbol.apply(${name: String})).as[${tpe: Tree}]" =>
      Field.RawField(name, tpe.tpe)
  }

  implicit lazy val readerMacroOperationLiftable: Liftable[ReaderMacroOperation] = Liftable[ReaderMacroOperation] {
    case ReaderMacroOperation.ExtractFieldAs(field, tpe, as, fun) =>
      q"$buildersPack.ReaderDescription.BuilderOperation.ExtractFieldAs[$as, $tpe]($field, $fun)"

    case ReaderMacroOperation.ExtractFieldValue(field, from, fun) =>
      q"$buildersPack.ReaderDescription.BuilderOperation.ExtractFieldValue($field, _root_.scala.Seq(..$from), $fun)"

    case ReaderMacroOperation.ExtractFieldReader(field, from, fun) =>
      q"$buildersPack.ReaderDescription.BuilderOperation.ExtractFieldReader($field, _root_.scala.Seq(..$from), $fun)"
  }


  implicit lazy val readerMacroOperationUnliftable: Unliftable[ReaderMacroOperation] = Unliftable[ReaderMacroOperation] {
    case q"$_.ReaderDescription.BuilderOperation.ExtractFieldAs.apply[${as: Tree}, ${tpe: Tree}](${field: String}, ${fun: Tree})" =>
      ReaderMacroOperation.ExtractFieldAs(field, tpe.tpe, as.tpe, fun)

    case q"$_.ReaderDescription.BuilderOperation.ExtractFieldValue.apply(${field: String}, $_.Seq.apply[$_](..${from: Seq[Field]}), ${fun: Tree})" =>
      ReaderMacroOperation.ExtractFieldValue(field, from, fun)

    case q"$_.ReaderDescription.BuilderOperation.ExtractFieldReader.apply(${field: String}, $_.Seq.apply[$_](..${from: Seq[Field]}), ${fun: Tree})" =>
      ReaderMacroOperation.ExtractFieldReader(field, from, fun)
  }
} 
Example 56
Source File: ReaderDescriptionCommons.scala    From tethys   with Apache License 2.0 5 votes vote down vote up
package tethys.derivation.impl.builder

import tethys.derivation.builder.{ReaderBuilder, ReaderDerivationConfig, ReaderDescription}

import scala.reflect.macros.blackbox

trait ReaderDescriptionCommons extends ReaderBuilderUtils {
  val c: blackbox.Context
  import c.universe._

  def convertReaderBuilder[A: WeakTypeTag](builder: Expr[ReaderBuilder[A]]): Expr[ReaderDescription[A]] = {
    val description = extractDescription(builder.tree)

    c.Expr[ReaderDescription[A]] {
      c.untypecheck {
        q"$description"
      }
    }
  }

  protected lazy val emptyReaderConfig: Expr[ReaderDerivationConfig] = c.Expr[ReaderDerivationConfig](c.untypecheck(
    q"tethys.derivation.builder.ReaderDerivationConfig.empty"
  ))

  private def extractDescription(tree: Tree): ReaderMacroDescription = tree match {
    // ===== ROOT =====
    case q"ReaderBuilder.apply[$_]" =>
      ReaderMacroDescription(emptyReaderConfig, Seq())

    case q"$_.ReaderBuilder.apply[$_]" =>
      ReaderMacroDescription(emptyReaderConfig, Seq())

    // ===== FieldAs =====
    case q"${rest: Tree}.extract[${tpe: Tree}](${f: BuilderField}).as[${as: Tree}].apply(${fun: Tree})" =>
      val description = extractDescription(rest)
      description.copy(operations = description.operations :+ ReaderMacroOperation.ExtractFieldAs(
        f.name, tpe.tpe, as.tpe, fun
      ))

    // ===== FieldValue =====
    case q"${rest: Tree}.extract[$tpe](${f: BuilderField}).from[..$_](..${fs: Seq[Field]}).apply(${fun: Tree})" =>
      val description = extractDescription(rest)
      description.copy(operations = description.operations :+ ReaderMacroOperation.ExtractFieldValue(
        f.name, fs, fun
      ))

    case q"${rest: Tree}.extract[$tpe](${f: BuilderField}).from[..$_](..${fs: Seq[Field]}).and[..$_](..${ands: Seq[Field]}).apply(${fun: Tree})" =>
      val description = extractDescription(rest)
      description.copy(operations = description.operations :+ ReaderMacroOperation.ExtractFieldValue(
        f.name, fs ++ ands, fun
      ))

    // ===== FieldReader =====
    case q"${rest: Tree}.extractReader[$tpe](${f: BuilderField}).from[..$_](..${fs: Seq[Field]}).apply(${fun: Tree})" =>
      val description = extractDescription(rest)
      description.copy(operations = description.operations :+ ReaderMacroOperation.ExtractFieldReader(
        f.name, fs, fun
      ))

    case q"${rest: Tree}.extractReader[$tpe](${f: BuilderField}).from[..$_](..${fs: Seq[Field]}).and[..$_](..${ands: Seq[Field]}).apply(${fun: Tree})" =>
      val description = extractDescription(rest)
      description.copy(operations = description.operations :+ ReaderMacroOperation.ExtractFieldReader(
        f.name, fs ++ ands, fun
      ))

    // ===== FieldStyle =====
    case q"${rest: Tree}.fieldStyle(${style: Tree})" =>
      val description = extractDescription(rest)
      description.copy(config = c.Expr[ReaderDerivationConfig](
        q"${description.config.tree}.withFieldStyle($style)"
      ))

    // ===== isStrict =====
    case q"${rest: Tree}.strict" =>
      val description = extractDescription(rest)
      description.copy(config = c.Expr[ReaderDerivationConfig](
        q"${description.config.tree}.strict"
      ))

    // ===== NOPE =====
    case _ =>
      abort(s"Unknown builder tree: $tree")
  }
} 
Example 57
Source File: MacroLogging.scala    From tethys   with Apache License 2.0 5 votes vote down vote up
package tethys.derivation.impl

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

object MacroLogging {
  def logCode[A](tree: A): A = macro MacroLoggingImpl.logCode
  def logTree[A](tree: A): A = macro MacroLoggingImpl.logTree

  private class MacroLoggingImpl(val c: blackbox.Context) {
    import c.universe._

    def logCode(tree: Tree): Tree = {
      c.info(c.enclosingPosition, show(tree), force = false)
      tree
    }

    def logTree(tree: Tree): Tree = {
      c.info(c.enclosingPosition, showRaw(tree), force = false)
      tree
    }
  }
} 
Example 58
Source File: CaseClassUtils.scala    From tethys   with Apache License 2.0 5 votes vote down vote up
package tethys.derivation.impl

import scala.reflect.macros.blackbox


trait CaseClassUtils extends LoggingUtils {
  val c: blackbox.Context
  import c.universe._

  case class CaseClassDefinition(tpe: Type, fields: List[CaseClassField], typeParamsToRealTypes: Map[String, Type])
  case class CaseClassField(name: String, tpe: Type)

  def caseClassDefinition[A: WeakTypeTag]: CaseClassDefinition = caseClassDefinition(weakTypeOf[A])

  def caseClassDefinition(tpe: Type): CaseClassDefinition = {
    val ctor = getConstructor(tpe)
    val typeParamsToRealTypes = extractTypeParamsToRealTypes(tpe)
    CaseClassDefinition(
      tpe = tpe,
      fields = ctor.paramLists.head.map(constructorParameterToCaseClassField(tpe)),
      typeParamsToRealTypes = typeParamsToRealTypes
    )
  }

  def isCaseClass[A: WeakTypeTag]: Boolean = isCaseClass(weakTypeOf[A])

  def isCaseClass(tpe: Type): Boolean = {
    tpe.typeSymbol.isClass &&
      (tpe.typeSymbol.asClass.isCaseClass ||
        tpe.member(TermName("copy")).isMethod &&
        tpe <:< weakTypeOf[Product])
  }

  private def getConstructor(tpe: Type): MethodSymbol = {
    tpe.decls.collectFirst {
      case s: MethodSymbol if s.isPrimaryConstructor => s
    }.getOrElse {
      abort(s"Type '${tpe.typeSymbol.name.decodedName.toString} doesn't have main constructor")
    }
  }

  private def constructorParameterToCaseClassField(tpe: Type)(param: Symbol): CaseClassField = {
    val possibleRealType = tpe.decls.collectFirst {
      case s if s.name == param.name => s.typeSignatureIn(tpe).finalResultType
    }
    CaseClassField(
      name = param.name.decodedName.toString,
      tpe = possibleRealType.getOrElse(param.typeSignatureIn(tpe))
    )
  }

  private def extractTypeParamsToRealTypes(tpe: Type): Map[String, Type] = {
    val ctorTypeArgs = getConstructor(tpe).typeSignature.finalResultType.typeArgs
    ctorTypeArgs.zip(tpe.typeArgs).map {
      case (gen, real) => gen.typeSymbol.name.decodedName.toString -> real
    }.toMap
  }
} 
Example 59
Source File: CollectionBuilder.scala    From tethys   with Apache License 2.0 5 votes vote down vote up
package tethys.compat

import scala.collection.{IterableFactory, IterableFactoryDefaults, MapFactory, mutable}
import scala.language.experimental.macros
import scala.language.higherKinds
import scala.reflect.macros.blackbox

trait CollectionBuilder[A, C] {
  def newBuilder: mutable.Builder[A, C]
}

object CollectionBuilder {

  final class IterableFactoryCollectionBuilder[A, C[_]](factory: IterableFactory[C]) extends CollectionBuilder[A, C[A]] {
    override def newBuilder: mutable.Builder[A, C[A]] = factory.newBuilder[A]
  }

  final class MapFactoryCollectionBuilder[K, V, M[_, _]](factory: MapFactory[M]) extends CollectionBuilder[(K, V), M[K, V]] {
    override def newBuilder: mutable.Builder[(K, V), M[K, V]] = factory.newBuilder[K, V]
  }

  implicit def iterableFactoryCollectionBuilder[A, C[X] <: IterableFactoryDefaults[X, C]]: IterableFactoryCollectionBuilder[A, C] = macro CollectionBuilderMacroImpl.fromIterableFactory[A, C]
  implicit def mapFactoryCollectionBuilder[K, V, M[X, Y] <: Map[X, Y]]: MapFactoryCollectionBuilder[K, V, M] = macro CollectionBuilderMacroImpl.fromMapFactory[K, V, M]

  private class CollectionBuilderMacroImpl(val c: blackbox.Context) {
    import c.universe._

    def fromIterableFactory[A, C[X] <: IterableFactoryDefaults[X, C]](implicit A: WeakTypeTag[A], C: WeakTypeTag[C[A]]): Tree = {
      val ref = C.tpe.typeSymbol.companion
      q"new tethys.compat.CollectionBuilder.IterableFactoryCollectionBuilder[${A.tpe}, ${C.tpe}]($ref)"
    }

    def fromMapFactory[K, V, M[X, Y] <: Map[X, Y]](implicit
                                                   K: WeakTypeTag[K],
                                                   V: WeakTypeTag[V],
                                                   M: WeakTypeTag[M[K, V]]): Tree = {
      val ref = M.tpe.typeSymbol.companion
      q"new tethys.compat.CollectionBuilder.MapFactoryCollectionBuilder[${K.tpe}, ${V.tpe}, ${M.tpe}]($ref)"
    }
  }

} 
Example 60
Source File: GenKeyCodecMacros.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package macros.serialization

import scala.reflect.macros.blackbox

class GenKeyCodecMacros(ctx: blackbox.Context) extends CodecMacroCommons(ctx) {

  import c.universe._

  final def GenKeyCodecObj: Tree = q"$SerializationPkg.GenKeyCodec"
  final def GenKeyCodecCls: Tree = tq"$SerializationPkg.GenKeyCodec"

  def forSealedEnum[T: WeakTypeTag]: Tree = {
    val tpe = weakTypeOf[T]
    knownSubtypes(tpe).map { subtypes =>
      def singleValue(st: Type): Tree = singleValueFor(st).getOrElse(abort(s"$st is not an object"))
      val nameBySym = subtypes.groupBy(st => targetName(st.typeSymbol)).map {
        case (name, List(subtype)) => (subtype.typeSymbol, name)
        case (name, kst) =>
          abort(s"Objects ${kst.map(_.typeSymbol.name).mkString(", ")} have the same @name: $name")
      }

      q"""
        new $GenKeyCodecCls[$tpe] {
          def tpeString = ${tpe.toString}
          def read(key: $StringCls): $tpe = key match {
            case ..${subtypes.map(st => cq"${nameBySym(st.typeSymbol)} => ${singleValue(st)}")}
            case _ => throw new $SerializationPkg.GenCodec.ReadFailure(s"Cannot read $$tpeString, unknown object: $$key")
          }
          def write(value: $tpe): String = value match {
            case ..${subtypes.map(st => cq"_: $st => ${nameBySym(st.typeSymbol)}")}
          }
        }
      """
    }.getOrElse(abort(s"$tpe is not a sealed trait or class"))
  }

  def forTransparentWrapper[T: WeakTypeTag]: Tree = {
    val tpe = weakTypeOf[T].dealias
    val codecTpe = getType(tq"$GenKeyCodecCls[$tpe]")
    val (applyUnapply, param) = applyUnapplyFor(tpe) match {
      case Some(au@ApplyUnapply(_, _, _, _, List(soleParam))) => (au, soleParam)
      case _ => abort(s"$tpe is not a case class (or case class-like type) with exactly one field")
    }

    val wrappedCodecTpe = getType(tq"$GenKeyCodecCls[${param.typeSignature}]")
    val clue = s"Cannot materialize $codecTpe because of problem with parameter ${param.name}:\n"
    val wrappedCodec = inferCachedImplicit(wrappedCodecTpe, ErrorCtx(clue, param.pos)).reference(Nil)

    val unwrapped =
      if (applyUnapply.standardCaseClass)
        q"value.${param.name.toTermName}"
      else
        q"""
          ${applyUnapply.typedCompanion}.unapply[..${tpe.typeArgs}](value)
            .getOrElse(throw new $SerializationPkg.GenCodec.WriteFailure(
              s"Cannot write $$tpeString, unapply failed for $$value"))
         """

    q"""
      new $codecTpe {
        ..$cachedImplicitDeclarations
        def tpeString: $StringCls = ${tpe.toString}
        def read(key: $StringCls): $tpe = ${applyUnapply.mkApply(List(q"$wrappedCodec.read(key)"))}
        def write(value: $tpe): $StringCls = $wrappedCodec.write($unwrapped)
      }
     """
  }
} 
Example 61
Source File: CodecMacroCommons.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package macros.serialization

import com.avsystem.commons.macros.AbstractMacroCommons

import scala.reflect.macros.blackbox

abstract class CodecMacroCommons(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {

  import c.universe._

  final def SerializationPkg: Tree = q"$CommonsPkg.serialization"
  final lazy val NameAnnotType = staticType(tq"$SerializationPkg.name")
  final lazy val NameAnnotNameSym = NameAnnotType.member(TermName("name"))
  final lazy val WhenAbsentAnnotType = staticType(tq"$SerializationPkg.whenAbsent[_]")
  final def JavaInteropObj: Tree = q"$CommonsPkg.jiop.JavaInterop"
  final def JListObj: Tree = q"$JavaInteropObj.JList"
  final def JListCls: Tree = tq"$JavaInteropObj.JList"
  final def ListBufferCls: Tree = tq"$CollectionPkg.mutable.ListBuffer"
  final def BMapCls: Tree = tq"$CollectionPkg.Map"
  final def NOptObj: Tree = q"$MiscPkg.NOpt"
  final def NOptCls: Tree = tq"$MiscPkg.NOpt"
  final def OptObj: Tree = q"$CommonsPkg.Opt"
  final def OptCls: Tree = tq"$CommonsPkg.Opt"
  final lazy val TransparentAnnotType = staticType(tq"$SerializationPkg.transparent")
  final lazy val TransientDefaultAnnotType = staticType(tq"$SerializationPkg.transientDefault")
  final lazy val FlattenAnnotType = staticType(tq"$SerializationPkg.flatten")
  final lazy val OutOfOrderAnnotType = staticType(tq"$SerializationPkg.outOfOrder")
  final lazy val GeneratedAnnotType = staticType(tq"$SerializationPkg.generated")
  final lazy val DefaultCaseAnnotType = staticType(tq"$SerializationPkg.defaultCase")
  final def GenCodecObj: Tree = q"$SerializationPkg.GenCodec"
  final def GenCodecCls: Tree = tq"$SerializationPkg.GenCodec"
  final val DefaultCaseField = "_case"

  def tupleGet(i: Int) = TermName(s"_${i + 1}")

  def targetName(sym: Symbol): String =
    findAnnotation(sym, NameAnnotType).fold(sym.name.decodedName.toString)(_.findArg[String](NameAnnotNameSym))

  def caseAccessorFor(sym: Symbol): Symbol =
    if (sym.isParameter && sym.owner.isConstructor) {
      val ownerClass = sym.owner.owner.asClass
      if (ownerClass.isCaseClass) {
        alternatives(ownerClass.toType.member(sym.name)).find(_.asTerm.isCaseAccessor).getOrElse(NoSymbol)
      } else NoSymbol
    } else NoSymbol

  def withAccessed(sym: Symbol): List[Symbol] =
    if (sym.isTerm) {
      val tsym = sym.asTerm
      if (tsym.isGetter) List(sym, tsym.accessed)
      else List(sym)
    } else List(sym)

  def hasAnnotation(sym: Symbol, annotTpe: Type): Boolean =
    findAnnotation(sym, annotTpe).nonEmpty

  def isTransparent(sym: Symbol): Boolean =
    hasAnnotation(sym, TransparentAnnotType)

  def isGenerated(sym: Symbol): Boolean =
    hasAnnotation(sym, GeneratedAnnotType)
} 
Example 62
Source File: UniversalMacros.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package macros

import scala.reflect.macros.blackbox

class UniversalMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {

  import c.universe._

  def sourceCode: Tree = {
    if (!ctx.compilerSettings.contains("-Yrangepos")) {
      abort("sourceCode only works with range positions enabled (-Yrangepos)")
    }
    val Apply(_, List(prefix)) = c.prefix.tree
    val pos = prefix.pos
    val code = new String(pos.source.content, pos.start, pos.end - pos.start)

    def lineIndent(line: String): Int =
      line.indexWhere(c => !c.isWhitespace) match {
        case -1 => 0
        case i => i
      }

    val indentToStrip = lineIndent(pos.source.lineToString(pos.source.offsetToLine(pos.start)))
    val stripped = code.split('\n').map(l => l.drop(indentToStrip min lineIndent(l))).mkString("\n")
    q"$stripped"
  }

  def withSourceCode: Tree = {
    val Apply(_, List(prefix)) = c.prefix.tree
    q"($prefix, $sourceCode)"
  }

  def showAst[A]: Tree = {
    val Apply(_, List(prefix)) = c.prefix.tree
    c.error(prefix.pos, showCode(prefix))
    prefix
  }

  def showRawAst[A]: Tree = {
    val Apply(_, List(prefix)) = c.prefix.tree
    c.error(prefix.pos, showRaw(prefix))
    prefix
  }

  def showSymbol[A]: Tree = {
    val Apply(_, List(prefix)) = c.prefix.tree
    c.error(prefix.pos, show(prefix.symbol))
    prefix
  }

  def showSymbolFullName[A]: Tree = {
    val Apply(_, List(prefix)) = c.prefix.tree
    c.error(prefix.pos, prefix.symbol.fullName)
    prefix
  }

  def showType[A]: Tree = {
    val Apply(_, List(prefix)) = c.prefix.tree
    c.error(prefix.pos, showCode(tq"${prefix.tpe.widen}"))
    prefix
  }

  def showRawType[A]: Tree = {
    val Apply(_, List(prefix)) = c.prefix.tree
    c.error(prefix.pos, showRaw(prefix.tpe.widen))
    prefix
  }

  def showTypeSymbol[A]: Tree = {
    val Apply(_, List(prefix)) = c.prefix.tree
    c.error(prefix.pos, show(prefix.tpe.typeSymbol))
    prefix
  }

  def showTypeSymbolFullName[A]: Tree = {
    val Apply(_, List(prefix)) = c.prefix.tree
    c.error(prefix.pos, prefix.tpe.typeSymbol.fullName)
    prefix
  }
} 
Example 63
Source File: DelegationMacros.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package macros.misc

import com.avsystem.commons.macros.AbstractMacroCommons

import scala.reflect.macros.blackbox

class DelegationMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {

  import c.universe._

  final def DelegationCls: Tree = tq"$MiscPkg.Delegation"

  def delegate[A: WeakTypeTag, B: WeakTypeTag](source: Tree): Tree = instrument {
    val targetTpe = weakTypeOf[B]

    val targetSymbol = targetTpe.dealias.typeSymbol
    if (!targetSymbol.isClass && !targetSymbol.asClass.isAbstract) {
      abort(s"$targetTpe is not a trait or abstract class")
    }

    val wrappedName = c.freshName(TermName("w"))

    val methodDelegations = targetTpe.members.iterator
      .filter(m => m.isAbstract)
      .flatMap { m =>
        if (m.isPublic && m.isMethod && !m.asTerm.isSetter) {
          val ms = m.asMethod
          val name = m.name.toTermName
          val mtpe = m.typeSignatureIn(targetTpe)
          val typeNames = mtpe.typeParams.map(_.name.toTypeName)
          val typeDefs = mtpe.typeParams.map(typeSymbolToTypeDef(_))
          val paramNames =
            mtpe.paramLists.map(_.map(p => if (isRepeated(p)) q"${p.name.toTermName}: _*" else q"${p.name.toTermName}"))
          val paramLists = mtpe.paramLists.map(_.map(paramSymbolToValDef))
          val resultTpeTree = treeForType(mtpe.finalResultType)

          val result = if (ms.isGetter)
            q"val $name: $resultTpeTree = $wrappedName.$name"
          else
            q"def $name[..$typeDefs](...$paramLists): $resultTpeTree = $wrappedName.$name[..$typeNames](...$paramNames)"

          Some(result)
        } else {
          error(s"Can't delegate ${m.name} - only public defs and vals can be delegated")
          None
        }
      }.toList

    q"""
      val $wrappedName = $source
      new $targetTpe {
        ..$methodDelegations
      }
     """
  }

  def materializeDelegation[A: WeakTypeTag, B: WeakTypeTag]: Tree = instrument {
    val targetTpe = weakTypeOf[B]
    val sourceTpe = weakTypeOf[A]

    q"""
      new $DelegationCls[$sourceTpe, $targetTpe] {
        def delegate(source: $sourceTpe): $targetTpe = ${delegate[A, B](q"source")}
      }
     """
  }

} 
Example 64
Source File: SealedMacros.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package macros.misc

import com.avsystem.commons.macros.AbstractMacroCommons

import scala.reflect.macros.blackbox

class SealedMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {

  import c.universe._

  final lazy val OrderedEnumType: Type = staticType(tq"$MiscPkg.OrderedEnum")

  def caseObjectsFor[T: WeakTypeTag]: Tree = instrument {
    val tpe = weakTypeOf[T]
    knownSubtypes(tpe).map { subtypes =>
      val objects = subtypes.map(subTpe => singleValueFor(subTpe)
        .getOrElse(abort(s"All possible values of a SealedEnum must be objects but $subTpe is not")))
      val result = q"$ListObj(..$objects)"
      if (tpe <:< OrderedEnumType) q"$result.sorted" else result
    }.getOrElse(abort(s"$tpe is not a sealed trait or class"))
  }

  def instancesFor[TC: WeakTypeTag, T: WeakTypeTag]: Tree = instrument {
    val tpe = weakTypeOf[T]
    def instanceTpe(forTpe: Type): Type = weakTypeOf[TC] match {
      case TypeRef(pre, sym, Nil) => internal.typeRef(pre, sym, List(forTpe))
      case _ => abort(s"expected type constructor")
    }
    val subtypes = knownSubtypes(tpe).getOrElse(abort(s"$tpe is not a sealed hierarchy root"))
    q"${subtypes.map(st => q"""$ImplicitsObj.infer[${instanceTpe(st)}]("")""")}"
  }
} 
Example 65
Source File: LazyLoggingMacros.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package macros.misc

import com.avsystem.commons.macros.MacroCommons

import scala.reflect.macros.blackbox


class LazyLoggingMacros(val c: blackbox.Context) extends MacroCommons {

  import c.universe._

  val DelegationCls = tq"$MiscPkg.Delegation"

  def warningImpl(msg: Tree) =
    q"""
      if(${c.prefix}.rawLog.isWarningEnabled) {
        ${c.prefix}.rawLog.warning($msg)
      }
     """

  def infoImpl(msg: Tree) =
    q"""
      if(${c.prefix}.rawLog.isInfoEnabled) {
        ${c.prefix}.rawLog.info($msg)
      }
     """

  def debugImpl(msg: Tree) =
    q"""
      if(${c.prefix}.rawLog.isDebugEnabled) {
        ${c.prefix}.rawLog.debug($msg)
      }
     """
} 
Example 66
Source File: TestUtils.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import com.avsystem.commons.annotation.{atLeast, explicitGenerics, macroPrivate}

import scala.reflect.macros.blackbox

object TestUtils {
  def need3Params(@atLeast(3) args: Any*) = ()

  @macroPrivate
  def macroPrivateMethod = 42

  def invokeMacroPrivateMethod: Int = macro invokeMacroPrivateMethodImpl

  def invokeMacroPrivateMethodImpl(c: blackbox.Context): c.Tree = {
    import c.universe._
    q"${c.prefix}.macroPrivateMethod"
  }

  object Extractor {
    @macroPrivate def unapply(any: Any): Option[Any] = None
  }

  def genericMacroImpl[T](c: blackbox.Context)(arg: c.Tree): c.Tree = arg

  @explicitGenerics
  def genericMethod[T](arg: T): T = arg
  @explicitGenerics
  def genericMacro[T](arg: T): T = macro genericMacroImpl[T]
} 
Example 67
Source File: ExportMacros.scala    From pureconfig   with Mozilla Public License 2.0 5 votes vote down vote up
package pureconfig.generic

import scala.reflect.macros.blackbox

import pureconfig._


class ExportMacros(val c: blackbox.Context) {
  import c.universe._

  final def exportDerivedReader[A](implicit a: c.WeakTypeTag[A]): c.Expr[Exported[ConfigReader[A]]] = {
    c.typecheck(q"_root_.shapeless.lazily[_root_.pureconfig.generic.DerivedConfigReader[$a]]", silent = true) match {
      case EmptyTree => c.abort(c.enclosingPosition, s"Unable to infer value of type $a")
      case t =>
        c.Expr[Exported[ConfigReader[A]]](
          q"new _root_.pureconfig.Exported($t: _root_.pureconfig.ConfigReader[$a])")
    }
  }

  final def exportDerivedWriter[A](implicit a: c.WeakTypeTag[A]): c.Expr[Exported[ConfigWriter[A]]] = {
    c.typecheck(q"_root_.shapeless.lazily[_root_.pureconfig.generic.DerivedConfigWriter[$a]]", silent = true) match {
      case EmptyTree => c.abort(c.enclosingPosition, s"Unable to infer value of type $a")
      case t =>
        c.Expr[Exported[ConfigWriter[A]]](
          q"new _root_.pureconfig.Exported($t: _root_.pureconfig.ConfigWriter[$a])")
    }
  }
} 
Example 68
Source File: ProtoBinWrapper.scala    From aerospike-scala   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.aerospikeproto.wrapper

import com.aerospike.client.Value
import com.aerospike.client.Value.BytesValue
import com.trueaccord.lenses.Updatable
import com.trueaccord.scalapb.{GeneratedMessage, Message}
import ru.tinkoff.aerospikemacro.converters.BinWrapper

import scala.language.experimental.macros
import scala.reflect.macros.blackbox



trait ProtoBinWrapper[T <: GeneratedMessage with Message[T] with Updatable[T]] extends BinWrapper[T] {
  override def toValue(v: T): Value = new BytesValue(v.toByteArray)

  override def fetch(any: Any): Option[T] = scala.util.Try {
    Value.getFromRecordObject(any) match {
      case b: BytesValue => b.getObject match {
        case arr: Array[Byte] => parse(arr)
      }
    }
  }.toOption

  def parse: Array[Byte] => T
}

object ProtoBinWrapper {
  implicit def materialize[T <: GeneratedMessage
    with Message[T] with Updatable[T]]: ProtoBinWrapper[T] = macro impl[T]

  def impl[T <: GeneratedMessage with Message[T] with Updatable[T] : c.WeakTypeTag]
  (c: blackbox.Context): c.Expr[ProtoBinWrapper[T]] = {
    import c.universe._
    val tpe = weakTypeOf[T]

    val simpleName = tpe.typeSymbol.fullName.split('.').last
    val termName = q"${TermName(simpleName)}"

    c.Expr[ProtoBinWrapper[T]] {
      q"""
      import com.aerospike.client.Value
      import com.aerospike.client.Value.BytesValue
      import com.trueaccord.lenses.Updatable
      import com.trueaccord.scalapb.{GeneratedMessage, Message}
      import ru.tinkoff.aerospikemacro.converters.BinWrapper

      new ProtoBinWrapper[$tpe] {
        override def parse: Array[Byte] => $tpe = $termName.parseFrom
      }
     """
    }
  }
} 
Example 69
Source File: Printer.scala    From aerospike-scala   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.aerospikemacro.printer

import scala.language.experimental.macros
import scala.reflect.macros.blackbox


object Printer {
  def printNameValue[T](x: T): Unit = macro impl[T]

  def impl[R](c: blackbox.Context)(x: c.Tree): c.Tree = {
    import c.universe._
    val tpe = weakTypeOf[R]

    val name = x match {
      case Select(_, TermName(s)) => s
      case _ => ""
    }

    val isArray = tpe.widen.typeSymbol.name.eq(TypeName("Array"))

    q"""
       println("-"*20)
       println($name + " => " + $x)
     """
  }
} 
Example 70
Source File: IgnoreMacro.scala    From diffx   with Apache License 2.0 5 votes vote down vote up
package com.softwaremill.diffx

import scala.annotation.tailrec
import scala.reflect.macros.blackbox

object IgnoreMacro {
  private val ShapeInfo = "Path must have shape: _.field1.field2.each.field3.(...)"

  def ignoreMacro[T: c.WeakTypeTag, U: c.WeakTypeTag](
      c: blackbox.Context
  )(path: c.Expr[T => U]): c.Tree = applyIgnored[T, U](c)(ignoredFromPathMacro(c)(path))

  private def applyIgnored[T: c.WeakTypeTag, U: c.WeakTypeTag](c: blackbox.Context)(
      path: c.Expr[List[String]]
  ): c.Tree = {
    import c.universe._
    q"""{
      ${c.prefix}.ignoreUnsafe($path:_*)
     }"""
  }

  
    @tailrec
    def collectPathElements(tree: c.Tree, acc: List[PathElement]): List[PathElement] = {
      def typeSupported(diffxIgnoreType: c.Tree) =
        Seq("DiffxEach", "DiffxEither", "DiffxEachMap")
          .exists(diffxIgnoreType.toString.endsWith)

      tree match {
        case q"$parent.$child " =>
          collectPathElements(parent, TermPathElement(child) :: acc)
        case q"$tpname[..$_]($t)($f) " if typeSupported(tpname) =>
          val newAcc = acc match {
            // replace the term controlled by quicklens
            case TermPathElement(term, xargs @ _*) :: rest => FunctorPathElement(f, term, xargs: _*) :: rest
            case pathEl :: _ =>
              c.abort(c.enclosingPosition, s"Invalid use of path element $pathEl. $ShapeInfo, got: ${path.tree}")
            case Nil =>
              c.abort(c.enclosingPosition, s"Invalid use of path element(Nil). $ShapeInfo, got: ${path.tree}")
          }
          collectPathElements(t, newAcc)
        case t: Ident => acc
        case _        => c.abort(c.enclosingPosition, s"Unsupported path element. $ShapeInfo, got: $tree")
      }
    }

    val pathEls = path.tree match {
      case q"($arg) => $pathBody " => collectPathElements(pathBody, Nil)
      case _                       => c.abort(c.enclosingPosition, s"$ShapeInfo, got: ${path.tree}")
    }

    c.Expr[List[String]](q"${pathEls.collect {
      case TermPathElement(c) => c.decodedName.toString
    }}")
  }

  private[diffx] def ignoredFromPath[T, U](path: T => U): List[String] = macro ignoredFromPathMacro[T, U]
} 
Example 71
Source File: FeatureBuilderMacros.scala    From TransmogrifAI   with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
package com.salesforce.op.features

import com.salesforce.op.features.types._

import scala.language.experimental.macros
import scala.reflect.macros.blackbox


  private object ParamRename {
    def apply(c: blackbox.Context) = {
      import c.universe._
      new Transformer {
        var i = 0
        var renames = Map[String, String]()
        override def transform(tree: Tree): Tree = {
          val nt = tree match {
            case ValDef(m, TermName(v), tpe, tr) if m.hasFlag(Flag.PARAM) =>
              val newName = "x$" + i.toString
              i = i + 1
              renames = renames + (v -> newName)
              ValDef(m, TermName(newName), tpe, tr)
            case Ident(TermName(v)) if renames.contains(v) => Ident(TermName(renames(v)))
            case x => x
          }
          super.transform(nt)
        }
      }
    }
  }

  // scalastyle:on
} 
Example 72
Source File: ConfiguredJsonCodec.scala    From circe-generic-extras   with Apache License 2.0 5 votes vote down vote up
package io.circe.generic.extras

import io.circe.generic.util.macros.JsonCodecMacros
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

class ConfiguredJsonCodec(
  encodeOnly: Boolean = false,
  decodeOnly: Boolean = false
) extends scala.annotation.StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro ConfiguredJsonCodecMacros.jsonCodecAnnotationMacro
}

private[generic] class ConfiguredJsonCodecMacros(val c: blackbox.Context) extends JsonCodecMacros {
  import c.universe._

  protected[this] def semiautoObj: Symbol = symbolOf[semiauto.type].asClass.module
  protected[this] def deriveMethodPrefix: String = "deriveConfigured"

  def jsonCodecAnnotationMacro(annottees: Tree*): Tree = constructJsonCodec(annottees: _*)
} 
Example 73
Source File: Macros.scala    From seed   with Apache License 2.0 5 votes vote down vote up
import scala.reflect.macros.blackbox
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation

object helloMacro {
  def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    import Flag._
    val result = {
      annottees.map(_.tree).toList match {
        case q"object $name extends ..$parents { ..$body }" :: Nil =>
          q"""
            object $name extends ..$parents {
              def hello: ${typeOf[String]} = "hello"
              ..$body
            }
          """
      }
    }
    c.Expr[Any](result)
  }
}

class hello extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro helloMacro.impl
} 
Example 74
Source File: Macros.scala    From seed   with Apache License 2.0 5 votes vote down vote up
import scala.reflect.macros.blackbox
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation

object helloMacro {
  def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    import Flag._
    val result = {
      annottees.map(_.tree).toList match {
        case q"object $name extends ..$parents { ..$body }" :: Nil =>
          q"""
            object $name extends ..$parents {
              def hello: ${typeOf[String]} = "hello"
              ..$body
            }
          """
      }
    }
    c.Expr[Any](result)
  }
}

class hello extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro helloMacro.impl
} 
Example 75
Source File: Macros.scala    From seed   with Apache License 2.0 5 votes vote down vote up
import scala.reflect.macros.blackbox
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation

object helloMacro {
  def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    import Flag._
    val result = {
      annottees.map(_.tree).toList match {
        case q"object $name extends ..$parents { ..$body }" :: Nil =>
          q"""
            object $name extends ..$parents {
              def hello: ${typeOf[String]} = "hello"
              ..$body
            }
          """
      }
    }
    c.Expr[Any](result)
  }
}

class hello extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro helloMacro.impl
} 
Example 76
Source File: LambdaHTTPApiAnnotation.scala    From quaich   with Apache License 2.0 5 votes vote down vote up
package codes.bytes.quaich.api.http.macros

import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.postfixOps
import scala.reflect.macros.blackbox
import scala.language.experimental.macros

object LambdaHTTPApi {
  // todo - check for companion object and reject
  def annotation_impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    import Flag._

    val p = c.enclosingPosition

    val inputs = annottees.map(_.tree).toList



    val result: Tree = inputs match {
      case (cls @ q"$mods class $name[..$tparams] extends ..$parents { ..$body }") :: Nil if mods.hasFlag(ABSTRACT) ⇒
        c.abort(p, "! The @LambdaHTTPApi annotation is not valid on abstract classes.")
        cls
      // todo - detect and handle companion object!
      case (cls @ q"$mods class $name[..$tparams] extends ..$parents { ..$body }") :: Nil ⇒
        //val baseName = name.decodedName.toString
        //val handlerName = TermName(s"$baseName$$RequestHandler")
        //val handlerName = name.toTermName
        val handlerName = name.asInstanceOf[TypeName].toTermName

        val cls = q"""
        $mods class $name[..$tparams](
            val request: codes.bytes.quaich.api.http.LambdaHTTPRequest,
            val context: codes.bytes.quaich.api.http.LambdaContext
          )
          extends ..$parents
          with codes.bytes.quaich.api.http.HTTPHandler {
            import org.json4s.jackson.JsonMethods._
            import org.json4s.jackson.Serialization
            import org.json4s.jackson.Serialization._
            import org.json4s.{NoTypeHints, _}

            protected implicit val formats = Serialization.formats(NoTypeHints)

            ..$body
          }
        """

        val obj = q"""
        object $handlerName extends codes.bytes.quaich.api.http.HTTPApp {
          def newHandler(
            request: codes.bytes.quaich.api.http.LambdaHTTPRequest,
            context: codes.bytes.quaich.api.http.LambdaContext
          ): codes.bytes.quaich.api.http.HTTPHandler =
            new $name(request, context)


        }
        """

        q"$cls; $obj"

      case Nil ⇒
        c.abort(p, s"Cannot annotate an empty Tree.")
      case _ ⇒
        c.abort(p, s"! The @LambdaHTTPApi Annotation is only valid on non-abstract Classes")
    }

    //c.info(p, "result: " + result, force = true)

    c.Expr[Any](result)

  }

}

@compileTimeOnly("Setup the macro paradise compiler plugin to enable expansion of macro annotations.")
class LambdaHTTPApi extends StaticAnnotation {

  def macroTransform(annottees: Any*): Any = macro LambdaHTTPApi.annotation_impl

}
// vim: set ts=2 sw=2 sts=2 et: 
Example 77
Source File: BodyElementCollectorMacro.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.dsl

import scala.reflect.macros.{ TypecheckException, blackbox }

class BodyElementCollectorMacro(context: blackbox.Context) {
  val c: blackbox.Context = context

  import c.universe._

  private val initTreeFold: (Tree, List[Tree]) = q"Nil" -> Nil

  def collectImpl(body: Tree): Tree = {
    val contextType = c.prefix.tree.tpe
    val validContext = typeOf[BodyElementCollector[_, _]]

    if (!(contextType <:< validContext))
      c.abort(c.enclosingPosition, s"Macro only allowed to be used directly inside of a `$validContext`")
    else {
      val elementType = contextType.typeArgs.head
      blockOrApplyExpressionList(body, elementType) { elements =>
        val (finalTree, rest) = elements.foldLeft(initTreeFold) {
          case ((accTree, accSingle), elem) =>
            if (elem.tpe <:< elementType)
              accTree -> (accSingle :+ elem) //todo avoid List.append
            else
              q"$accTree ++ $accSingle ++ $elem" -> Nil
        }

        q"${c.prefix.tree}.get($finalTree ++ $rest)"
      }
    }
  }

  private def blockOrApplyExpressionList(body: Tree, elementType: Type)(typesTreesFn: List[Tree] => Tree): c.universe.Tree =
    body match {
      case block: Block =>
        blockExpressionList(block, elementType)(typesTreesFn)
      case app: Apply =>
        singleExpressionList(app, elementType)(typesTreesFn)
      case Typed(app: Apply, _) =>
        singleExpressionList(app, elementType)(typesTreesFn)
      case s @ Select(_, _) =>
        singleExpressionList(s, elementType)(typesTreesFn)
      case e =>
        val unsupportedMessage = s"Unsupported expression. Only expressions of type `$elementType` are allowed here."
        c.abort(e.pos, s"$unsupportedMessage\nfound '$e' of type '${e.tpe}'")
    }

  private def singleExpressionList(app: Tree, elementType: Type)(typesTreesFn: List[Tree] => Tree): c.universe.Tree =
    typeCheck(elementType, seqElementType(elementType))(app) match {
      case Right(checked)     => typesTreesFn(checked :: Nil)
      case Left((pos, error)) => c.abort(pos, error)
    }

  private def seqElementType(elementType: Type): Type =
    c.typecheck(q"Seq[$elementType]()").tpe

  private def blockExpressionList(block: Block, elementType: Type)(typesTreesFn: List[Tree] => Tree): c.universe.Tree = {
    val allStats = block.stats :+ block.expr //todo avoid List.append
    val seq = seqElementType(elementType)
    val checked = allStats.map(typeCheck(elementType, seq))

    if (checked.exists(_.isLeft)) {
      val errors = checked.collect { case Left(error) => error }
      errors.dropRight(1).foreach { case (pos, error) => c.error(pos, error) }
      val lastError = errors.last
      c.abort(lastError._1, lastError._2)
    } else
      typesTreesFn(checked.collect { case Right(typed) => typed })
  }

  private def typeCheck(elementType: Type, seq: Type)(tree: Tree): Either[(c.universe.Position, String), c.Tree] = {
    val checked = c.typecheck(tree)
    // checked.tpe is null if the statement is an import
    if (checked.tpe == null)
      Left(tree.pos -> s"Expected expression of either `$elementType` or `$seq` but found '$tree'")
    else if (checked.tpe <:< elementType || checked.tpe <:< seq)
      Right(checked)
    else
      try Right(c.typecheck(tree, pt = elementType)) catch {
        case TypecheckException(_, msg) => Left(tree.pos ->
          (s"Result of this expression can be either `$elementType` or `$seq`. " + msg))
      }
  }
} 
Example 78
Source File: Macro.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.optics.macros.internal

import tofu.optics.{Contains, PContains}

import scala.reflect.macros.blackbox

object Macro {
  def mkContains[S, T, A, B](fieldName: String): PContains[S, T, A, B] = macro MacroImpl.mkContains_impl[S, T, A, B]
}

private[macros] class MacroImpl(val c: blackbox.Context) {
  def genContains_impl[S: c.WeakTypeTag, A: c.WeakTypeTag](field: c.Expr[S => A]): c.Expr[Contains[S, A]] = {
    import c.universe._

    
    object SelectChain {
      def unapply(tree: Tree): Option[(Name, Seq[(Type, TermName)])] = tree match {
        case Select(tail @ Ident(termUseName), field: TermName) =>
          Some((termUseName, Seq(tail.tpe.widen -> field)))
        case Select(tail, field: TermName)                      =>
          SelectChain
            .unapply(tail)
            .map(t => t.copy(_2 = t._2 :+ (tail.tpe.widen -> field)))
        case _                                                  => None
      }
    }

    field match {
      // _.field
      case Expr(
            Function(
              List(ValDef(_, termDefName, _, EmptyTree)),
              Select(Ident(termUseName), fieldNameName)
            )
          ) if termDefName.decodedName.toString == termUseName.decodedName.toString =>
        val fieldName = fieldNameName.decodedName.toString
        mkContains_impl[S, S, A, A](c.Expr[String](q"$fieldName"))

      // _.field1.field2...
      case Expr(
            Function(
              List(ValDef(_, termDefName, _, EmptyTree)),
              SelectChain(termUseName, typesFields)
            )
          ) if termDefName.decodedName.toString == termUseName.decodedName.toString =>
        c.Expr[Contains[S, A]](
          typesFields.map { case (t, f) => q"_root_.tofu.optics.macros.GenContains[$t](_.$f)" }
            .reduce((a, b) => q"$a andThen $b")
        )

      case _ =>
        c.abort(
          c.enclosingPosition,
          s"Illegal field reference ${show(field.tree)}; please use _.field1.field2... instead"
        )
    }
  }

  def mkContains_impl[S: c.WeakTypeTag, T: c.WeakTypeTag, A: c.WeakTypeTag, B: c.WeakTypeTag](
      fieldName: c.Expr[String]
  ): c.Expr[PContains[S, T, A, B]] = {
    import c.universe._

    val (sTpe, tTpe, aTpe, bTpe) = (weakTypeOf[S], weakTypeOf[T], weakTypeOf[A], weakTypeOf[B])

    val strFieldName = c.eval(c.Expr[String](c.untypecheck(fieldName.tree.duplicate)))

    val fieldMethod = sTpe.decls.collectFirst {
      case m: MethodSymbol if m.isCaseAccessor && m.name.decodedName.toString == strFieldName => m
    }.getOrElse(c.abort(c.enclosingPosition, s"Cannot find method $strFieldName in $sTpe"))

    val constructor = sTpe.decls.collectFirst {
      case m: MethodSymbol if m.isPrimaryConstructor => m
    }.getOrElse(c.abort(c.enclosingPosition, s"Cannot find constructor in $sTpe"))

    val field = constructor.paramLists.head
      .find(_.name.decodedName.toString == strFieldName)
      .getOrElse(c.abort(c.enclosingPosition, s"Cannot find constructor field named $fieldName in $sTpe"))

    c.Expr[PContains[S, T, A, B]](q"""
      import _root_.tofu.optics.PContains
      import _root_.scala.language.higherKinds // prevent warning at call site

      new PContains[$sTpe, $tTpe, $aTpe, $bTpe]{
        override def extract(s: $sTpe): $aTpe =
          s.$fieldMethod

        override def set(s: $sTpe, a: $bTpe): $tTpe =
          s.copy($field = a)
      }
    """)
  }
} 
Example 79
Source File: Macros.scala    From swave   with Mozilla Public License 2.0 5 votes vote down vote up
package swave.core

import scala.reflect.macros.blackbox

package object macros {

  def requireArg(cond: Boolean): Unit = macro Macros.requireArgImpl

  def requireArg(cond: Boolean, msg: Any): Unit = macro Macros.requireArg1Impl

  def requireState(cond: Boolean): Unit = macro Macros.requireStateImpl

  def requireState(cond: Boolean, msg: Any): Unit = macro Macros.requireState1Impl
}

package macros {
  private[macros] object Macros {

    def requireArgImpl(c: blackbox.Context)(cond: c.Expr[Boolean]): c.Expr[Unit] = {
      import c.universe._
      reify {
        if (!cond.splice) throw new IllegalArgumentException
      }
    }

    def requireArg1Impl(c: blackbox.Context)(cond: c.Expr[Boolean], msg: c.Expr[Any]): c.Expr[Unit] = {
      import c.universe._
      reify {
        if (!cond.splice) {
          throw new IllegalArgumentException(msg.splice.toString)
        }
      }
    }

    def requireStateImpl(c: blackbox.Context)(cond: c.Expr[Boolean]): c.Expr[Unit] = {
      import c.universe._
      reify {
        if (!cond.splice) {
          throw new IllegalStateException
        }
      }
    }

    def requireState1Impl(c: blackbox.Context)(cond: c.Expr[Boolean], msg: c.Expr[Any]): c.Expr[Unit] = {
      import c.universe._
      reify {
        if (!cond.splice) {
          throw new IllegalStateException(msg.splice.toString)
        }
      }
    }
  }
} 
Example 80
Source File: Macros.scala    From perfolation   with MIT License 5 votes vote down vote up
package perfolation

import scala.StringContext.InvalidEscapeException
import scala.annotation.compileTimeOnly
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

@compileTimeOnly("Enable macros to expand")
object Macros {
  def p(c: blackbox.Context)(args: c.Expr[Any]*): c.Expr[String] = px(c)(args: _*)(scala.StringContext.processEscapes)
  def raw(c: blackbox.Context)(args: c.Expr[Any]*): c.Expr[String] = px(c)(args: _*)(identity)

  private[this] def px(c: blackbox.Context)(args: c.Expr[Any]*)(process: String => String): c.Expr[String] = {
    import c.universe._

    val constants = (c.prefix.tree match {
      case Apply(_, List(Apply(_, literals))) => literals
    }).map { case Literal(Constant(s: String)) =>
      try process(s) catch {
        case ex: InvalidEscapeException => c.abort(c.enclosingPosition, ex.getMessage)
      }
    }

    if (args.isEmpty) c.Expr(Literal(Constant(constants.mkString)))
    else {
      val (valDeclarations, values) = args.map { arg =>
        arg.tree match {
          case tree @ Literal(Constant(_)) =>
            (EmptyTree, if (tree.tpe <:< definitions.NullTpe) q"(null: String)" else tree)
          case tree =>
            val name = TermName(c.freshName())
            val tpe = if (tree.tpe <:< definitions.NullTpe) typeOf[String] else tree.tpe
            (q"val $name: $tpe = $arg", Ident(name))
        }
      }.unzip

      val stringBuilderWithAppends = constants.zipAll(values, "", null)
        .foldLeft(q"perfolation.stringBuilder()") { case (sb, (s, v)) =>
          val len = s.length
          if (len == 0) {
            if (v == null) sb
            else q"$sb.append($v)"
          } else if (len == 1) {
            if (v == null) q"$sb.append(${s.charAt(0)})"
            else q"$sb.append(${s.charAt(0)}).append($v)"
          } else {
            if (v == null) q"$sb.append($s)"
            else q"$sb.append($s).append($v)"
          }
        }

      c.Expr(c.typecheck(q"..$valDeclarations; $stringBuilderWithAppends.toString"))
    }
  }
} 
Example 81
Source File: CypherStringInterpolator.scala    From neotypes   with MIT License 5 votes vote down vote up
package neotypes

import types.QueryParam

import scala.reflect.macros.blackbox

final class CypherStringInterpolator(private val sc: StringContext) extends AnyVal {
  def c(args: Any*): DeferredQueryBuilder = macro CypherStringInterpolator.macroImpl
}

object CypherStringInterpolator {
  def createQuery(sc: StringContext)(parameters: QueryParam*): DeferredQueryBuilder = {
    val queries = sc.parts.iterator.map(DeferredQueryBuilder.Query)
    val params = parameters.iterator.map(DeferredQueryBuilder.Param)

    val queryParts = new Iterator[DeferredQueryBuilder.Part] {
      private var paramNext: Boolean = false
      override def hasNext: Boolean = queries.hasNext
      override def next(): DeferredQueryBuilder.Part =
        if (paramNext && params.hasNext) {
          paramNext = false
          params.next()
        } else {
          paramNext = true
          queries.next()
        }
    }

    new DeferredQueryBuilder(queryParts.toList)
  }

  def macroImpl(c: blackbox.Context)(args: c.Expr[Any]*): c.Expr[DeferredQueryBuilder] = {
    import c.universe._

    val q"$foo($sc)" = c.prefix.tree
    neotypes.internal.utils.void(q"$foo")

    val parameters = args.map { arg =>
      val nextElement = arg.tree
      val tpe = nextElement.tpe.widen

      q"neotypes.mappers.ParameterMapper[${tpe}].toQueryParam(${nextElement})"
    }

    c.Expr(
      q"neotypes.CypherStringInterpolator.createQuery(${sc})(..${parameters})"
    )
  }
} 
Example 82
Source File: Connections.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl

import scala.reflect.macros.blackbox

class Connections(val c: blackbox.Context) {
  import c.universe._

  def setup(setup: Tree): Tree = {
    val q"$_.$name[$tpt](...$_)" = c.macroApplication

    q"${termNames.ROOTPKG}.loci.language.Connections.$name(${signature(tpt)}, $setup)"
  }

  def factory(factory: Tree)(args: Tree*): Tree = {
    val q"$_.$name[$tpt](...$_)" = c.macroApplication
    val arguments =
      if (args.size == 1)
        args :+ q"${termNames.ROOTPKG}.scala.collection.immutable.Map.empty"
      else
        args

    q"${termNames.ROOTPKG}.loci.language.Connections.$name(..${signature(tpt) +: factory +: arguments})"
  }

  private val documentationCompiler =
    c.compilerSettings.size > 1 && (c.compilerSettings sliding 2 exists {
      case Seq(flag, value) =>
        flag == "-d" && ((value endsWith "/api") || (value endsWith "\\api"))
    })

  private def signature(tpt: Tree) = {
    val name = TermName(s"$$loci$$peer$$sig$$${tpt.symbol.name}")

    tpt match {
      case _ if documentationCompiler =>
        q"${termNames.ROOTPKG}.scala.Predef.???"

      case tq"$prefix.$_" if (prefix.tpe member name) != NoSymbol =>
        q"$prefix.$name"

      case _ =>
        c.abort(
          if (tpt.pos != NoPosition) tpt.pos else c.enclosingPosition,
          s"$tpt is not a peer type")
    }
  }
} 
Example 83
Source File: Component.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl

import scala.reflect.macros.blackbox

trait Component[C <: blackbox.Context] {
  val engine: Engine[C]
  val phases: Seq[Phase]
}

object Component {
  type AnyFactory = Factory[Component]

  abstract class Factory[+Comp[C <: blackbox.Context] <: Component[C]](
    val requires: Seq[AnyFactory] = Seq.empty) {

    def asInstance[C <: blackbox.Context]: PartialFunction[Component[C], Comp[C]]
    def apply[C <: blackbox.Context](engine: Engine[C]): Comp[C]
  }
} 
Example 84
Source File: Remote.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl

import scala.reflect.macros.blackbox

object Remote {
  def asRemote[P: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
    import c.universe._

    val q"$expr.asRemote[$tpt]" = c.macroApplication

    val enclosingMultitierMacro = c.enclosingMacros exists { c =>
      import c.universe._

      val multitier = c.mirror.staticClass(s"${termNames.ROOTPKG}.loci.multitier")

      c.macroApplication match {
        case q"new $expr[..$tpts](...$exprss).macroTransform[..$_](...$_)" =>
          c.typecheck(q"new $expr[..$tpts](...$exprss)", silent = true) match {
            case q"new $expr[..$_](...$_)" =>
              expr.symbol == multitier
            case _ =>
              false
          }
        case _ =>
          false
      }
    }

    val documentationCompiler =
      c.compilerSettings.size > 1 && (c.compilerSettings sliding 2 exists {
        case Seq(flag, value) =>
          flag == "-d" && ((value endsWith "/api") || (value endsWith "\\api"))
      })

    if (!enclosingMultitierMacro && !documentationCompiler) {
      val remote = weakTypeOf[Remote[P]]
      val reference = typeOf[runtime.Remote.Reference]
      val name = TermName(s"$$loci$$peer$$sig$$${tpt.symbol.name}")

      val prefix = tpt match {
        case tq"$prefix.$_" if (prefix.tpe member name) != NoSymbol =>
          prefix
        case _ =>
          c.abort(
            if (tpt.pos != NoPosition) tpt.pos else c.enclosingPosition,
            s"$tpt is not a peer type")
      }

      val signature = q"$prefix.$name"
      val ref = TermName("$loci$ref")

      q"""$expr match {
        case $ref: $reference if $ref.signature <= $signature =>
          ${termNames.ROOTPKG}.scala.Some[$remote]($ref)
        case _ =>
          ${termNames.ROOTPKG}.scala.None
      }"""
    }
    else if (documentationCompiler)
      atPos(tpt.pos) { q"${termNames.ROOTPKG}.scala.Predef.???" }
    else
      atPos(tpt.pos) { q"${termNames.ROOTPKG}.loci.runtime.Remote.cast[$tpt]($expr)" }
  }
} 
Example 85
Source File: ContextReference.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl

import scala.reflect.macros.blackbox

trait ContextReference {
  object Value {
    trait Base[C <: blackbox.Context] { val c: C }
  }

  type Value[C <: blackbox.Context] <: Value.Base[C]

  def apply[C <: blackbox.Context](c: C): Value[c.type]

  private var value: Value[_] = _

  final def get(c: blackbox.Context): Value[c.type] =
    this.value match {
      case value: Value[c.type] @unchecked if value.c eq c =>
        value
      case _ =>
        val value = apply(c)
        this.value = value
        value
    }
} 
Example 86
Source File: Logging.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl

import scala.reflect.macros.blackbox

object Logging {
  def apply(c: blackbox.Context) = new Logging(c)
}

class Logging(c: blackbox.Context) {
  private val info = c.compilerSettings contains "-verbose"
  private val debug = c.settings contains "loci.macro.verbose"
  private val code = c.settings contains "loci.macro.expanded-code"

  def infoEnabled = info || debug

  def debugEnabled = debug

  def codeEnabled = code

  def info(message: => String): Unit =
    if (infoEnabled)
      c.info(c.universe.NoPosition, message, force = true)

  def debug(message: => String): Unit =
    if (debugEnabled)
      c.info(c.universe.NoPosition, message, force = true)

  def code(message: => String): Unit =
    if (codeEnabled)
      c.info(c.universe.NoPosition, message, force = true)
} 
Example 87
Source File: MultitierTypes.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl
package preprocessors

import scala.reflect.macros.blackbox

object MultitierTypes extends Preprocessor.Factory[MultitierTypes] {
  def apply[C <: blackbox.Context](c: C) = new MultitierTypes(c)
}

class MultitierTypes[C <: blackbox.Context](val c: C) extends Preprocessor[C] {
  import c.universe._

  def process(tree: Tree): Tree = {
    val outer = tree

    object transformer extends Transformer {
      override def transform(tree: Tree): Tree = tree match {
        case ClassDef(mods, name, tparams, impl @ Template(parents, self, body))
            if !(mods hasFlag Flag.TRAIT) && tree != outer =>
          super.transform(treeCopy.ClassDef(
            tree, mods, name, tparams, treeCopy.Template(
              impl, parents, self, placedValuesDef :: body)))

        case _ =>
          super.transform(tree)
      }
    }

    transformer transform tree
  }

  private val placedValuesDef =
    q"${Flag.SYNTHETIC} protected[this] def `<placed values>`: Nothing = _root_.scala.Predef.???"
} 
Example 88
Source File: AbstractValues.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl
package preprocessors

import scala.reflect.macros.blackbox

object AbstractValues extends Preprocessor.Factory[AbstractValues] {
  def apply[C <: blackbox.Context](c: C) = new AbstractValues(c)
}

class AbstractValues[C <: blackbox.Context](val c: C) extends Preprocessor[C] {
  import c.universe._

  def process(tree: Tree): Tree = {
    def reducedFlags(mods: Modifiers) =
      Seq(Flag.ABSOVERRIDE, Flag.ARTIFACT, Flag.FINAL, Flag.IMPLICIT,
          Flag.LOCAL, Flag.MUTABLE, Flag.OVERRIDE, Flag.PRESUPER,
          Flag.PRIVATE, Flag.PROTECTED, Flag.STABLE, Flag.SYNTHETIC)
        .foldLeft(NoFlags) { (flagAcc, flag) =>
          if (mods hasFlag flag) flagAcc | flag else flagAcc
        }

    def processMods(mods: Modifiers) =
      Modifiers(reducedFlags(mods), mods.privateWithin, annotation :: mods.annotations)

    def processStats(stats: List[Tree]) = stats map {
      case tree @ DefDef(mods, name, tparams, vparamss, tpt, EmptyTree)
          if (mods hasFlag Flag.DEFERRED) && !(mods hasFlag Flag.PRIVATE) =>
        treeCopy.DefDef(
          tree, processMods(mods), name, tparams, vparamss, tpt, q"null.asInstanceOf[$tpt]")

      case tree @ ValDef(mods, name, tpt, EmptyTree)
          if (mods hasFlag Flag.DEFERRED) && !(mods hasFlag Flag.PRIVATE) =>
        treeCopy.ValDef(
          tree, processMods(mods), name, tpt, q"null.asInstanceOf[$tpt]")

      case tree =>
        tree
    }

    object transformer extends Transformer {
      override def transform(tree: Tree): Tree = tree match {
        case ClassDef(mods, name, tparams, impl @ Template(parents, self, body))
            if mods hasFlag Flag.FINAL =>
          super.transform(treeCopy.ClassDef(
            tree, mods, name, tparams, treeCopy.Template(
              impl, parents, self, processStats(body))))

        case ModuleDef(mods, name, impl @ Template(parents, self, body)) =>
          super.transform(treeCopy.ModuleDef(
            tree, mods, name, treeCopy.Template(
              impl, parents, self, processStats(body))))

        case _ =>
          super.transform(tree)
      }
    }

    transformer transform tree
  }

  private val annotation = q"new ${termNames.ROOTPKG}.loci.runtime.AbstractValue"
} 
Example 89
Source File: Preprocessor.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl

import scala.reflect.macros.blackbox

trait Preprocessor[C <: blackbox.Context] {
  val c: C
  def process(tree: c.Tree): c.Tree
}

object Preprocessor {
  def run(
      c: blackbox.Context)(
      tree: c.Tree,
      factories: Seq[Preprocessor.Factory[Preprocessor]]) = {
    val logging = Logging(c)

    val preprocessors = factories.distinct map { factory => factory[c.type](c) }

    logging.debug("Multitier preprocessors")
    preprocessors foreach { preprocessor =>
      logging.debug(s" ${name(preprocessor)}")
    }

    preprocessors.foldLeft(tree) { (tree, preprocessor) =>
      logging.debug(s"Running multitier preprocessor ${name(preprocessor)}")
      preprocessor process tree
    }
  }

  private def name(ref: AnyRef) = {
    val name = ref.getClass.getSimpleName
    if (name endsWith "$")
      name.dropRight(1)
    else
      name
  }

  abstract class Factory[+Pre[C <: blackbox.Context] <: Preprocessor[C]] {
    def apply[C <: blackbox.Context](c: C): Pre[C]
  }
} 
Example 90
Source File: RuntimeAccess.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl
package components

import scala.reflect.macros.blackbox

object RuntimeAccess extends Component.Factory[RuntimeAccess](
    requires = Seq(Commons, Values)) {
  def apply[C <: blackbox.Context](engine: Engine[C]) = new RuntimeAccess(engine)
  def asInstance[C <: blackbox.Context] = { case c: RuntimeAccess[C] => c }
}

class RuntimeAccess[C <: blackbox.Context](val engine: Engine[C]) extends Component[C] {
  val phases = Seq(
    Phase("runtime:access", processRuntimeAccess, after = Set("values:collect"), before = Set("impls:lift")))

  val commons = engine.require(Commons)
  val values = engine.require(Values)

  import engine.c.universe._
  import commons._
  import values._

  def processRuntimeAccess(records: List[Any]): List[Any] = {
    var count = 0
    val result = records process {
      case record @ PlacedValue(_, _, _, _) =>
        object transformer extends Transformer {
          override def transform(tree: Tree): Tree = tree match {
            case q"$_.$name[..$tpts](...$exprss)"
                if tree.symbol.owner == symbols.multitier &&
                  (name == names.running || name == names.terminate) =>
              count += 1
              q"$$loci$$sys.$name[..$tpts](...$exprss)"

            case _ =>
              super.transform(tree)
          }
        }

        record.copy(tree = transformer transform record.tree)
    }

    logging.debug(s" Processed $count multitier runtime ${if (count == 1) "query" else "queries"}")

    result
  }
} 
Example 91
Source File: Subjectivity.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl
package components

import scala.reflect.macros.blackbox

object Subjectivity extends Component.Factory[Subjectivity](
    requires = Seq(Commons, Values)) {
  def apply[C <: blackbox.Context](engine: Engine[C]) = new Subjectivity(engine)
  def asInstance[C <: blackbox.Context] = { case c: Subjectivity[C] => c }
}

class Subjectivity[C <: blackbox.Context](val engine: Engine[C]) extends Component[C] {
  val phases = Seq(
    Phase("local:sbj", processLocalSubjectiveAccess, after = Set("values:collect"), before = Set("impls:lift")))

  val commons = engine.require(Commons)
  val values = engine.require(Values)

  import engine.c.universe._
  import commons._
  import values._

  def processLocalSubjectiveAccess(records: List[Any]): List[Any] = {
    var count = 0
    val result = records process {
      case record @ PlacedValue(_, _, _, _) =>
        object transformer extends Transformer {
          override def transform(tree: Tree): Tree = tree match {
            case q"$expr.$_[..$_]($_[..$_](...$exprss))"
                if tree.nonEmpty &&
                   tree.symbol == symbols.to =>
              decomposePlacementType(expr.tpe.widen, EmptyTree, expr.symbol, expr.pos, moduleDefinition = false) match {
                case Placed(_, _, _, Modality.Subjective(_)) =>
                  count += 1

                  val value = transform(expr)
                  val remote = transform(exprss.head.head)

                  if (expr.symbol.isTerm && expr.symbol.asTerm.isStable)
                    q"$$loci$$sys.subjectiveValue($value, $remote)"
                  else
                    q"$value($remote)"

                case _ =>
                  transform(expr)
              }

            case _ =>
              super.transform(tree)
          }
        }

        record.copy(tree = transformer transform record.tree)
    }

    logging.debug(s" Processed $count local ${if (count == 1) "access" else "accesses"} to subjective values")

    result
  }
} 
Example 92
Source File: ModuleInfo.scala    From scala-loci   with Apache License 2.0 5 votes vote down vote up
package loci
package language
package impl
package components

import scala.reflect.macros.blackbox

object ModuleInfo extends Component.Factory[ModuleInfo](
    requires = Seq(Commons)) {
  def apply[C <: blackbox.Context](engine: Engine[C]) = new ModuleInfo(engine)
  def asInstance[C <: blackbox.Context] = { case c: ModuleInfo[C] => c }
}

class ModuleInfo[C <: blackbox.Context](val engine: Engine[C]) extends Component[C] {
  val phases = Seq.empty

  val commons = engine.require(Commons)

  import engine.c.universe._
  import commons._

  object module {
    val tree = engine.multitierCode
    val name = tree.name
    val className = name.toTypeName
    val symbol = tree.symbol
    val classSymbol = if (symbol.isModule) symbol.asModule.moduleClass.asClass else symbol.asClass
    val self = uniqueRealisticTermName(engine.multitierCode.symbol)
    val outer = engine.outerMultitierName.headOption
    val path = engine.outerMultitierName.reverse map { case (value, _) => value }
  }

  private val underExpansion: Set[Symbol] = (engine.multitierCode collect {
    case tree: DefTree if tree.symbol != NoSymbol => tree.symbol
  }).toSet

  def underExpansion(symbol: Symbol): Boolean = underExpansion contains symbol

  private val underEnclosingExpansion: Set[Symbol] = (engine.outerMultitierCode collect {
    case tree: DefTree if tree.symbol != NoSymbol => tree.symbol
  }).toSet

  def underEnclosingExpansion(symbol: Symbol): Boolean = underEnclosingExpansion contains symbol
} 
Example 93
Source File: DerivingMacros.scala    From scalaz-deriving   with GNU Lesser General Public License v3.0 5 votes vote down vote up
// Copyright: 2017 - 2020 Sam Halliday
// License: http://www.gnu.org/licenses/lgpl-3.0.en.html

package scalaz.macros

import scala.Predef._
import scala.reflect.macros.blackbox

final class DerivingMacrosImpl(val c: blackbox.Context) {
  import c.universe._

  def deriving[F[_], A](implicit
    evF: c.WeakTypeTag[F[_]],
    evA: c.WeakTypeTag[A]
  ): Tree = {
    val F   = evF.tpe
    val A   = evA.tpe
    val fqn = F.dealias.typeSymbol.fullName
    readConfig().targets.get(fqn) match {
      case Some(target) => parseTerm(target)
      case None         => q"_root_.scalaz.Deriving.gen[$F, $A]"
    }
  }

  def xderiving[F[_], A](implicit
    evF: c.WeakTypeTag[F[_]],
    evA: c.WeakTypeTag[A]
  ): Tree = {
    val F = evF.tpe
    val A = evA.tpe
    A.decls.collect {
      case m: MethodSymbol if m.isParamAccessor => m.asMethod
    }.toList match {
      case value :: Nil =>
        val hasXmap   = F.decls.find(_.name.toString == "xmap").isDefined
        val access    = value.name
        val U         = value.typeSignatureIn(A).resultType
        def invariant =
          q"""_root_.scalaz.InvariantFunctor[${F.typeSymbol}].xmap(
              _root_.scala.Predef.implicitly[${F.typeSymbol}[$U]],
              (u: $U) => new $A(u),
              (a: $A) => a.$access)"""
        def xmap      =
          q"""_root_.scala.Predef.implicitly[${F.typeSymbol}[$U]].xmap(
              (u: $U) => new $A(u),
              (a: $A) => a.$access)"""
        if (hasXmap) xmap else invariant
      case _            =>
        c.abort(c.enclosingPosition, "only supports classes with one parameter")
    }
  }

  private def readConfig(): DerivingConfig =
    DerivingConfig.targets
      .fold(
        error => {
          c.error(c.prefix.tree.pos, s"Failed to parse deriving config: $error")
          throw new IllegalStateException
        },
        success => DerivingConfig(success)
      )

  private def parseTerm(s: String): Tree = {
    def toSelect(parts: List[TermName]): Tree =
      parts match {
        case Nil          => Ident(termNames.ROOTPKG)
        case head :: tail => Select(toSelect(tail), head)
      }
    toSelect(s.split("[.]").toList.map(TermName(_)).reverse)
  }

}

object DerivingMacros {
  def deriving[F[_], A]: F[A] = macro DerivingMacrosImpl.deriving[F, A]
  def xderiving[F[_], A]: F[A] = macro DerivingMacrosImpl.xderiving[F, A]
} 
Example 94
Source File: LoggerMacros.scala    From almond   with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
package almond.logger.internal

import scala.reflect.macros.blackbox

object LoggerMacros {

  def error(c: blackbox.Context)(message: c.Expr[String]): c.universe.Tree = {
    import c.universe._
    q"if (${c.prefix}.underlying.errorEnabled) ${c.prefix}.underlying.error($message)"
  }

  def warn(c: blackbox.Context)(message: c.Expr[String]): c.universe.Tree = {
    import c.universe._
    q"if (${c.prefix}.underlying.warningEnabled) ${c.prefix}.underlying.warn($message)"
  }

  def info(c: blackbox.Context)(message: c.Expr[String]): c.universe.Tree = {
    import c.universe._
    q"if (${c.prefix}.underlying.infoEnabled) ${c.prefix}.underlying.info($message)"
  }

  def debug(c: blackbox.Context)(message: c.Expr[String]): c.universe.Tree = {
    import c.universe._
    q"if (${c.prefix}.underlying.debugEnabled) ${c.prefix}.underlying.debug($message)"
  }


  def errorEx(c: blackbox.Context)(message: c.Expr[String], throwable: c.Expr[Throwable]): c.universe.Tree = {
    import c.universe._
    q"if (${c.prefix}.underlying.errorEnabled) ${c.prefix}.underlying.error($message, $throwable)"
  }

  def warnEx(c: blackbox.Context)(message: c.Expr[String], throwable: c.Expr[Throwable]): c.universe.Tree = {
    import c.universe._
    q"if (${c.prefix}.underlying.warningEnabled) ${c.prefix}.underlying.warn($message, $throwable)"
  }

  def infoEx(c: blackbox.Context)(message: c.Expr[String], throwable: c.Expr[Throwable]): c.universe.Tree = {
    import c.universe._
    q"if (${c.prefix}.underlying.infoEnabled) ${c.prefix}.underlying.info($message, $throwable)"
  }

  def debugEx(c: blackbox.Context)(message: c.Expr[String], throwable: c.Expr[Throwable]): c.universe.Tree = {
    import c.universe._
    q"if (${c.prefix}.underlying.debugEnabled) ${c.prefix}.underlying.debug($message, $throwable)"
  }

} 
Example 95
Source File: Macros.scala    From caliban   with Apache License 2.0 5 votes vote down vote up
package caliban

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

import caliban.parsing.Parser

object Macros {

  
  def gqldoc(document: String): String = macro MacrosInternal.queryLiteral

  private class MacrosInternal(val c: blackbox.Context) {
    import c.universe._
    def queryLiteral(document: c.Expr[String]): c.Expr[String] =
      document.tree match {
        case Literal(Constant(s: String)) =>
          Parser.check(s).fold(document)(e => c.abort(c.enclosingPosition, s"GraphQL document is invalid: $e"))
        case _ =>
          c.abort(c.enclosingPosition, s"This macro can only be used with string literals.")
      }
  }
} 
Example 96
Source File: CodeExampleImpl.scala    From slinky   with MIT License 5 votes vote down vote up
package slinky.docs

import java.io.File

import slinky.core.facade.ReactElement

import scala.io.Source
import scala.reflect.macros.blackbox

object CodeExampleImpl {
  def text(c: blackbox.Context)(exampleLocation: c.Expr[String]): c.Expr[ReactElement] = {
    import c.universe._
    val Literal(Constant(loc: String)) = exampleLocation.tree
    val inputFile = new File(s"docs/src/main/scala/${loc.split('.').mkString("/")}.scala")
    val enclosingPackage = loc.split('.').init.mkString(".")

    val fileContent = Source.fromFile(inputFile).mkString

    val innerCode = fileContent.split('\n')

    val textToDisplay = innerCode
      .map(_.replaceAllLiterally("//display:", ""))
      .filterNot(_.endsWith("//nodisplay"))
      .dropWhile(_.trim.isEmpty)
      .reverse.dropWhile(_.trim.isEmpty).reverse
      .mkString("\n")

    val codeToRun = innerCode.filter(_.startsWith("//run:")).map(_.replaceAllLiterally("//run:", "")).mkString("\n")

    c.Expr[ReactElement](
      q"""{
         import ${c.parse(enclosingPackage)}._

         _root_.slinky.docs.CodeExampleInternal(codeText = ${Literal(Constant(textToDisplay))}, demoElement = {${c.parse(codeToRun)}})
       }""")
  }
} 
Example 97
Source File: SymbolMacros.scala    From typed-schema   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.tschema.macros
import shapeless.ReprTypes

import scala.reflect.macros.{blackbox, whitebox}

trait SymbolMacros extends ReprTypes {
  val c: blackbox.Context

  import c.universe._
  import c.internal.{constantType, refinedType}

  def taggedType = typeOf[shapeless.tag.Tagged[_]].typeConstructor

  object KeyName {
    def apply(name: String): Type =
      NamedSymbol(appliedType(taggedType, constantType(Constant(name))))

    def unapply(tpe: Type): Option[String] = tpe match {
      case NamedSymbol(ConstantType(Constant(name: String))) => Some(name)
      case ConstantType(Constant(name: String))              => Some(name)
      case _                                                 => None
    }
  }

  object NamedSymbol {
    def apply(tpe: Type): Type = refinedType(List(symbolTpe, tpe), NoSymbol)

    def unapply(tpe: Type): Option[Type] = tpe.dealias match {
      case RefinedType(List(sym, tag, _*), _) if sym == symbolTpe => tag.typeArgs.headOption
      case _                                                      => None
    }
  }

  def freshIdent(name: String): Ident   = Ident(freshName(name))
  def freshName(name: String): TermName = TermName(c.freshName(name))

} 
Example 98
Source File: ShapelessMacros.scala    From typed-schema   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.tschema.macros
import shapeless.ReprTypes

import scala.annotation.tailrec
import scala.reflect.macros.blackbox

trait ShapelessMacros extends ReprTypes with MacroMessages with SymbolMacros {
  val c: blackbox.Context
  import c.universe._

  def unfoldCompoundTpe(compoundTpe: Type, nil: Type, cons: Type): List[Type] = {
    @tailrec
    def loop(tpe: Type, acc: List[Type]): List[Type] =
      tpe.dealias match {
        case TypeRef(_, consSym, List(hd, tl)) if consSym.asType.toType.typeConstructor =:= cons => loop(tl, hd :: acc)
        case `nil`                                                                               => acc
        case other                                                                               => abort(s"Bad compound type $compoundTpe")
      }
    loop(compoundTpe, Nil).reverse
  }

  def hlistElements(tpe: Type): List[Type] =
    unfoldCompoundTpe(tpe, hnilTpe, hconsTpe)

  def extractRecord(tpe: Type): List[Option[(String, Type)]] =
    hlistElements(tpe).map {
      case FieldType(KeyName(name), value) => Some(name -> value)
      case _                               => None
    }

  object FieldType {
    import internal._

    def apply(kTpe: Type, vTpe: Type): Type =
      refinedType(List(vTpe, typeRef(keyTagTpe, keyTagTpe.typeSymbol, List(kTpe, vTpe))), NoSymbol)

    def unapply(fTpe: Type): Option[(Type, Type)] = {
      val KeyTagPre = keyTagTpe
      fTpe.dealias match {
        case RefinedType(List(v0, TypeRef(pre, sym, List(k, v1))), _)
            if sym.asType.toType.typeConstructor =:= KeyTagPre && v0 =:= v1 =>
          Some((k, v0))
        case _ => None
      }
    }
  }

} 
Example 99
Source File: Query1.scala    From scio   with Apache License 2.0 5 votes vote down vote up
package com.spotify.scio.sql

import com.spotify.scio.schemas._
import com.spotify.scio.values.SCollection
import org.apache.beam.sdk.extensions.sql.SqlTransform
import org.apache.beam.sdk.extensions.sql.impl.ParseException
import org.apache.beam.sdk.values._

import scala.reflect.ClassTag

final case class Query1[A, B](
  query: String,
  tag: TupleTag[A] = Sql.defaultTag[A],
  udfs: List[Udf] = Nil
)

object Query1 {
  import scala.reflect.macros.blackbox
  import QueryMacros._

  
  def typecheck[A: Schema, B: Schema](q: Query1[A, B]): Either[String, Query1[A, B]] =
    Queries
      .typecheck(
        q.query,
        List((q.tag.getId, SchemaMaterializer.beamSchema[A])),
        SchemaMaterializer.beamSchema[B],
        q.udfs
      )
      .right
      .map(_ => q)

  def typed[A: Schema, B: Schema](query: String): Query1[A, B] =
    macro typedImplDefaultTag[A, B]

  def typed[A: Schema, B: Schema](query: String, aTag: TupleTag[A]): Query1[A, B] =
    macro typedImpl[A, B]

  def typedImplDefaultTag[A: c.WeakTypeTag, B: c.WeakTypeTag](c: blackbox.Context)(
    query: c.Expr[String]
  )(iSchema: c.Expr[Schema[A]], oSchema: c.Expr[Schema[B]]): c.Expr[Query1[A, B]] = {
    val h = new { val ctx: c.type = c } with SchemaMacroHelpers
    import h._
    import c.universe._

    val tag = c.Expr[TupleTag[A]](q"${Sql.defaultTag[A]}")
    typedImpl(c)(query, tag)(iSchema, oSchema)
  }

  def typedImpl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: blackbox.Context)(
    query: c.Expr[String],
    aTag: c.Expr[TupleTag[A]]
  )(iSchema: c.Expr[Schema[A]], oSchema: c.Expr[Schema[B]]): c.Expr[Query1[A, B]] = {
    val h = new { val ctx: c.type = c } with SchemaMacroHelpers
    import h._
    import c.universe._

    assertConcrete[A](c)
    assertConcrete[B](c)

    val (sIn, sOut) =
      c.eval(c.Expr[(Schema[A], Schema[B])](q"(${untyped(iSchema)}, ${untyped(oSchema)})"))

    val sq = Query1[A, B](cons(c)(query), tupleTag(c)(aTag))
    typecheck(sq)(sIn, sOut)
      .fold(
        err => c.abort(c.enclosingPosition, err),
        _ => c.Expr[Query1[A, B]](q"_root_.com.spotify.scio.sql.Query1($query, $aTag)")
      )
  }
}

final class SqlSCollection1[A: Schema: ClassTag](sc: SCollection[A]) {
  def query(q: String, udfs: Udf*): SCollection[Row] =
    query(Query1[A, Row](q, Sql.defaultTag, udfs = udfs.toList))

  def query(q: Query1[A, Row]): SCollection[Row] =
    sc.context.wrap {
      val scWithSchema = Sql.setSchema(sc)
      val transform =
        SqlTransform
          .query(q.query)
          .withTableProvider(Sql.BeamProviderName, Sql.tableProvider(q.tag, scWithSchema))
      val sqlTransform = Sql.registerUdf(transform, q.udfs: _*)
      scWithSchema.applyInternal(sqlTransform)
    }

  def queryAs[R: Schema: ClassTag](q: String, udfs: Udf*): SCollection[R] =
    queryAs(Query1[A, R](q, Sql.defaultTag, udfs = udfs.toList))

  def queryAs[R: Schema: ClassTag](q: Query1[A, R]): SCollection[R] =
    try {
      query(Query1[A, Row](q.query, q.tag, q.udfs)).to(To.unchecked((_, i) => i))
    } catch {
      case e: ParseException =>
        Query1.typecheck(q).fold(err => throw new RuntimeException(err, e), _ => throw e)
    }
} 
Example 100
Source File: MacroSettings.scala    From scio   with Apache License 2.0 5 votes vote down vote up
package com.spotify.scio

import scala.reflect.macros.blackbox

sealed private[scio] trait FeatureFlag
private[scio] object FeatureFlag {
  case object Enable extends FeatureFlag
  case object Disable extends FeatureFlag
}

private[scio] object MacroSettings {
  private def getFlag(settings: List[String])(name: String, default: FeatureFlag): FeatureFlag = {
    val ss: Map[String, String] =
      settings
        .map(_.split("="))
        .map {
          case Array(k, v) =>
            (k.trim, v.trim)
        }
        .toMap

    ss.get(name)
      .map {
        case "true" =>
          FeatureFlag.Enable
        case "false" =>
          FeatureFlag.Disable
        case v =>
          throw new IllegalArgumentException(
            s"""Invalid value for setting -Xmacro-settings:$name,""" +
              s"""expected "true" or "false", got $v"""
          )
      }
      .getOrElse(default)
  }

  
  def cacheImplicitSchemas(c: blackbox.Context): FeatureFlag =
    getFlag(c.settings)("cache-implicit-schemas", FeatureFlag.Disable)
} 
Example 101
Source File: SysPropsMacros.scala    From scio   with Apache License 2.0 5 votes vote down vote up
package com.spotify.scio

import scala.annotation.{compileTimeOnly, StaticAnnotation}
import scala.reflect.macros.blackbox

@compileTimeOnly(
  "enable macro paradise (2.12) or -Ymacro-annotations (2.13) to expand macro annotations"
)
final class registerSysProps extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro registerSysPropsMacro.impl
}

private object registerSysPropsMacro {
  def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._

    val traitT = tq"_root_.com.spotify.scio.SysProps"

    annottees.map(_.tree) match {
      case List(q"$mod object $name extends ..$parents { ..$body }") =>
        val vars = body.collect {
          case ValDef(_, _, _, rhs) => c.Expr(rhs)
        }

        val propertiesMethod =
          q"""override def properties: List[SysProp] = List(..$vars)"""

        c.Expr[Any](q"""
            $mod object $name extends ..$parents with $traitT {
              $propertiesMethod
              ..$body
            }
            """)
      case t => c.abort(c.enclosingPosition, s"Invalid annotation $t")
    }
  }
} 
Example 102
Source File: AvroCoderMacros.scala    From scio   with Apache License 2.0 5 votes vote down vote up
package com.spotify.scio.coders

import org.apache.avro.specific.SpecificRecordBase

import scala.reflect.macros.blackbox

private[coders] object AvroCoderMacros {

  
  def staticInvokeCoder[T <: SpecificRecordBase: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
    import c.universe._
    val wtt = weakTypeOf[T]
    val companioned = wtt.typeSymbol

    q"""
    _root_.com.spotify.scio.coders.Coder.beam(
      _root_.org.apache.beam.sdk.coders.AvroCoder.of[$companioned](
        classOf[$companioned],
        new $companioned().getSchema
      )
    )
    """
  }
} 
Example 103
Source File: SetProperty.scala    From scio   with Apache License 2.0 5 votes vote down vote up
package com.spotify.scio.bigquery.validation

import scala.annotation.{compileTimeOnly, StaticAnnotation}
import scala.reflect.macros.blackbox

// This shouldn't be necessary in most production use cases. However passing System properties from
// Intellij can cause issues. The ideal place to set this system property is in your build.sbt file.
private[validation] object SetProperty {
  @compileTimeOnly(
    "enable macro paradise (2.12) or -Ymacro-annotations (2.13) to expand macro annotations"
  )
  class setProperty extends StaticAnnotation {
    def macroTransform(annottees: Any*): Any = macro setPropertyImpl
  }

  def setSystemProperty(): String =
    System.setProperty(
      "override.type.provider",
      "com.spotify.scio.bigquery.validation.SampleOverrideTypeProvider"
    )

  def setPropertyImpl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    setSystemProperty()
    annottees.head
  }
} 
Example 104
Source File: Debug.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.generic.internal

object Debug {
  import scala.reflect.macros.blackbox

  private val macroDebugEnabled = System.getenv("TAPIR_LOG_GENERATED_CODE") == "true"

  def logGeneratedCode(c: blackbox.Context)(typeName: String, tree: c.universe.Tree): Unit = {
    import c.universe._
    if (macroDebugEnabled) {
      println(s"""$typeName macro output start:""")
      println(showCode(tree))
      println(s"""$typeName macro output end.""")
    }
  }
} 
Example 105
Source File: CaseClassUtil.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.generic.internal

import scala.reflect.macros.blackbox

private[generic] class CaseClassUtil[C <: blackbox.Context, T: C#WeakTypeTag](val c: C) {
  import c.universe._

  val t: Type = weakTypeOf[T]
  if (!t.typeSymbol.isClass || !t.typeSymbol.asClass.isCaseClass) {
    c.error(c.enclosingPosition, s"Multipart codec can only be generated for a case class, but got: $t.")
  }

  lazy val fields: List[Symbol] = t.decls
    .collectFirst {
      case m: MethodSymbol if m.isPrimaryConstructor => m
    }
    .get
    .paramLists
    .head

  private lazy val companion: Ident = Ident(TermName(t.typeSymbol.name.decodedName.toString))

  lazy val instanceFromValues: Tree = if (fields.size == 1) {
    q"$companion.apply(values.head.asInstanceOf[${fields.head.typeSignature}])"
  } else {
    q"$companion.tupled.asInstanceOf[Any => $t].apply(sttp.tapir.internal.SeqToParams(values))"
  }

  lazy val schema: Tree = c.typecheck(q"implicitly[sttp.tapir.Schema[$t]]")
} 
Example 106
Source File: FormCodecDerivation.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.generic.internal

import sttp.tapir.generic.Configuration
import sttp.tapir.{Codec, CodecFormat}

import scala.reflect.macros.blackbox

trait FormCodecDerivation {
  implicit def formCaseClassCodec[T <: Product with Serializable](implicit
      conf: Configuration
  ): Codec[String, T, CodecFormat.XWwwFormUrlencoded] =
    macro FormCodecMacros.generateForCaseClass[T]
}

object FormCodecMacros {
  // http://blog.echo.sh/2013/11/04/exploring-scala-macros-map-to-case-class-conversion.html
  def generateForCaseClass[T: c.WeakTypeTag](
      c: blackbox.Context
  )(conf: c.Expr[Configuration]): c.Expr[Codec[String, T, CodecFormat.XWwwFormUrlencoded]] = {
    import c.universe._

    val t = weakTypeOf[T]
    val util = new CaseClassUtil[c.type, T](c)
    val fields = util.fields

    val fieldsWithCodecs = fields.map { field =>
      (field, c.typecheck(q"implicitly[sttp.tapir.Codec[List[String], ${field.typeSignature}, sttp.tapir.CodecFormat.TextPlain]]"))
    }

    val encodeParams: Iterable[Tree] = fieldsWithCodecs.map {
      case (field, codec) =>
        val fieldName = field.name.asInstanceOf[TermName]
        val fieldNameAsString = fieldName.decodedName.toString
        q"""val transformedName = $conf.toLowLevelName($fieldNameAsString)
            $codec.encode(o.$fieldName).map(v => (transformedName, v))"""
    }

    val decodeParams = fieldsWithCodecs.map {
      case (field, codec) =>
        val fieldName = field.name.decodedName.toString
        q"""val transformedName = $conf.toLowLevelName($fieldName)
            $codec.decode(paramsMap.get(transformedName).toList.flatten)"""
    }

    val codecTree = q"""
      {
        def decode(params: Seq[(String, String)]): sttp.tapir.DecodeResult[$t] = {
          val paramsMap: Map[String, Seq[String]] = params.groupBy(_._1).mapValues(_.map(_._2)).toMap
          val decodeResults = List(..$decodeParams)
          sttp.tapir.DecodeResult.sequence(decodeResults).map { values =>
            ${util.instanceFromValues}
          }
        }
        def encode(o: $t): Seq[(String, String)] = List(..$encodeParams).flatten

        sttp.tapir.Codec.formSeqCodecUtf8
          .mapDecode(decode _)(encode _)
          .schema(${util.schema})
          .validate(implicitly[sttp.tapir.Validator[$t]])
      }
     """
    Debug.logGeneratedCode(c)(t.typeSymbol.fullName, codecTree)
    c.Expr[Codec[String, T, CodecFormat.XWwwFormUrlencoded]](codecTree)
  }
} 
Example 107
Source File: OneOfMacro.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.generic.internal

import sttp.tapir.Schema

import scala.annotation.tailrec
import scala.reflect.macros.blackbox

object OneOfMacro {
  // http://onoffswitch.net/extracting-scala-method-names-objects-macros/

  def oneOfMacro[E: c.WeakTypeTag, V: c.WeakTypeTag](
      c: blackbox.Context
  )(extractor: c.Expr[E => V], asString: c.Expr[V => String])(mapping: c.Expr[(V, Schema[_])]*): c.Expr[Schema[E]] = {
    import c.universe._

    @tailrec
    def resolveFunctionName(f: Function): String = {
      f.body match {
        // the function name
        case t: Select => t.name.decodedName.toString

        case t: Function =>
          resolveFunctionName(t)

        // an application of a function and extracting the name
        case t: Apply if t.fun.isInstanceOf[Select @unchecked] =>
          t.fun.asInstanceOf[Select].name.decodedName.toString

        // curried lambda
        case t: Block if t.expr.isInstanceOf[Function @unchecked] =>
          val func = t.expr.asInstanceOf[Function]

          resolveFunctionName(func)

        case _ =>
          throw new RuntimeException("Unable to resolve function name for expression: " + f.body)
      }
    }
    val weakTypeE = weakTypeOf[E]

    def extractTypeArguments(weakType: c.Type): List[String] = {
      def allTypeArguments(tn: c.Type): Seq[c.Type] = tn.typeArgs.flatMap(tn2 => tn2 +: allTypeArguments(tn2))
      allTypeArguments(weakType).map(_.typeSymbol.name.decodedName.toString).toList
    }

    val name = resolveFunctionName(extractor.tree.asInstanceOf[Function])
    val schemaForE =
      q"""{
            import sttp.tapir.Schema._
            import sttp.tapir.SchemaType._
            val rawMapping = scala.collection.immutable.Map(..$mapping)
            val discriminator = Discriminator($name, rawMapping.map{case (k, sf)=> $asString.apply(k) -> SRef(sf.schemaType.asInstanceOf[SObject].info)})
            Schema(SCoproduct(SObjectInfo(${weakTypeE.typeSymbol.fullName},${extractTypeArguments(weakTypeE)}), rawMapping.values.toList, Some(discriminator)))
          }"""

    Debug.logGeneratedCode(c)(weakTypeE.typeSymbol.fullName, schemaForE)
    c.Expr[Schema[E]](schemaForE)
  }
} 
Example 108
Source File: SchemaMapMacro.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.generic.internal

import sttp.tapir.Schema

import scala.reflect.macros.blackbox

object SchemaMapMacro {
  
  def schemaForMap[M: c.WeakTypeTag, V: c.WeakTypeTag](
      c: blackbox.Context
  )(schemaForV: c.Expr[Schema[V]]): c.Expr[Schema[Map[String, V]]] = {
    import c.universe._

    def extractTypeArguments(weakType: c.Type): List[String] = {
      def allTypeArguments(tn: c.Type): Seq[c.Type] = tn.typeArgs.flatMap(tn2 => tn2 +: allTypeArguments(tn2))
      allTypeArguments(weakType).map(_.typeSymbol.name.decodedName.toString).toList
    }

    val weakTypeV = weakTypeOf[V]
    val genericTypeParametersM = List(weakTypeV.typeSymbol.name.decodedName.toString) ++ extractTypeArguments(weakTypeV)
    val schemaForMap =
      q"""sttp.tapir.Schema(sttp.tapir.SchemaType.SOpenProduct(sttp.tapir.SchemaType.SObjectInfo("Map", ${genericTypeParametersM}), ${schemaForV}))"""
    Debug.logGeneratedCode(c)(weakTypeV.typeSymbol.fullName, schemaForMap)
    c.Expr[Schema[Map[String, V]]](schemaForMap)
  }
} 
Example 109
Source File: ValidatorEnumMacro.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.generic.internal

import sttp.tapir.Validator

import scala.reflect.macros.blackbox

// based on: https://stackoverflow.com/questions/13671734/iteration-over-a-sealed-trait-in-scala
trait ValidatorEnumMacro {
  def validatorForEnum[E: c.WeakTypeTag](c: blackbox.Context): c.Expr[Validator.Enum[E]] = {
    import c.universe._

    val t = weakTypeOf[E]
    val symbol = t.typeSymbol.asClass
    if (!symbol.isClass || !symbol.isSealed) {
      c.abort(c.enclosingPosition, "Can only enumerate values of a sealed trait or class.")
    } else {
      val subclasses = symbol.knownDirectSubclasses.toList.sortBy(_.name.encodedName.toString)
      if (!subclasses.forall(_.isModuleClass)) {
        c.abort(c.enclosingPosition, "All children must be objects.")
      } else {
        val instances = subclasses.map(x => Ident(x.asInstanceOf[scala.reflect.internal.Symbols#Symbol].sourceModule.asInstanceOf[Symbol]))
        val validatorEnum = q"sttp.tapir.Validator.enum($instances)"
        Debug.logGeneratedCode(c)(t.typeSymbol.fullName, validatorEnum)
        c.Expr[Validator.Enum[E]](validatorEnum)
      }
    }
  }
} 
Example 110
Source File: ModifySchemaMacro.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.internal

import sttp.tapir.Schema

import scala.annotation.tailrec
import scala.reflect.macros.blackbox

object ModifySchemaMacro {
  private val ShapeInfo = "Path must have shape: _.field1.field2.each.field3.(...)"

  def modifyMacro[T: c.WeakTypeTag, U: c.WeakTypeTag](
      c: blackbox.Context
  )(path: c.Expr[T => U])(modification: c.Expr[Schema[U] => Schema[U]]): c.Tree =
    applyModification[T, U](c)(extractPathFromFunctionCall(c)(path), modification)

  def setDescriptionMacro[T: c.WeakTypeTag, U: c.WeakTypeTag](
      c: blackbox.Context
  )(path: c.Expr[T => U], description: c.Expr[String]): c.Tree =
    addDescription[T, U](c)(extractPathFromFunctionCall(c)(path), description)

  private def addDescription[T: c.WeakTypeTag, U: c.WeakTypeTag](c: blackbox.Context)(
      path: c.Expr[List[String]],
      description: c.Expr[String]
  ): c.Tree = {
    import c.universe._
    q"""{
      ${c.prefix}.modifyUnsafe($path:_*)((v: sttp.tapir.Schema[${c.weakTypeOf[T]}]) => v.description($description))
     }"""
  }

  private def applyModification[T: c.WeakTypeTag, U: c.WeakTypeTag](c: blackbox.Context)(
      path: c.Expr[List[String]],
      modification: c.Expr[Schema[U] => Schema[U]]
  ): c.Tree = {
    import c.universe._
    q"""{
      ${c.prefix}.modifyUnsafe($path:_*)($modification)
     }"""
  }

  
    @tailrec
    def collectPathElements(tree: c.Tree, acc: List[PathElement]): List[PathElement] = {
      def typeSupported(quicklensType: c.Tree) =
        Seq("ModifyEach", "ModifyEither", "ModifyEachMap")
          .exists(quicklensType.toString.endsWith)

      tree match {
        case q"$parent.$child " =>
          collectPathElements(parent, TermPathElement(child) :: acc)
        case q"$tpname[..$_]($t)($f) " if typeSupported(tpname) =>
          val newAcc = acc match {
            // replace the term controlled by quicklens
            case TermPathElement(term, xargs @ _*) :: rest => FunctorPathElement(f, term, xargs: _*) :: rest
            case pathEl :: _ =>
              c.abort(c.enclosingPosition, s"Invalid use of path element $pathEl. $ShapeInfo, got: ${path.tree}")
            case Nil =>
              c.abort(c.enclosingPosition, s"Invalid use of path element(Nil). $ShapeInfo, got: ${path.tree}")
          }
          collectPathElements(t, newAcc)
        case _: Ident => acc
        case _        => c.abort(c.enclosingPosition, s"Unsupported path element. $ShapeInfo, got: $tree")
      }
    }

    val pathEls = path.tree match {
      case q"($arg) => $pathBody " => collectPathElements(pathBody, Nil)
      case _                       => c.abort(c.enclosingPosition, s"$ShapeInfo, got: ${path.tree}")
    }

    def isOptionalFunctor(tree: c.Tree): Boolean = {
      tree match {
        case TypeApply(Select(_, TermName("optionModifyFunctor")), _) => true
        case _                                                        => false
      }
    }

    c.Expr[List[String]](q"${pathEls.collect {
      case TermPathElement(c) => c.decodedName.toString
      case FunctorPathElement(functor, method, _ @_*) if !isOptionalFunctor(functor) =>
        method.decodedName.toString
    }}")
  }

  private[internal] def ignoredFromPath[T, U](path: T => U): List[String] = macro extractPathFromFunctionCall[T, U]
} 
Example 111
Source File: StatusMappingMacro.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.internal

import sttp.model.StatusCode
import sttp.tapir.EndpointOutput
import sttp.tapir.EndpointOutput.StatusMapping

import scala.reflect.ClassTag
import scala.reflect.macros.blackbox

object StatusMappingMacro {
  def classMatcherIfErasedSameAsType[O: c.WeakTypeTag](c: blackbox.Context)(
      statusCode: c.Expr[StatusCode],
      output: c.Expr[EndpointOutput[O]]
  )(ct: c.Expr[ClassTag[O]]): c.Expr[StatusMapping[O]] = {
    import c.universe._

    val t = implicitly[c.WeakTypeTag[O]].tpe.dealias

    if (!(t =:= t.erasure) && !(t =:= typeOf[Unit])) {
      c.error(
        c.enclosingPosition,
        s"Constructing statusMapping of type $t is not allowed because of type erasure. Using a runtime-class-based check it isn't possible to verify " +
          s"that the input matches the desired class. Please use statusMappingClassMatcher, statusMappingValueMatcher or statusMappingFromMatchType instead"
      )
    }

    c.Expr[StatusMapping[O]](q"sttp.tapir.statusMappingClassMatcher($statusCode, $output, $ct.runtimeClass)")
  }
} 
Example 112
Source File: SealedValues.scala    From flamy   with Apache License 2.0 5 votes vote down vote up
package com.flaminem.flamy.utils.macros

import scala.collection.immutable.Seq
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

//scalastyle:off

object SealedValues {

  def values[A]: Seq[A] = macro values_impl[A]

  def values_impl[A: c.WeakTypeTag](c: blackbox.Context) : c.Expr[Seq[A]] = {
    import c.universe._

    val symbol = weakTypeOf[A].typeSymbol

    if (!symbol.isClass)  { c.abort(
      c.enclosingPosition,
      "Can only enumerate values of a sealed trait or class."
    )}
    else if (!symbol.asClass.isSealed) {
      c.abort(
        c.enclosingPosition,
        "Can only enumerate values of a sealed trait or class."
      )
    } else {
      val siblingSubclasses: List[Symbol] = scala.util.Try {
        val enclosingModule = c.macroApplication
        enclosingModule.filter { x =>
          scala.util.Try(x.symbol.asModule.moduleClass.asClass.baseClasses.contains(symbol))
            .getOrElse(false)
        }.map(_.symbol)
      } getOrElse {
        Nil
      }

      val children = symbol.asClass.knownDirectSubclasses.toList.sortBy{_.pos.start} ::: siblingSubclasses
      if (!children.forall(x => x.isModuleClass || x.isModule)) {
        c.abort(
          c.enclosingPosition,
          "All children must be objects."
        )
      } else c.Expr[Seq[A]] {
        def sourceModuleRef(sym: Symbol) = Ident(
          if (sym.isModule) {
            sym
          }
          else {
            sym.asInstanceOf[
              scala.reflect.internal.Symbols#Symbol
              ].sourceModule.asInstanceOf[Symbol]
          }
        )

        Apply(
          Select(
            reify(Seq).tree,
            TermName("apply")
          ),
          children.map(sourceModuleRef(_))
        )
      }
    }
  }
}

//scalastyle:on 
Example 113
Source File: Macros.scala    From jsonapi-scala   with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
package com.qvantel.jsonapi

import scala.annotation.compileTimeOnly
import com.qvantel.jsonapi.macrosupport.{JsonApiReaders, JsonApiWriters}

import scala.reflect.macros.blackbox


@compileTimeOnly("Macros can only be used at compile-time")
final class Macros(val c: blackbox.Context) extends JsonApiWriters with JsonApiReaders {
  import c.universe._

  private[this] def createFormat(t: c.Type): c.Tree = {
    val rootParamName     = TermName(c.freshName("root"))
    val includedParamName = TermName(c.freshName("included"))
    val includePaths      = TermName(c.freshName("includePaths"))
    val includePath       = TermName(c.freshName("includePath"))
    q"""new _root_.com.qvantel.jsonapi.JsonApiFormat[$t] with _root_.spray.json.RootJsonFormat[$t] {
          import _root_.com.qvantel.jsonapi.PathJsonFormat
          override final def write($rootParamName: $t, sparseFields: Map[String, List[String]]): _root_.spray.json.JsValue = ${primaryDataWriter(
      t,
      rootParamName)}
          override final def included($rootParamName: $t, sparseFields: Map[String, List[String]]): _root_.scala.collection.immutable.Set[_root_.spray.json.JsObject] = ${includedWriter(
      t,
      rootParamName)}
          override final def read(
            $rootParamName: _root_.spray.json.JsValue,
            $includedParamName: _root_.scala.collection.immutable.Map[(String, String), _root_.spray.json.JsObject],
            $includePaths: _root_.scala.collection.immutable.Set[String],
            $includePath: String
          ): $t = ${reader(t, rootParamName, includedParamName, includePaths, includePath)}
        }"""
  }

  def createIncludes[A: c.WeakTypeTag]: c.Tree = {
    val t = weakTypeOf[A]

    val includeParamName    = TermName(c.freshName())
    val includeMapParamName = TermName(c.freshName())
    q"""
      new _root_.com.qvantel.jsonapi.Includes[$t] {
        private[this] final lazy val $includeMapParamName: Map[String, _root_.com.qvantel.jsonapi.Includes[_]] = ${includesMap(
      t)}
        override def includeAllowed($includeParamName: String): Boolean = ${includeAllowed(t,
                                                                                           includeParamName,
                                                                                           includeMapParamName)}
      }
      """
  }

  def jsonApiWriterWithNoNameManglingImpl[A: c.WeakTypeTag]: c.Tree = createWriter(weakTypeOf[A])
  def jsonApiFormatWithNoNameManglingImpl[A: c.WeakTypeTag]: c.Tree = createFormat(weakTypeOf[A])
} 
Example 114
Source File: CompileTimeState.scala    From phobos   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.phobos.derivation



import scala.collection.mutable
import scala.reflect.macros.blackbox

private[derivation] object CompileTimeState {

  sealed abstract class TypePath(path: String) { override def toString = path }
  final case class CoproductType(typeName: String) extends TypePath(s"coproduct type $typeName")

  final case class ProductType(paramName: String, typeName: String)
    extends TypePath(s"parameter '$paramName' of product type $typeName")

  final case class ChainedImplicit(typeClassName: String, typeName: String)
    extends TypePath(s"chained implicit $typeClassName for type $typeName")

  final class Stack[C <: blackbox.Context with Singleton] {
    private var frames = List.empty[Frame]
    private val cache = mutable.Map.empty[C#Type, C#Tree]

    def isEmpty: Boolean = frames.isEmpty
    def nonEmpty: Boolean = frames.nonEmpty
    def top: Option[Frame] = frames.headOption
    def pop(): Unit = frames = frames drop 1
    def push(frame: Frame): Unit = frames ::= frame

    def clear(): Unit = {
      frames = Nil
      cache.clear()
    }

    def find(searchType: C#Type): Option[C#TermName] = frames.collectFirst {
      case Frame(_, tpe, term) if tpe =:= searchType => term
    }

    def recurse[T <: C#Tree](frame: Frame, searchType: C#Type)(fn: => C#Tree): C#Tree = {
      push(frame)
      val result = cache.getOrElseUpdate(searchType, fn)
      pop()
      result
    }

    def trace: List[TypePath] =
      frames.drop(1).zip(frames).collect {
        case (Frame(path, tp1, _), Frame(_, tp2, _))
          if !(tp1 =:= tp2) => path
      }

    override def toString: String =
      frames.mkString(" a stack:\n", "\n", "\n")

    final case class Frame(path: TypePath, searchType: C#Type, term: C#TermName)
  }

  object Stack {
    // Cheating to satisfy Singleton bound (which improves type inference).
    private val dummyContext: blackbox.Context = null
    private val global = new Stack[dummyContext.type]
    private val workSet = mutable.Set.empty[blackbox.Context#Symbol]

    def withContext(c: blackbox.Context)(fn: Stack[c.type] => c.Tree): c.Tree = {
      workSet += c.macroApplication.symbol
      val depth = c.enclosingMacros.count(m => workSet(m.macroApplication.symbol))
      try fn(global.asInstanceOf[Stack[c.type]])
      finally if (depth <= 1) {
        global.clear()
        workSet.clear()
      }
    }
  }
} 
Example 115
Source File: ExportMacro.scala    From phobos   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.phobos.derivation.auto

import ru.tinkoff.phobos.encoding.ElementEncoder
import ru.tinkoff.phobos.decoding.ElementDecoder

import scala.reflect.macros.blackbox

class ExportMacro(val c: blackbox.Context) {
  import c.universe._

  def exportEncoder[A: WeakTypeTag]: Expr[Exported[ElementEncoder[A]]] = {
    c.Expr[Exported[ElementEncoder[A]]](q"""new _root_.ru.tinkoff.phobos.derivation.auto.Exported(
       _root_.ru.tinkoff.phobos.derivation.semiauto.deriveElementEncoder[${weakTypeOf[A]}]
     )""")
  }

  def exportDecoder[A: WeakTypeTag]: Expr[Exported[ElementDecoder[A]]] = {
    c.Expr[Exported[ElementDecoder[A]]](q"""new _root_.ru.tinkoff.phobos.derivation.auto.Exported(
       _root_.ru.tinkoff.phobos.derivation.semiauto.deriveElementDecoder[${weakTypeOf[A]}]
     )""")
  }
} 
Example 116
Source File: ElementCodec.scala    From phobos   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.phobos.annotations

import ru.tinkoff.phobos.configured.ElementCodecConfig
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.reflect.macros.blackbox

@compileTimeOnly("enable macro paradise to expand macro annotations")
final class ElementCodec(config: ElementCodecConfig = ElementCodecConfig.default) extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro ElementCodecImpl.impl
}

private final class ElementCodecImpl(ctx: blackbox.Context) extends CodecAnnotation(ctx) {
  import c.universe._

  def instances(typ: Tree): Seq[Tree] = {
    val pkg = q"ru.tinkoff.phobos"

    val config = c.prefix.tree match {
      case q"new ElementCodec"          => defaultConfig.tree
      case q"new ElementCodec($config)" => config
    }

    Seq(
      q"""
          implicit val ${TermName(c.freshName("elementEncoder"))}: $pkg.encoding.ElementEncoder[$typ] =
            $pkg.derivation.semiauto.deriveElementEncoderConfigured[$typ]($config)
       """,
      q"""
          implicit val ${TermName(c.freshName("elementDecoder"))}: $pkg.decoding.ElementDecoder[$typ] =
            $pkg.derivation.semiauto.deriveElementDecoderConfigured[$typ]($config)
       """
    )
  }

} 
Example 117
Source File: CodecAnnotation.scala    From phobos   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.phobos.annotations

import ru.tinkoff.phobos.configured.ElementCodecConfig
import scala.reflect.macros.blackbox

private[phobos] abstract class CodecAnnotation(val c: blackbox.Context) {

  import c.universe._

  def instances(typ: Tree): Seq[Tree]

  def impl(annottees: c.Tree*): c.Tree = {
    annottees match {
      case Seq(q"$mods object $obj extends { ..$earlydefns } with ..$parents { $self => ..$body }") =>
        q"""
            $mods object $obj extends {..$earlydefns} with ..$parents { $self =>
              ..${instances(tq"$obj.type") ++: body}
            }
          """

      case Seq(cls: ClassDef) =>
        q"""
            $cls
            object ${cls.name.toTermName} {
              ..${instances(tq"${cls.name}")}
            }
          """

      case Seq(cls: ClassDef, q"$mods object $obj extends { ..$earlydefns } with ..$parents { $self => ..$body }") =>
        q"""
            $cls
            $mods object $obj extends {..$earlydefns} with ..$parents { $self =>
              ..${instances(tq"${cls.name}") ++: body}
            }
          """

      case _ =>
        c.abort(c.enclosingPosition, "Namespace must be represented with class or object")
    }
  }

  protected val defaultConfig = reify(ElementCodecConfig.default)
} 
Example 118
Source File: XmlCodecNs.scala    From phobos   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.phobos.annotations

import ru.tinkoff.phobos.Namespace
import ru.tinkoff.phobos.configured.ElementCodecConfig
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.reflect.macros.blackbox

@compileTimeOnly("enable macro paradise to expand macro annotations")
class XmlCodecNs[T: Namespace](localName: String, namespace: T, config: ElementCodecConfig = ElementCodecConfig.default)
    extends StaticAnnotation {
  def namespaceUri: String = Namespace[T].getNamespace
  def macroTransform(annottees: Any*): Any = macro XmlCodecNsImpl.impl
}

private final class XmlCodecNsImpl(ctx: blackbox.Context) extends CodecAnnotation(ctx) {
  import c.universe._

  def instances(typ: Tree): Seq[Tree] = {
    val pkg = q"ru.tinkoff.phobos"
    val (nsInstance, localName, config) = c.prefix.tree match {
      case q"new XmlCodecNs($localName, $nsInstance)"              => (nsInstance, localName, defaultConfig.tree)
      case q"new XmlCodecNs($localName, $nsInstance, $config)"     => (nsInstance, localName, config)
      case q"new XmlCodecNs[$_]($localName, $nsInstance, $config)" => (nsInstance, localName, config)
    }

    Seq(
      q"""
          implicit val ${TermName(c.freshName("elementEncoder"))}: $pkg.encoding.ElementEncoder[$typ] =
            $pkg.derivation.semiauto.deriveElementEncoderConfigured[$typ]($config)
       """,
      q"""
          implicit val ${TermName(c.freshName("elementDecoder"))}: $pkg.decoding.ElementDecoder[$typ] =
            $pkg.derivation.semiauto.deriveElementDecoderConfigured[$typ]($config)
       """,
      q"""
          implicit val ${TermName(c.freshName("xmlEncoder"))}: $pkg.encoding.XmlEncoder[$typ] =
            $pkg.encoding.XmlEncoder.fromElementEncoderNs($localName, $nsInstance)
       """,
      q"""
          implicit val ${TermName(c.freshName("xmlDecoder"))}: $pkg.decoding.XmlDecoder[$typ] =
            $pkg.decoding.XmlDecoder.fromElementDecoderNs($localName, $nsInstance)
       """
    )
  }

} 
Example 119
Source File: XmlCodec.scala    From phobos   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.phobos.annotations

import ru.tinkoff.phobos.configured.ElementCodecConfig
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.reflect.macros.blackbox

@compileTimeOnly("enable macro paradise to expand macro annotations")
class XmlCodec(localName: String, config: ElementCodecConfig = ElementCodecConfig.default) extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro XmlCodecImpl.impl
}

private final class XmlCodecImpl(ctx: blackbox.Context) extends CodecAnnotation(ctx) {
  import c.universe._

  def instances(typ: Tree): Seq[Tree] = {
    val pkg = q"ru.tinkoff.phobos"
    val (localName, config) = c.prefix.tree match {
      case q"new XmlCodec($localName)"          => (localName, defaultConfig.tree)
      case q"new XmlCodec($localName, $config)" => (localName, config)
    }

    Seq(
      q"""
          implicit val ${TermName(c.freshName("elementEncoder"))}: $pkg.encoding.ElementEncoder[$typ] =
            $pkg.derivation.semiauto.deriveElementEncoderConfigured[$typ]($config)
       """,
      q"""
          implicit val ${TermName(c.freshName("elementDecoder"))}: $pkg.decoding.ElementDecoder[$typ] =
            $pkg.derivation.semiauto.deriveElementDecoderConfigured[$typ]($config)
       """,
      q"""
          implicit val ${TermName(c.freshName("xmlEncoder"))}: $pkg.encoding.XmlEncoder[$typ] =
            $pkg.encoding.XmlEncoder.fromElementEncoder[$typ]($localName)
       """,
      q"""
          implicit val ${TermName(c.freshName("xmlDecoder"))}: $pkg.decoding.XmlDecoder[$typ] =
            $pkg.decoding.XmlDecoder.fromElementDecoder[$typ]($localName)
       """
    )
  }

} 
Example 120
Source File: XmlnsDef.scala    From phobos   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.phobos.annotations

import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.reflect.macros.blackbox

@compileTimeOnly("enable macro paradise to expand macro annotations")
final class XmlnsDef(uri: String) extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro XmlnsDefImpl.impl
}

private final class XmlnsDefImpl(ctx: blackbox.Context) extends CodecAnnotation(ctx) {
  import c.universe._

  def instances(typ: Tree): Seq[Tree] = {
    val pkg = q"ru.tinkoff.phobos"
    val instanceName = TermName(c.freshName("namespaceInstance"))
    val uri = c.prefix.tree match {
      case q"new XmlnsDef($uri)" => uri
    }
    Seq(q"implicit val $instanceName: $pkg.Namespace[$typ] = $pkg.Namespace.mkInstance[$typ]($uri)")
  }

} 
Example 121
Source File: Model.scala    From chimney   with Apache License 2.0 5 votes vote down vote up
package io.scalaland.chimney.internal.macros

import io.scalaland.chimney.internal.TransformerConfiguration

import scala.reflect.macros.blackbox

trait Model extends TransformerConfiguration {

  val c: blackbox.Context

  import c.universe._

  case class Target(name: String, tpe: Type)
  object Target {
    def fromJavaBeanSetter(ms: MethodSymbol, site: Type): Target =
      Target(ms.canonicalName, ms.beanSetterParamTypeIn(site))

    def fromField(ms: MethodSymbol, site: Type): Target =
      Target(ms.canonicalName, ms.resultTypeIn(site))
  }

  case class TransformerBodyTree(tree: Tree, isWrapped: Boolean)

  sealed trait AccessorResolution extends Product with Serializable {
    def isResolved: Boolean
  }
  object AccessorResolution {
    case object NotFound extends AccessorResolution {
      override def isResolved: Boolean = false
    }
    case class Resolved(symbol: MethodSymbol, wasRenamed: Boolean) extends AccessorResolution {
      override def isResolved: Boolean = true
    }
    case object DefAvailable extends AccessorResolution {
      override def isResolved: Boolean = false
    }
  }
} 
Example 122
Source File: ChimneyBlackboxMacros.scala    From chimney   with Apache License 2.0 5 votes vote down vote up
package io.scalaland.chimney.internal.macros

import io.scalaland.chimney
import io.scalaland.chimney.internal.utils.{DerivationGuards, EitherUtils, MacroUtils}
import io.scalaland.chimney.{Patcher, TransformerF, TransformerFSupport}

import scala.reflect.macros.blackbox

class ChimneyBlackboxMacros(val c: blackbox.Context)
    extends PatcherMacros
    with TransformerMacros
    with DerivationGuards
    with MacroUtils
    with EitherUtils {

  import c.universe._

  def buildTransformerImpl[From: WeakTypeTag, To: WeakTypeTag, C: WeakTypeTag]
      : c.Expr[chimney.Transformer[From, To]] = {
    c.Expr[chimney.Transformer[From, To]](buildDefinedTransformer[From, To, C]())
  }

  def buildTransformerFImpl[F[+_], From: WeakTypeTag, To: WeakTypeTag, C: WeakTypeTag](
      tfs: c.Expr[TransformerFSupport[F]]
  ): c.Expr[TransformerF[F, From, To]] = {
    c.Expr[TransformerF[F, From, To]](buildDefinedTransformer[From, To, C](tfs.tree))
  }

  def transformImpl[From: WeakTypeTag, To: WeakTypeTag, C: WeakTypeTag]: c.Expr[To] = {
    c.Expr[To](expandTransform[From, To, C]())
  }

  def transformFImpl[F[+_], From: WeakTypeTag, To: WeakTypeTag, C: WeakTypeTag](
      tfs: c.Expr[TransformerFSupport[F]]
  ): c.Expr[F[To]] = {
    c.Expr[F[To]](expandTransform[From, To, C](tfs.tree))
  }

  def deriveTransformerImpl[From: WeakTypeTag, To: WeakTypeTag]: c.Expr[chimney.Transformer[From, To]] = {
    c.Expr[chimney.Transformer[From, To]](
      genTransformer[From, To](
        TransformerConfig(
          definitionScope = Some((weakTypeOf[From], weakTypeOf[To]))
        )
      )
    )
  }

  def deriveTransformerFImpl[F[+_], From: WeakTypeTag, To: WeakTypeTag](
      tfs: c.Expr[TransformerFSupport[F]]
  )(
      implicit F: WeakTypeTag[F[_]]
  ): c.Expr[TransformerF[F, From, To]] = {
    c.Expr[TransformerF[F, From, To]](
      genTransformer[From, To](
        TransformerConfig(
          definitionScope = Some((weakTypeOf[From], weakTypeOf[To])),
          wrapperType = Some(F.tpe),
          wrapperSupportInstance = tfs.tree
        )
      )
    )
  }

  def patchImpl[T: WeakTypeTag, Patch: WeakTypeTag, C: WeakTypeTag]: c.Expr[T] = {
    c.Expr[T](expandPatch[T, Patch, C])
  }

  def derivePatcherImpl[T: WeakTypeTag, Patch: WeakTypeTag]: c.Expr[Patcher[T, Patch]] = {
    genPatcher[T, Patch](PatcherConfig())
  }
} 
Example 123
Source File: PatcherCfg.scala    From chimney   with Apache License 2.0 5 votes vote down vote up
package io.scalaland.chimney.internal

import scala.reflect.macros.blackbox

sealed abstract class PatcherCfg

object PatcherCfg {
  final class Empty extends PatcherCfg
  final class IgnoreRedundantPatcherFields[C <: PatcherCfg] extends PatcherCfg
  final class IgnoreNoneInPatch[C <: PatcherCfg] extends PatcherCfg
}

trait PatcherConfiguration {

  val c: blackbox.Context

  import c.universe._

  case class PatcherConfig(
      ignoreNoneInPatch: Boolean = false,
      ignoreRedundantPatcherFields: Boolean = false
  )

  def capturePatcherConfig(cfgTpe: Type, config: PatcherConfig = PatcherConfig()): PatcherConfig = {

    import PatcherCfg._

    val emptyT = typeOf[Empty]
    val ignoreRedundantPatcherFields = typeOf[IgnoreRedundantPatcherFields[_]].typeConstructor
    val ignoreNoneInPatch = typeOf[IgnoreNoneInPatch[_]].typeConstructor

    if (cfgTpe =:= emptyT) {
      config
    } else if (cfgTpe.typeConstructor =:= ignoreRedundantPatcherFields) {
      capturePatcherConfig(cfgTpe.typeArgs.head, config.copy(ignoreRedundantPatcherFields = true))
    } else if (cfgTpe.typeConstructor =:= ignoreNoneInPatch) {
      capturePatcherConfig(cfgTpe.typeArgs.head, config.copy(ignoreNoneInPatch = true))
    } else {
      // $COVERAGE-OFF$
      c.abort(c.enclosingPosition, "Bad internal patcher config type shape!")
      // $COVERAGE-ON$
    }
  }
} 
Example 124
Source File: CompanionUtils.scala    From chimney   with Apache License 2.0 5 votes vote down vote up
package io.scalaland.chimney.internal.utils

import scala.reflect.macros.{blackbox, runtime}
import scala.tools.nsc.Global

trait CompanionUtils {

  val c: blackbox.Context

  // Copied from Magnolia: https://github.com/propensive/magnolia/blob/master/core/shared/src/main/scala/globalutil.scala

  // From Shapeless: https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/generic.scala#L698
  // Cut-n-pasted (with most original comments) and slightly adapted from
  // https://github.com/scalamacros/paradise/blob/c14c634923313dd03f4f483be3d7782a9b56de0e/plugin/src/main/scala/org/scalamacros/paradise/typechecker/Namers.scala#L568-L613
  def patchedCompanionRef(c: blackbox.Context)(tpe: c.Type): c.Tree = {
    // see https://github.com/scalamacros/paradise/issues/7
    // also see https://github.com/scalamacros/paradise/issues/64

    val global = c.universe.asInstanceOf[Global]
    val typer = c.asInstanceOf[runtime.Context].callsiteTyper.asInstanceOf[global.analyzer.Typer]
    val ctx = typer.context
    val globalType = tpe.asInstanceOf[global.Type]
    val original = globalType.typeSymbol
    val owner = original.owner
    val companion = original.companion.orElse {
      import global.{abort => aabort, _}
      implicit class PatchedContext(ctx: global.analyzer.Context) {
        trait PatchedLookupResult { def suchThat(criterion: Symbol => Boolean): Symbol }
        def patchedLookup(name: Name, expectedOwner: Symbol) = new PatchedLookupResult {
          override def suchThat(criterion: Symbol => Boolean): Symbol = {
            var res: Symbol = NoSymbol
            var ctx = PatchedContext.this.ctx
            while (res == NoSymbol && ctx.outer != ctx) {
              // NOTE: original implementation says `val s = ctx.scope lookup name`
              // but we can't use it, because Scope.lookup returns wrong results when the lookup is ambiguous
              // and that triggers https://github.com/scalamacros/paradise/issues/64
              val s = {
                val lookupResult = ctx.scope.lookupAll(name).filter(criterion).toList
                lookupResult match {
                  case Nil          => NoSymbol
                  case List(unique) => unique
                  case _ =>
                    aabort(s"unexpected multiple results for a companion symbol lookup for $original#{$original.id}")
                }
              }
              if (s != NoSymbol && s.owner == expectedOwner)
                res = s
              else
                ctx = ctx.outer
            }
            res
          }
        }
      }

      ctx.patchedLookup(original.name.companionName, owner) suchThat { sym =>
        (original.isTerm || sym.hasModuleFlag) && (sym isCoDefinedWith original)
      }
    }

    global.gen.mkAttributedRef(globalType.prefix, companion).asInstanceOf[c.Tree]
  }
}