Skip to content

Commit

Permalink
Add all unapply methods, and missing apply methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jchyb committed Jan 3, 2024
1 parent fe6ff94 commit 44d1d72
Show file tree
Hide file tree
Showing 9 changed files with 3,796 additions and 577 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,22 @@ package quasiquotes

import scala.compat.Platform.EOL
import scala.language.experimental.macros
// import scala.reflect.macros.whitebox.Context
import scala.quoted._
import scala.meta.internal.trees.{Reflection => AstReflection}

// NOTE: we don't have the signature as [O, I] to keep symmetry with Unlift
object Lift {
transparent inline def apply[I](outside: Any): I = ${ConversionMacros.liftApplyImpl[I]('outside)}
transparent inline def unapply[I](outside: Any): Option[I] = ${ConversionMacros.liftUnapplyImpl[I]('outside)}
transparent inline def apply[I](inline outside: Any): I = ${ConversionMacros.liftApplyImpl[I]('outside)}
transparent inline def unapply[I](inline outside: Any): Option[I] = ${ConversionMacros.liftUnapplyImpl[I]('outside)}
}

// NOTE: here we can't have the signature be [I, O], because we never know I
// in the case of Unlift.apply, we've just assembled the reified result and don't know its type yet
// in the case of Unlift.unapply, we only know the expected type of the unquote, not its actual type
// it would be nice if Scala supported partially provided type argument lists
object Unlift {
transparent inline def apply[O](inside: Any): O = ${ConversionMacros.unliftApplyImpl[O]('inside)}
transparent inline def unapply[O](inside: Any): Option[O] = ${ConversionMacros.unliftUnapplyImpl[O]('inside)}
transparent inline def apply[O](inline inside: Any): O = ${ConversionMacros.unliftApplyImpl[O]('inside)}
transparent inline def unapply[O](inline inside: Any): Option[O] = ${ConversionMacros.unliftUnapplyImpl[O]('inside)}
}

object ConversionMacros {
Expand Down Expand Up @@ -50,7 +49,7 @@ class ConversionMacros(using val topLevelQuotes: Quotes) {//extends AstReflectio
outside.asExprOf[I]
} else {
outsideTpe.asType match
case '[t] =>
case '[t] =>
val liftableMaybe = Expr.summon[Lift[t, I]]
liftableMaybe match
case Some(liftable) => '{$liftable.apply(${outsideExpr.asExprOf[t]})}
Expand All @@ -68,7 +67,6 @@ class ConversionMacros(using val topLevelQuotes: Quotes) {//extends AstReflectio
def unliftApply[O: Type](inside: Expr[Any]): Expr[O] = {
// NOTE: here we just disregard the expected outside type, because I can't find uses for it
// duality is a fun thing, but it looks like here it just led me into a dead-end
// q"$inside"
inside.asExprOf[O]
}

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
package scala.meta

private[meta] enum QuasiquoteType:
case Q, P, T
case Term // q""
case TermParam // param""
case Type // t""
case TypeParam // tparam""
case CaseOrPattern // p""
case Init // init""
case Self //self""
case Template // template""
case Mod // mod""
case Enumerator // enumerator""
case Importer // importer""
case Importee // importee""
case Source // source""

def parserClass() =
"scala.meta.quasiquotes.Api.XTensionQuasiquote" + toString

Large diffs are not rendered by default.

191 changes: 147 additions & 44 deletions quasiquotes3/shared/src/main/scala/scala/meta/quasiquotes/Api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,81 @@ package scala.meta
package quasiquotes

import scala.meta.internal.trees.quasiquote
import scala.meta.parsers.Parse
import scala.meta.internal.quasiquotes._
import scala.meta.parsers.Parse
import scala.meta._

type Qunapply
object Qunapply
type QuasiquoteUnapply

private[meta] trait Api {
// val a: Ctor
// @quasiquote[Ctor, Stat]('q)
// implicit class XtensionQuasiquoteTerm(ctx: StringContext)
// @quasiquote[Term.Param]('param)
// implicit class XtensionQuasiquoteTermParam(ctx: StringContext)
// @quasiquote[Type]('t)
// implicit class XtensionQuasiquoteType(ctx: StringContext)
// @quasiquote[Type.Param]('tparam)
// implicit class XtensionQuasiquoteTypeParam(ctx: StringContext)
// @quasiquote[Case, Pat]('p)
// implicit class XtensionQuasiquoteCaseOrPattern(ctx: StringContext)
// @quasiquote[Init]('init)
// implicit class XtensionQuasiquoteInit(ctx: StringContext)
// @quasiquote[Self]('self)
// implicit class XtensionQuasiquoteSelf(ctx: StringContext)
// @quasiquote[Template]('template)
// implicit class XtensionQuasiquoteTemplate(ctx: StringContext)
// @quasiquote[Mod]('mod)
// implicit class XtensionQuasiquoteMod(ctx: StringContext)
// @quasiquote[Enumerator]('enumerator)
// implicit class XtensionQuasiquoteEnumerator(ctx: StringContext)
// @quasiquote[Importer]('importer)
// implicit class XtensionQuasiquoteImporter(ctx: StringContext)
// @quasiquote[Importee]('importee)
// implicit class XtensionQuasiquoteImportee(ctx: StringContext)
// @quasiquote[Source]('source)
// implicit class XtensionQuasiquoteSource(ctx: StringContext)
extension (stringContext: scala.StringContext)
@annotation.compileTimeOnly(".q should not be called directly. Use q\"...\" string interpolation.")
def q: Qunapply = ???
extension (inline sc: Qunapply)
transparent inline def unapply(inline scrutinee: Any)(implicit dialect: scala.meta.Dialect): Option[Seq[Any]] =
${ ReificationMacros.unapplyQuasiquoteImpl('sc, 'scrutinee, 'dialect) }

// apply methods
extension (inline sc: StringContext) {
transparent inline def q(inline args: Any*)(implicit dialect: scala.meta.Dialect) = ${ ReificationMacros.quasiquoteImpl('sc, 'args, 'dialect) }
transparent inline def t(inline args: Any*)(implicit dialect: scala.meta.Dialect) = ${ ReificationMacros.typeImpl('sc, 'args, 'dialect) }
transparent inline def p(inline args: Any*)(implicit dialect: scala.meta.Dialect) = ${ ReificationMacros.caseOrPatternImpl('sc, 'args, 'dialect) }
transparent inline def q(inline args: Any*): Tree = ${ ReificationMacros.termImpl('sc, 'args) }
transparent inline def param(inline args: Any*): Term.Param = ${ ReificationMacros.termParamImpl('sc, 'args) }
transparent inline def t(inline args: Any*): Type = ${ ReificationMacros.typeImpl('sc, 'args) }
transparent inline def tparam(inline args: Any*): Type.Param = ${ ReificationMacros.typeParamImpl('sc, 'args) }
transparent inline def p(inline args: Any*): Tree = ${ ReificationMacros.caseOrPatternImpl('sc, 'args) }
transparent inline def init(inline args: Any*): Init = ${ ReificationMacros.initImpl('sc, 'args) }
transparent inline def self(inline args: Any*): Self = ${ ReificationMacros.selfImpl('sc, 'args) }
transparent inline def template(inline args: Any*): Template = ${ ReificationMacros.templateImpl('sc, 'args) }
transparent inline def mod(inline args: Any*): Mod = ${ ReificationMacros.modImpl('sc, 'args) }
transparent inline def enumerator(inline args: Any*): Enumerator = ${ ReificationMacros.enumeratorImpl('sc, 'args) }
transparent inline def importer(inline args: Any*): Importer = ${ ReificationMacros.importerImpl('sc, 'args) }
transparent inline def importee(inline args: Any*): Importee = ${ ReificationMacros.importeeImpl('sc, 'args) }
transparent inline def source(inline args: Any*): Source = ${ ReificationMacros.sourceImpl('sc, 'args) }
}

// unapply methods
extension (stringContext: scala.StringContext)
@annotation.compileTimeOnly(".q should not be called directly. Use q\"...\" string interpolation.")
def q: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".param should not be called directly. Use param\"...\" string interpolation.")
def param: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".t should not be called directly. Use t\"...\" string interpolation.")
def t: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".tparam should not be called directly. Use tparam\"...\" string interpolation.")
def tparam: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".p should not be called directly. Use p\"...\" string interpolation.")
def p: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".init should not be called directly. Use init\"...\" string interpolation.")
def init: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".self should not be called directly. Use self\"...\" string interpolation.")
def self: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".template should not be called directly. Use template\"...\" string interpolation.")
def template: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".mod should not be called directly. Use mod\"...\" string interpolation.")
def mod: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".enumerator should not be called directly. Use enumerator\"...\" string interpolation.")
def enumerator: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".importer should not be called directly. Use importer\"...\" string interpolation.")
def importer: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".importee should not be called directly. Use importee\"...\" string interpolation.")
def importee: QuasiquoteUnapply = ???
@annotation.compileTimeOnly(".source should not be called directly. Use source\"...\" string interpolation.")
def source: QuasiquoteUnapply = ???

extension (inline sc: QuasiquoteUnapply)
transparent inline def unapplySeq(scrutinee: Any): Option[Seq[Any]] =
${ ReificationMacros.unapplyImpl('sc, 'scrutinee) }


// parsers
object XTensionQuasiquoteTerm {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Ctor]];
val parse = implicitly[Parse[Ctor]]
parse(input, dialect)
}.orElse{
val parse = implicitly[Parse[Stat]];
val parse = implicitly[Parse[Stat]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
case x: scala.meta.parsers.Parsed.Error => throw x.details
}
}
object XTensionQuasiquoteTermParam {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Term.Param]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
Expand All @@ -63,7 +85,16 @@ private[meta] trait Api {
}
object XTensionQuasiquoteType {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Type]];
val parse = implicitly[Parse[Type]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
case x: scala.meta.parsers.Parsed.Error => throw x.details
}
}
object XTensionQuasiquoteTypeParam {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Type.Param]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
Expand All @@ -72,10 +103,82 @@ private[meta] trait Api {
}
object XTensionQuasiquoteCaseOrPattern {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Case]];
val parse = implicitly[Parse[Case]]
parse(input, dialect)
}.orElse{
val parse = implicitly[Parse[Pat]];
val parse = implicitly[Parse[Pat]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
case x: scala.meta.parsers.Parsed.Error => throw x.details
}
}
object XTensionQuasiquoteInit {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Init]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
case x: scala.meta.parsers.Parsed.Error => throw x.details
}
}
object XTensionQuasiquoteSelf {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Self]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
case x: scala.meta.parsers.Parsed.Error => throw x.details
}
}
object XTensionQuasiquoteTemplate {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Template]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
case x: scala.meta.parsers.Parsed.Error => throw x.details
}
}
object XTensionQuasiquoteMod {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Mod]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
case x: scala.meta.parsers.Parsed.Error => throw x.details
}
}
object XTensionQuasiquoteEnumerator {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Enumerator]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
case x: scala.meta.parsers.Parsed.Error => throw x.details
}
}
object XTensionQuasiquoteImporter {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Importer]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
case x: scala.meta.parsers.Parsed.Error => throw x.details
}
}
object XTensionQuasiquoteImportee {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Importee]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
case x: scala.meta.parsers.Parsed.Error => throw x.details
}
}
object XTensionQuasiquoteSource {
private[meta] def parse(input: scala.meta.inputs.Input, dialect: scala.meta.Dialect) = {
val parse = implicitly[Parse[Source]]
parse(input, dialect)
} match {
case x: scala.meta.parsers.Parsed.Success[_] => x.tree
Expand Down
102 changes: 0 additions & 102 deletions quasiquotes3/shared/src/test/scala/scala/meta/tests/Example.scala

This file was deleted.

0 comments on commit 44d1d72

Please sign in to comment.