From 44d1d720074b88224cb2c9c3035d53767dc77e66 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Wed, 3 Jan 2024 17:17:02 +0100 Subject: [PATCH] Add all unapply methods, and missing apply methods --- .../quasiquotes/ConversionMacros.scala | 12 +- .../meta/internal/quasiquotes/ExprLifts.scala | 452 ++- .../internal/quasiquotes/QuasiquoteType.scala | 17 +- .../quasiquotes/ReificationMacros.scala | 495 +-- .../scala/scala/meta/quasiquotes/Api.scala | 191 +- .../test/scala/scala/meta/tests/Example.scala | 102 - .../scala/meta/tests/RoundtripSuite.scala | 121 + .../scala/scala/meta/tests/SuccessSuite.scala | 2955 +++++++++++++++++ .../scala/meta/tests/TreeSuiteBase.scala | 28 +- 9 files changed, 3796 insertions(+), 577 deletions(-) delete mode 100644 quasiquotes3/shared/src/test/scala/scala/meta/tests/Example.scala create mode 100644 quasiquotes3/shared/src/test/scala/scala/meta/tests/RoundtripSuite.scala create mode 100644 quasiquotes3/shared/src/test/scala/scala/meta/tests/SuccessSuite.scala diff --git a/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ConversionMacros.scala b/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ConversionMacros.scala index 654b1b45ec..bda7e8237d 100644 --- a/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ConversionMacros.scala +++ b/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ConversionMacros.scala @@ -4,14 +4,13 @@ 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 @@ -19,8 +18,8 @@ object Lift { // 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 { @@ -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]})} @@ -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] } diff --git a/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ExprLifts.scala b/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ExprLifts.scala index 3b7d03f153..82f1466312 100644 --- a/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ExprLifts.scala +++ b/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ExprLifts.scala @@ -12,168 +12,168 @@ import scala.meta.internal.parsers.Messages import scala.collection.mutable import scala.annotation.tailrec -// uses holes in implementation, for which we do not have access here -trait InternalTrait(using Quotes) { - def liftTree(tree: MetaTree)(using Quotes): Expr[Any] - def liftOptionTree(maybeTree: Option[MetaTree]): Expr[Option[Any]] - def liftTrees[T: Type](trees: Seq[MetaTree])(using Quotes): Expr[List[Any]] - def liftQuasi0(quasi: Quasi, optional: Boolean = false): Expr[Any] +// uses holes in implementation, for which we do not have access here, so we implement those elsewhere +trait InternalTrait(using val internalQuotes: Quotes) { + def liftTree(tree: MetaTree): internalQuotes.reflect.Tree + def liftOptionTree[T: Type](maybeTree: Option[MetaTree]): internalQuotes.reflect.Tree + def liftTrees[T: Type](trees: Seq[MetaTree]): internalQuotes.reflect.Tree + def liftTreess(treess: List[List[MetaTree]]): internalQuotes.reflect.Tree + def liftQuasi0(quasi: Quasi, optional: Boolean = false): internalQuotes.reflect.Tree protected def unquotesName(q: scala.meta.internal.trees.Quasi): Boolean } // TODO should be generated by a custom codegen script -trait ExprLifts(using Quotes) extends ReificationMacros with InternalTrait { - import quotes.reflect._ +trait ExprLifts(using override val internalQuotes: Quotes)(isPatternMode: Boolean) extends ReificationMacros with InternalTrait { + import internalQuotes.reflect._ - given liftableSubTree[T <: MetaTree]: ToExpr[T] with { - def apply(tree: T)(using Quotes) = - liftableSubTree0(tree) - } - given liftableSubSeqTree[T <: MetaTree: Type]: ToExpr[Seq[T]] with { - def apply(tree: Seq[T])(using Quotes) = - liftTrees(tree).asExprOf[Seq[T]] - } - given liftableSubTrees[T <: MetaTree: Type]: ToExpr[List[T]] with { - def apply(tree: List[T])(using Quotes) = liftTrees[T](tree).asInstanceOf[Expr[List[T]]] - } - given liftableSubSeqTrees[T <: MetaTree]: ToExpr[Seq[List[T]]] with { - def apply(tree: Seq[List[T]])(using Quotes) = ???//Lifts.liftTreess(tree) - } - given liftableSubTreess[T <: MetaTree]: ToExpr[List[List[T]]] with { - def apply(tree: List[List[T]])(using Quotes) = ???//Lifts.liftTreess(tree) - } - given liftableOptionSubTree[T <: MetaTree]: ToExpr[Option[T]] with { - def apply(tree: Option[T])(using Quotes) = liftOptionTree(tree).asInstanceOf[Expr[Option[T]]] - } + def makeByMode[T](expr: Expr[T], args: Tree*): Tree = + val term = expr.asTerm match + case Inlined(_, _, inlined) => inlined + expr.asTerm.tpe.asType match + case '[t] => + if isPatternMode then Unapply(Select.unique(term, "unapply"), Nil, args.toList) + else Select.overloaded(term, "apply", Nil, args.toList.asInstanceOf[List[Term]]) - def liftQuasi(y: scala.meta.internal.trees.Quasi) = liftQuasi0(y); - def liftTypeFuncParamClause(y: scala.meta.Type.FuncParamClause) = '{scala.meta.Type.FuncParamClause(${Expr(y.values)})} - def liftTypeBounds(y: scala.meta.Type.Bounds) = '{scala.meta.Type.Bounds(${Expr(y.lo)}, ${Expr(y.hi)})} - def liftMemberParamClauseGroup(y: scala.meta.Member.ParamClauseGroup) = '{scala.meta.Member.ParamClauseGroup(${Expr(y.tparamClause)}, ${Expr(y.paramClauses)})} - def liftTemplate(y: scala.meta.Template) = '{scala.meta.Template(${Expr(y.early)}, ${Expr(y.inits)}, ${Expr(y.self)}, ${Expr(y.stats)}, ${Expr(y.`derives`)})} - def liftImporter(y: scala.meta.Importer) = '{scala.meta.Importer(${Expr(y.ref)}, ${Expr(y.importees)})} - def liftSource(y: scala.meta.Source) = '{scala.meta.Source(${Expr(y.stats)})} - def liftMultiSource(y: scala.meta.MultiSource) = '{scala.meta.MultiSource(${Expr(y.sources)})} - def liftInit(y: scala.meta.Init) = '{scala.meta.Init(${Expr(y.tpe)}, ${Expr(y.name)}, ${Expr(y.argClauses)})} - def liftNameAnonymous(y: scala.meta.Name.Anonymous) = '{scala.meta.Name.Anonymous()} - def liftNameThis(y: scala.meta.Name.This) = '{scala.meta.Name.This()} - def liftNameIndeterminate(y: scala.meta.Name.Indeterminate) = '{scala.meta.Name.Indeterminate(${Expr(y.value)})} - def liftNamePlaceholder(y: scala.meta.Name.Placeholder) = '{scala.meta.Name.Placeholder()} - def liftTermName(y: scala.meta.Term.Name) = '{scala.meta.Term.Name(${Expr(y.value)})} - def liftTermAnonymous(y: scala.meta.Term.Anonymous) = '{scala.meta.Term.Anonymous()} - def liftTypeName(y: scala.meta.Type.Name) = '{scala.meta.Type.Name(${Expr(y.value)})} - def liftTermThis(y: scala.meta.Term.This) = '{scala.meta.Term.This(${Expr(y.qual)})} - def liftTermSuper(y: scala.meta.Term.Super) = '{scala.meta.Term.Super(${Expr(y.thisp)}, ${Expr(y.superp)})} - def liftTermSelect(y: scala.meta.Term.Select) = '{scala.meta.Term.Select(${Expr(y.qual)}, ${Expr(y.name)})} - def liftTermApplyUnary(y: scala.meta.Term.ApplyUnary) = '{scala.meta.Term.ApplyUnary(${Expr(y.op)}, ${Expr(y.arg)})} - def liftTypeSelect(y: scala.meta.Type.Select) = '{scala.meta.Type.Select(${Expr(y.qual)}, ${Expr(y.name)})} - def liftTypeProject(y: scala.meta.Type.Project) = '{scala.meta.Type.Project(${Expr(y.qual)}, ${Expr(y.name)})} - def liftTypeSingleton(y: scala.meta.Type.Singleton) = '{scala.meta.Type.Singleton(${Expr(y.ref)})} - def liftImporteeWildcard(y: scala.meta.Importee.Wildcard) = '{scala.meta.Importee.Wildcard()} - def liftImporteeGiven(y: scala.meta.Importee.Given) = '{scala.meta.Importee.Given(${Expr(y.tpe)})} - def liftImporteeGivenAll(y: scala.meta.Importee.GivenAll) = '{scala.meta.Importee.GivenAll()} - def liftImporteeName(y: scala.meta.Importee.Name) = '{scala.meta.Importee.Name(${Expr(y.name)})} - def liftImporteeRename(y: scala.meta.Importee.Rename) = '{scala.meta.Importee.Rename(${Expr(y.name)}, ${Expr(y.rename)})} - def liftImporteeUnimport(y: scala.meta.Importee.Unimport) = '{scala.meta.Importee.Unimport(${Expr(y.name)})} - def liftTypeAnonymousName(y: scala.meta.Type.AnonymousName) = '{scala.meta.Type.AnonymousName()} - def liftTypeApply(y: scala.meta.Type.Apply) = '{scala.meta.Type.Apply(${Expr(y.tpe)}, ${Expr(y.argClause)})} - def liftTypeApplyInfix(y: scala.meta.Type.ApplyInfix) = '{scala.meta.Type.ApplyInfix(${Expr(y.lhs)}, ${Expr(y.op)}, ${Expr(y.rhs)})} - def liftTypePolyFunction(y: scala.meta.Type.PolyFunction) = '{scala.meta.Type.PolyFunction(${Expr(y.tparamClause)}, ${Expr(y.tpe)})} - def liftTypeImplicitFunction(y: scala.meta.Type.ImplicitFunction) = '{scala.meta.Type.ImplicitFunction(${Expr(y.params)}, ${Expr(y.res)})} - def liftTypeTuple(y: scala.meta.Type.Tuple) = '{scala.meta.Type.Tuple(${Expr(y.args)})} - def liftTypeWith(y: scala.meta.Type.With) = '{scala.meta.Type.With(${Expr(y.lhs)}, ${Expr(y.rhs)})} - def liftTypeAnd(y: scala.meta.Type.And) = '{scala.meta.Type.And(${Expr(y.lhs)}, ${Expr(y.rhs)})} - def liftTypeOr(y: scala.meta.Type.Or) = '{scala.meta.Type.Or(${Expr(y.lhs)}, ${Expr(y.rhs)})} - def liftTypeRefine(y: scala.meta.Type.Refine) = '{scala.meta.Type.Refine(${Expr(y.tpe)}, ${Expr(y.stats)})} - def liftTypeExistential(y: scala.meta.Type.Existential) = '{scala.meta.Type.Existential(${Expr(y.tpe)}, ${Expr(y.stats)})} - def liftTypeAnnotate(y: scala.meta.Type.Annotate) = '{scala.meta.Type.Annotate(${Expr(y.tpe)}, ${Expr(y.annots)})} - def liftTypeLambda(y: scala.meta.Type.Lambda) = '{scala.meta.Type.Lambda(${Expr(y.tparamClause)}, ${Expr(y.tpe)})} - def liftTypeAnonymousLambda(y: scala.meta.Type.AnonymousLambda) = '{scala.meta.Type.AnonymousLambda(${Expr(y.tpe)})} - def liftTypeMacro(y: scala.meta.Type.Macro) = '{scala.meta.Type.Macro(${Expr(y.body)})} - def liftTypeMethod(y: scala.meta.Type.Method) = '{scala.meta.Type.Method(${Expr(y.paramClauses)}, ${Expr(y.tpe)})} - def liftTypePatWildcard(y: scala.meta.Type.PatWildcard) = '{scala.meta.Type.PatWildcard()} - def liftTypeByName(y: scala.meta.Type.ByName) = '{scala.meta.Type.ByName(${Expr(y.tpe)})} - def liftTypeRepeated(y: scala.meta.Type.Repeated) = '{scala.meta.Type.Repeated(${Expr(y.tpe)})} - def liftTypeVar(y: scala.meta.Type.Var) = '{scala.meta.Type.Var(${Expr(y.name)})} - def liftTypeMatch(y: scala.meta.Type.Match) = '{scala.meta.Type.Match(${Expr(y.tpe)}, ${Expr(y.cases)})} - def liftLitNull(y: scala.meta.Lit.Null) = '{scala.meta.Lit.Null()} - def liftLitInt(y: scala.meta.Lit.Int) = '{scala.meta.Lit.Int(${Expr(y.value)})} - def liftLitDouble(y: scala.meta.Lit.Double) = '{scala.meta.Lit.Double(${Expr(y.format)})} - def liftLitFloat(y: scala.meta.Lit.Float) = '{scala.meta.Lit.Float(${Expr(y.format)})} - def liftLitByte(y: scala.meta.Lit.Byte) = '{scala.meta.Lit.Byte(${Expr(y.value)})} - def liftLitShort(y: scala.meta.Lit.Short) = '{scala.meta.Lit.Short(${Expr(y.value)})} - def liftLitChar(y: scala.meta.Lit.Char) = '{scala.meta.Lit.Char(${Expr(y.value)})} - def liftLitLong(y: scala.meta.Lit.Long) = '{scala.meta.Lit.Long(${Expr(y.value)})} - def liftLitBoolean(y: scala.meta.Lit.Boolean) = '{scala.meta.Lit.Boolean(${Expr(y.value)})} - def liftLitUnit(y: scala.meta.Lit.Unit) = '{scala.meta.Lit.Unit()} - def liftLitString(y: scala.meta.Lit.String) = '{scala.meta.Lit.String(${Expr(y.value)})} - // def liftLitSymbol(y: scala.meta.Lit.Symbol) = '{scala.meta.Lit.Symbol(${Expr(y.value)})} - def liftTypeFunction(y: scala.meta.Type.Function) = '{scala.meta.Type.Function(${Expr(y.paramClause)}, ${Expr(y.res)})} - def liftTypeContextFunction(y: scala.meta.Type.ContextFunction) = '{scala.meta.Type.ContextFunction(${Expr(y.paramClause)}, ${Expr(y.res)})} - def liftTypePlaceholderImpl(y: scala.meta.Type.Placeholder.Impl) = '{scala.meta.Type.Placeholder.Impl(${Expr(y.bounds)})} - def liftTypeWildcard(y: scala.meta.Type.Wildcard) = '{scala.meta.Type.Wildcard(${Expr(y.bounds)})} - def liftTypeAnonymousParam(y: scala.meta.Type.AnonymousParam) = '{scala.meta.Type.AnonymousParam(${Expr(y.variant)})} - def liftTypeTypedParam(y: scala.meta.Type.TypedParam) = '{scala.meta.Type.TypedParam(${Expr(y.name)}, ${Expr(y.typ)}, ${Expr(y.mods)})} - def liftTypeFunctionArg(y: scala.meta.Type.FunctionArg) = '{scala.meta.Type.FunctionArg(${Expr(y.mods)}, ${Expr(y.tpe)})} - def liftPatVar(y: scala.meta.Pat.Var) = '{scala.meta.Pat.Var(${Expr(y.name)})} - def liftPatWildcard(y: scala.meta.Pat.Wildcard) = '{scala.meta.Pat.Wildcard()} - def liftPatSeqWildcard(y: scala.meta.Pat.SeqWildcard) = '{scala.meta.Pat.SeqWildcard()} + def term[T <: MetaTree](tree: T): Tree = liftableSubTree0(tree) + def term[T <: MetaTree: Type](tree: Seq[T]): Tree = liftTrees[T](tree) + def term[T <: MetaTree: Type](tree: List[T]): Tree = liftTrees[T](tree) + @scala.annotation.targetName("term2") def term[T <: MetaTree: Type](tree: Seq[List[T]]): Tree = liftTreess(tree.toList) + @scala.annotation.targetName("term3") def term[T <: MetaTree: Type](tree: List[List[T]]): Tree = liftTreess(tree) + def term[T <: MetaTree: Type](tree: Option[T]): Tree = liftOptionTree[T](tree) + def term(tree: String): Tree = Literal(StringConstant(tree)) + def term(tree: Byte): Tree = Literal(ByteConstant(tree)) + def term(tree: Int): Tree = Literal(IntConstant(tree)) + def term(tree: Long): Tree = Literal(LongConstant(tree)) + def term(tree: Boolean): Tree = Literal(BooleanConstant(tree)) + + def liftQuasi(y: scala.meta.internal.trees.Quasi) = liftQuasi0(y) + def liftTypeFuncParamClause(y: scala.meta.Type.FuncParamClause) = makeByMode('{scala.meta.Type.FuncParamClause}, term(y.values)) + def liftTypeBounds(y: scala.meta.Type.Bounds) = makeByMode('{scala.meta.Type.Bounds}, term(y.lo), term(y.hi)) + def liftMemberParamClauseGroup(y: scala.meta.Member.ParamClauseGroup) = makeByMode('{scala.meta.Member.ParamClauseGroup}, term(y.tparamClause), term(y.paramClauses)) + def liftTemplate(y: scala.meta.Template) = makeByMode('{scala.meta.Template.After_4_4_0}, term(y.early), term(y.inits), term(y.self), term(y.stats), term(y.`derives`)) + def liftImporter(y: scala.meta.Importer) = makeByMode('{scala.meta.Importer}, term(y.ref), term(y.importees)) + def liftSource(y: scala.meta.Source) = makeByMode('{scala.meta.Source}, term(y.stats)) + def liftMultiSource(y: scala.meta.MultiSource) = makeByMode('{scala.meta.MultiSource}, term(y.sources)) + def liftInit(y: scala.meta.Init) = makeByMode('{scala.meta.Init.After_4_6_0}, term(y.tpe), term(y.name), term(y.argClauses)) + def liftNameAnonymous(y: scala.meta.Name.Anonymous) = makeByMode('{scala.meta.Name.Anonymous}) + def liftNameThis(y: scala.meta.Name.This) = makeByMode('{scala.meta.Name.This}) + def liftNameIndeterminate(y: scala.meta.Name.Indeterminate) = makeByMode('{scala.meta.Name.Indeterminate}, term(y.value)) + def liftNamePlaceholder(y: scala.meta.Name.Placeholder) = makeByMode('{scala.meta.Name.Placeholder}) + def liftTermName(y: scala.meta.Term.Name) = makeByMode('{scala.meta.Term.Name}, term(y.value)) + def liftTermAnonymous(y: scala.meta.Term.Anonymous) = makeByMode('{scala.meta.Term.Anonymous}) + def liftTypeName(y: scala.meta.Type.Name) = makeByMode('{scala.meta.Type.Name}, term(y.value)) + def liftTermThis(y: scala.meta.Term.This) = makeByMode('{scala.meta.Term.This}, term(y.qual)) + def liftTermSuper(y: scala.meta.Term.Super) = makeByMode('{scala.meta.Term.Super}, term(y.thisp), term(y.superp)) + def liftTermSelect(y: scala.meta.Term.Select) = makeByMode('{scala.meta.Term.Select}, term(y.qual), term(y.name)) + def liftTermApplyUnary(y: scala.meta.Term.ApplyUnary) = makeByMode('{scala.meta.Term.ApplyUnary}, term(y.op), term(y.arg)) + def liftTypeSelect(y: scala.meta.Type.Select) = makeByMode('{scala.meta.Type.Select}, term(y.qual), term(y.name)) + def liftTypeProject(y: scala.meta.Type.Project) = makeByMode('{scala.meta.Type.Project}, term(y.qual), term(y.name)) + def liftTypeSingleton(y: scala.meta.Type.Singleton) = makeByMode('{scala.meta.Type.Singleton}, term(y.ref)) + def liftImporteeWildcard(y: scala.meta.Importee.Wildcard) = makeByMode('{scala.meta.Importee.Wildcard}) + def liftImporteeGiven(y: scala.meta.Importee.Given) = makeByMode('{scala.meta.Importee.Given}, term(y.tpe)) + def liftImporteeGivenAll(y: scala.meta.Importee.GivenAll) = makeByMode('{scala.meta.Importee.GivenAll}) + def liftImporteeName(y: scala.meta.Importee.Name) = makeByMode('{scala.meta.Importee.Name}, term(y.name)) + def liftImporteeRename(y: scala.meta.Importee.Rename) = makeByMode('{scala.meta.Importee.Rename}, term(y.name), term(y.rename)) + def liftImporteeUnimport(y: scala.meta.Importee.Unimport) = makeByMode('{scala.meta.Importee.Unimport}, term(y.name)) + def liftTypeAnonymousName(y: scala.meta.Type.AnonymousName) = makeByMode('{scala.meta.Type.AnonymousName}) + def liftTypeApply(y: scala.meta.Type.Apply) = makeByMode('{scala.meta.Type.Apply.After_4_6_0}, term(y.tpe), term(y.argClause)) + def liftTypeApplyInfix(y: scala.meta.Type.ApplyInfix) = makeByMode('{scala.meta.Type.ApplyInfix.Initial}, term(y.lhs), term(y.op), term(y.rhs)) + def liftTypePolyFunction(y: scala.meta.Type.PolyFunction) = makeByMode('{scala.meta.Type.PolyFunction.After_4_6_0}, term(y.tparamClause), term(y.tpe)) + def liftTypeImplicitFunction(y: scala.meta.Type.ImplicitFunction) = makeByMode('{scala.meta.Type.ImplicitFunction.Initial}, term(y.params), term(y.res)) + def liftTypeTuple(y: scala.meta.Type.Tuple) = makeByMode('{scala.meta.Type.Tuple.Initial}, term(y.args)) + def liftTypeWith(y: scala.meta.Type.With) = makeByMode('{scala.meta.Type.With.Initial}, term(y.lhs), term(y.rhs)) + def liftTypeAnd(y: scala.meta.Type.And) = makeByMode('{scala.meta.Type.And.Initial}, term(y.lhs), term(y.rhs)) + def liftTypeOr(y: scala.meta.Type.Or) = makeByMode('{scala.meta.Type.Or.Initial}, term(y.lhs), term(y.rhs)) + def liftTypeRefine(y: scala.meta.Type.Refine) = makeByMode('{scala.meta.Type.Refine.Initial}, term(y.tpe), term(y.stats)) + def liftTypeExistential(y: scala.meta.Type.Existential) = makeByMode('{scala.meta.Type.Existential.Initial}, term(y.tpe), term(y.stats)) + def liftTypeAnnotate(y: scala.meta.Type.Annotate) = makeByMode('{scala.meta.Type.Annotate.Initial}, term(y.tpe), term(y.annots)) + def liftTypeLambda(y: scala.meta.Type.Lambda) = makeByMode('{scala.meta.Type.Lambda.After_4_6_0}, term(y.tparamClause), term(y.tpe)) + def liftTypeAnonymousLambda(y: scala.meta.Type.AnonymousLambda) = makeByMode('{scala.meta.Type.AnonymousLambda.Initial}, term(y.tpe)) + def liftTypeMacro(y: scala.meta.Type.Macro) = makeByMode('{scala.meta.Type.Macro.Initial}, term(y.body)) + def liftTypeMethod(y: scala.meta.Type.Method) = makeByMode('{scala.meta.Type.Method.After_4_6_0}, term(y.paramClauses), term(y.tpe)) + def liftTypePatWildcard(y: scala.meta.Type.PatWildcard) = makeByMode('{scala.meta.Type.PatWildcard}) + def liftTypeByName(y: scala.meta.Type.ByName) = makeByMode('{scala.meta.Type.ByName.Initial}, term(y.tpe)) + def liftTypeRepeated(y: scala.meta.Type.Repeated) = makeByMode('{scala.meta.Type.Repeated.Initial}, term(y.tpe)) + def liftTypeVar(y: scala.meta.Type.Var) = makeByMode('{scala.meta.Type.Var.Initial}, term(y.name)) + def liftTypeMatch(y: scala.meta.Type.Match) = makeByMode('{scala.meta.Type.Match.Initial}, term(y.tpe), term(y.cases)) + def liftLitNull(y: scala.meta.Lit.Null) = makeByMode('{scala.meta.Lit.Null}) + def liftLitInt(y: scala.meta.Lit.Int) = makeByMode('{scala.meta.Lit.Int.Initial}, term(y.value)) + def liftLitDouble(y: scala.meta.Lit.Double) = makeByMode('{scala.meta.Lit.Double.Initial}, term(y.format)) + def liftLitFloat(y: scala.meta.Lit.Float) = makeByMode('{scala.meta.Lit.Float.Initial}, term(y.format)) + def liftLitByte(y: scala.meta.Lit.Byte) = makeByMode('{scala.meta.Lit.Byte.Initial}, term(y.value)) + def liftLitShort(y: scala.meta.Lit.Short) = makeByMode('{scala.meta.Lit.Short.Initial}, term(y.value)) + def liftLitChar(y: scala.meta.Lit.Char) = makeByMode('{scala.meta.Lit.Char.Initial}, term(y.value)) + def liftLitLong(y: scala.meta.Lit.Long) = makeByMode('{scala.meta.Lit.Long.Initial}, term(y.value)) + def liftLitBoolean(y: scala.meta.Lit.Boolean) = makeByMode('{scala.meta.Lit.Boolean.Initial}, term(y.value)) + def liftLitUnit(y: scala.meta.Lit.Unit) = makeByMode('{scala.meta.Lit.Unit}) + def liftLitString(y: scala.meta.Lit.String) = makeByMode('{scala.meta.Lit.String.Initial}, term(y.value)) + // def liftLitSymbol(y: scala.meta.Lit.Symbol) = makeByMode('{scala.meta.Lit.Symbol}, term(y.value)) + def liftTypeFunction(y: scala.meta.Type.Function) = makeByMode('{scala.meta.Type.Function.After_4_6_0}, term(y.paramClause), term(y.res)) + def liftTypeContextFunction(y: scala.meta.Type.ContextFunction) = makeByMode('{scala.meta.Type.ContextFunction.After_4_6_0}, term(y.paramClause), term(y.res)) + def liftTypePlaceholderImpl(y: scala.meta.Type.Placeholder.Impl) = makeByMode('{scala.meta.Type.Placeholder.Impl.Initial}, term(y.bounds)) + def liftTypeWildcard(y: scala.meta.Type.Wildcard) = makeByMode('{scala.meta.Type.Wildcard.Initial}, term(y.bounds)) + def liftTypeAnonymousParam(y: scala.meta.Type.AnonymousParam) = makeByMode('{scala.meta.Type.AnonymousParam.Initial}, term(y.variant)) + def liftTypeTypedParam(y: scala.meta.Type.TypedParam) = makeByMode('{scala.meta.Type.TypedParam.After_4_7_8}, term(y.name), term(y.typ), term(y.mods)) + def liftTypeFunctionArg(y: scala.meta.Type.FunctionArg) = makeByMode('{scala.meta.Type.FunctionArg.Initial}, term(y.mods), term(y.tpe)) + def liftPatVar(y: scala.meta.Pat.Var) = makeByMode('{scala.meta.Pat.Var.Initial}, term(y.name)) + def liftPatWildcard(y: scala.meta.Pat.Wildcard) = makeByMode('{scala.meta.Pat.Wildcard}) + def liftPatSeqWildcard(y: scala.meta.Pat.SeqWildcard) = makeByMode('{scala.meta.Pat.SeqWildcard}) def liftPatBind(y: scala.meta.Pat.Bind) = { { - import quotes.reflect._ + import internalQuotes.reflect._ def prohibitName(pat: scala.meta.Tree): Unit = { pat match { case (q @ (_: scala.meta.internal.trees.Quasi)) if unquotesName(q) => { val action = if (q.rank == 0) "unquote" else "splice" - report.errorAndAbort("can\'t " + action + " a name here, use a pattern instead (e.g. p\"x\")")//, q.pos) + report.errorAndAbort("can\'t " + action + " a name here, use a pattern instead (e.g. p\"x\")") } case _ => () } }; prohibitName(y.lhs) } - '{scala.meta.Pat.Bind(${Expr(y.lhs)}, ${Expr(y.rhs)})} + makeByMode('{scala.meta.Pat.Bind}, term(y.lhs), term(y.rhs)) } - def liftPatAlternative(y: scala.meta.Pat.Alternative) = '{scala.meta.Pat.Alternative(${Expr(y.lhs)}, ${Expr(y.rhs)})} - def liftPatTuple(y: scala.meta.Pat.Tuple) = '{scala.meta.Pat.Tuple(${Expr(y.args)})} - def liftPatRepeated(y: scala.meta.Pat.Repeated) = '{scala.meta.Pat.Repeated(${Expr(y.name)})} - def liftPatExtract(y: scala.meta.Pat.Extract) = '{scala.meta.Pat.Extract(${Expr(y.fun)}, ${Expr(y.argClause)})} - def liftPatExtractInfix(y: scala.meta.Pat.ExtractInfix) = '{scala.meta.Pat.ExtractInfix(${Expr(y.lhs)}, ${Expr(y.op)}, ${Expr(y.argClause)})} - def liftPatInterpolate(y: scala.meta.Pat.Interpolate) = '{scala.meta.Pat.Interpolate(${Expr(y.prefix)}, ${Expr(y.parts)}, ${Expr(y.args)})} - def liftPatXml(y: scala.meta.Pat.Xml) = '{scala.meta.Pat.Xml(${Expr(y.parts)}, ${Expr(y.args)})} + def liftPatAlternative(y: scala.meta.Pat.Alternative) = makeByMode('{scala.meta.Pat.Alternative.Initial}, term(y.lhs), term(y.rhs)) + def liftPatTuple(y: scala.meta.Pat.Tuple) = makeByMode('{scala.meta.Pat.Tuple.Initial}, term(y.args)) + def liftPatRepeated(y: scala.meta.Pat.Repeated) = makeByMode('{scala.meta.Pat.Repeated.Initial}, term(y.name)) + def liftPatExtract(y: scala.meta.Pat.Extract) = makeByMode('{scala.meta.Pat.Extract.After_4_6_0}, term(y.fun), term(y.argClause)) + def liftPatExtractInfix(y: scala.meta.Pat.ExtractInfix) = makeByMode('{scala.meta.Pat.ExtractInfix.After_4_6_0}, term(y.lhs), term(y.op), term(y.argClause)) + def liftPatInterpolate(y: scala.meta.Pat.Interpolate) = makeByMode('{scala.meta.Pat.Interpolate.Initial}, term(y.prefix), term(y.parts), term(y.args)) + def liftPatXml(y: scala.meta.Pat.Xml) = makeByMode('{scala.meta.Pat.Xml.Initial}, term(y.parts), term(y.args)) def liftPatTyped(y: scala.meta.Pat.Typed) = { { - import quotes.reflect._ + import internalQuotes.reflect._ def prohibitName(pat: scala.meta.Tree): Unit = { pat match { case (q @ (_: scala.meta.internal.trees.Quasi)) if unquotesName(q) => { val action = if (q.rank == 0) "unquote" else "splice" - report.errorAndAbort("can\'t " + action + " a name here, use a pattern instead (e.g. p\"x\")")//, q.pos) + report.errorAndAbort("can\'t " + action + " a name here, use a pattern instead (e.g. p\"x\")") } case _ => () } } prohibitName(y.lhs) } - '{scala.meta.Pat.Typed(${Expr(y.lhs)}, ${Expr(y.rhs)})} - }; - def liftPatMacro(y: scala.meta.Pat.Macro) = '{scala.meta.Pat.Macro(${Expr(y.body)})} - def liftPatGiven(y: scala.meta.Pat.Given) = '{scala.meta.Pat.Given(${Expr(y.tpe)})} - def liftPkg(y: scala.meta.Pkg) = '{scala.meta.Pkg(${Expr(y.ref)}, ${Expr(y.stats)})} - def liftPkgObject(y: scala.meta.Pkg.Object) = '{scala.meta.Pkg.Object(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.templ)})} - def liftCtorSecondary(y: scala.meta.Ctor.Secondary) = '{scala.meta.Ctor.Secondary(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.paramClauses)}, ${Expr(y.init)}, ${Expr(y.stats)})} - def liftTermInterpolate(y: scala.meta.Term.Interpolate) = '{scala.meta.Term.Interpolate(${Expr(y.prefix)}, ${Expr(y.parts)}, ${Expr(y.args)})} - def liftTermXml(y: scala.meta.Term.Xml) = '{scala.meta.Term.Xml(${Expr(y.parts)}, ${Expr(y.args)})} + makeByMode('{scala.meta.Pat.Typed}, term(y.lhs), term(y.rhs)) + } + def liftPatMacro(y: scala.meta.Pat.Macro) = makeByMode('{scala.meta.Pat.Macro.Initial}, term(y.body)) + def liftPatGiven(y: scala.meta.Pat.Given) = makeByMode('{scala.meta.Pat.Given.Initial}, term(y.tpe)) + def liftPkg(y: scala.meta.Pkg) = makeByMode('{scala.meta.Pkg.Initial}, term(y.ref), term(y.stats)) + def liftPkgObject(y: scala.meta.Pkg.Object) = makeByMode('{scala.meta.Pkg.Object.Initial}, term(y.mods), term(y.name), term(y.templ)) + def liftCtorSecondary(y: scala.meta.Ctor.Secondary) = makeByMode('{scala.meta.Ctor.Secondary.After_4_6_0}, term(y.mods), term(y.name), term(y.paramClauses), term(y.init), term(y.stats)) + def liftTermInterpolate(y: scala.meta.Term.Interpolate) = makeByMode('{scala.meta.Term.Interpolate.Initial}, term(y.prefix), term(y.parts), term(y.args)) + def liftTermXml(y: scala.meta.Term.Xml) = makeByMode('{scala.meta.Term.Xml.Initial}, term(y.parts), term(y.args)) def liftTermApply(y: scala.meta.Term.Apply) = { object ApplyToTripleDots extends scala.AnyRef { def unapply(t: scala.meta.Term.Apply): Option[scala.Tuple2[scala.meta.Term, scala.Either[scala.meta.Term.Quasi, scala.meta.Term.ArgClause.Quasi]]] = t.argClause match { case (arg @ (_: scala.meta.Term.ArgClause.Quasi)) if arg.rank == 1 => scala.Some(scala.Tuple2(t.fun, scala.Right(arg))) - case scala.List((arg @ (_: scala.meta.Term.Quasi))) if arg.rank == (2) => scala.Some(scala.Tuple2(t.fun, scala.Left(arg))) + case List(arg @ (_: scala.meta.Term.Quasi)) if arg.rank == (2) => scala.Some(scala.Tuple2(t.fun, scala.Left(arg))) case _ => scala.None } } @@ -183,67 +183,65 @@ trait ExprLifts(using Quotes) extends ReificationMacros with InternalTrait { case _ => ???//c.abort(arg.pos, _root_.scala.meta.internal.parsers.Messages.QuasiquoteAdjacentEllipsesInPattern(arg.rank)) } case _ => () - }; + } def applyTermQuasi(fn: scala.meta.Term)(arg: scala.meta.Term.Quasi) = { checkNoTripleDots(fn, arg) - '{scala.meta.internal.trees.Syntactic.TermApply.ArgListList(${Expr(fn)}, ${Expr(List(List(arg)))})} - // c.universe.Apply(c.universe.Select(c.universe.Select(c.universe.Select(c.universe.Select(c.universe.Select(c.universe.Select(c.universe.Select(c.universe.Ident(c.universe.TermName("_root_")), c.universe.TermName("scala")), c.universe.TermName("meta")), c.universe.TermName("internal")), c.universe.TermName("trees")), c.universe.TermName("Syntactic")), c.universe.TermName("TermApply")), c.universe.TermName("ArgListList")), _root_.scala.List(_root_.scala.Predef.implicitly[c.universe.Liftable[_root_.scala.meta.Term]].apply(fn), _root_.scala.Predef.implicitly[c.universe.Liftable[List[List[_root_.scala.meta.Term.Quasi]]]].apply(List(List(arg))))) + makeByMode('{scala.meta.internal.trees.Syntactic.TermApply.ArgListList}, term(fn), term(List(List(arg)))) } def applyArgClauseQuasi(fn: _root_.scala.meta.Term)(arg: _root_.scala.meta.Term.ArgClause.Quasi) = { checkNoTripleDots(fn, arg) - '{scala.meta.internal.trees.Syntactic.TermApply.ArgList(${Expr(fn)}, ${Expr(List(arg))})} - // c.universe.Apply(c.universe.Select(c.universe.Select(c.universe.Select(c.universe.Select(c.universe.Select(c.universe.Select(c.universe.Select(c.universe.Ident(c.universe.TermName("_root_")), c.universe.TermName("scala")), c.universe.TermName("meta")), c.universe.TermName("internal")), c.universe.TermName("trees")), c.universe.TermName("Syntactic")), c.universe.TermName("TermApply")), c.universe.TermName("ArgList")), _root_.scala.List(_root_.scala.Predef.implicitly[c.universe.Liftable[_root_.scala.meta.Term]].apply(fn), _root_.scala.Predef.implicitly[c.universe.Liftable[List[_root_.scala.meta.Term.ArgClause.Quasi]]].apply(List(arg)))) + makeByMode('{scala.meta.internal.trees.Syntactic.TermApply.ArgList}, term(fn), term(List(arg))) } y match { case ApplyToTripleDots((fn @ _), (either @ _)) => either.fold(applyTermQuasi(fn), applyArgClauseQuasi(fn)) - case _ => '{scala.meta.Term.Apply(${Expr(y.fun)}, ${Expr(y.argClause)})} + case _ => makeByMode('{scala.meta.Term.Apply.After_4_6_0}, term(y.fun), term(y.argClause)) } } - def liftTermApplyUsing(y: scala.meta.Term.ApplyUsing) = '{scala.meta.Term.ApplyUsing(${Expr(y.fun)}, ${Expr(y.argClause)})} - def liftTermApplyType(y: scala.meta.Term.ApplyType)(using Quotes) = '{scala.meta.Term.ApplyType(${Expr(y.fun)}, ${Expr(y.targClause)})} - def liftTermApplyInfix(y: scala.meta.Term.ApplyInfix) = '{scala.meta.Term.ApplyInfix(${Expr(y.lhs)}, ${Expr(y.op)}, ${Expr(y.targClause)}, ${Expr(y.argClause)})} - def liftTermAssign(y: scala.meta.Term.Assign) = '{scala.meta.Term.Assign(${Expr(y.lhs)}, ${Expr(y.rhs)})} - def liftTermReturn(y: scala.meta.Term.Return) = '{scala.meta.Term.Return(${Expr(y.expr)})} - def liftTermThrow(y: scala.meta.Term.Throw) = '{scala.meta.Term.Throw(${Expr(y.expr)})} - def liftTermAscribe(y: scala.meta.Term.Ascribe) = '{scala.meta.Term.Ascribe(${Expr(y.expr)}, ${Expr(y.tpe)})} - def liftTermAnnotate(y: scala.meta.Term.Annotate) = '{scala.meta.Term.Annotate(${Expr(y.expr)}, ${Expr(y.annots)})} - def liftTermTuple(y: scala.meta.Term.Tuple) = '{scala.meta.Term.Tuple(${Expr(y.args)})} - def liftTermBlock(y: scala.meta.Term.Block) = '{scala.meta.Term.Block(${Expr(y.stats)})} - def liftTermEndMarker(y: scala.meta.Term.EndMarker) = '{scala.meta.Term.EndMarker(${Expr(y.name)})} - def liftTermIf(y: scala.meta.Term.If) = '{scala.meta.Term.If(${Expr(y.cond)}, ${Expr(y.thenp)}, ${Expr(y.elsep)}, ${Expr(y.mods)})} - def liftTermQuotedMacroExpr(y: scala.meta.Term.QuotedMacroExpr) = '{scala.meta.Term.QuotedMacroExpr(${Expr(y.body)})} - def liftTermQuotedMacroType(y: scala.meta.Term.QuotedMacroType) = '{scala.meta.Term.QuotedMacroType(${Expr(y.tpe)})} - def liftTermSplicedMacroExpr(y: scala.meta.Term.SplicedMacroExpr) = '{scala.meta.Term.SplicedMacroExpr(${Expr(y.body)})} - def liftTermSplicedMacroPat(y: scala.meta.Term.SplicedMacroPat) = '{scala.meta.Term.SplicedMacroPat(${Expr(y.pat)})} - def liftTermMatch(y: scala.meta.Term.Match) = '{scala.meta.Term.Match(${Expr(y.expr)}, ${Expr(y.cases)}, ${Expr(y.mods)})} - def liftTermTry(y: scala.meta.Term.Try) = '{scala.meta.Term.Try(${Expr(y.expr)}, ${Expr(y.catchp)}, ${Expr(y.finallyp)})} - def liftTermTryWithHandler(y: scala.meta.Term.TryWithHandler) = '{scala.meta.Term.TryWithHandler(${Expr(y.expr)}, ${Expr(y.catchp)}, ${Expr(y.finallyp)})} - def liftTermAnonymousFunction(y: scala.meta.Term.AnonymousFunction) = '{scala.meta.Term.AnonymousFunction(${Expr(y.body)})} - def liftTermPolyFunction(y: scala.meta.Term.PolyFunction) = '{scala.meta.Term.PolyFunction(${Expr(y.tparamClause)}, ${Expr(y.body)})} - def liftTermPartialFunction(y: scala.meta.Term.PartialFunction) = '{scala.meta.Term.PartialFunction(${Expr(y.cases)})} - def liftTermWhile(y: scala.meta.Term.While) = '{scala.meta.Term.While(${Expr(y.expr)}, ${Expr(y.body)})} - def liftTermDo(y: scala.meta.Term.Do) = '{scala.meta.Term.Do(${Expr(y.body)}, ${Expr(y.expr)})} - def liftTermFor(y: scala.meta.Term.For) = '{scala.meta.Term.For(${Expr(y.enums)}, ${Expr(y.body)})} - def liftTermForYield(y: scala.meta.Term.ForYield) = '{scala.meta.Term.ForYield(${Expr(y.enums)}, ${Expr(y.body)})} - def liftTermNew(y: scala.meta.Term.New) = '{scala.meta.Term.New(${Expr(y.init)})} - def liftTermNewAnonymous(y: scala.meta.Term.NewAnonymous) = '{scala.meta.Term.NewAnonymous(${Expr(y.templ)})} - def liftTermPlaceholder(y: scala.meta.Term.Placeholder) = '{scala.meta.Term.Placeholder()} - def liftTermEta(y: scala.meta.Term.Eta) = '{scala.meta.Term.Eta(${Expr(y.expr)})} - def liftTermRepeated(y: scala.meta.Term.Repeated) = '{scala.meta.Term.Repeated(${Expr(y.expr)})} - def liftTermContextFunction(y: scala.meta.Term.ContextFunction) = '{scala.meta.Term.ContextFunction(${Expr(y.paramClause)}, ${Expr(y.body)})} - def liftTermFunction(y: scala.meta.Term.Function) = '{scala.meta.Term.Function(${Expr(y.paramClause)}, ${Expr(y.body)})} - def liftDefnGiven(y: scala.meta.Defn.Given) = '{scala.meta.Defn.Given(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.paramClauseGroup)}, ${Expr(y.templ)})} - def liftDefnEnum(y: scala.meta.Defn.Enum) = '{scala.meta.Defn.Enum(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.tparamClause)}, ${Expr(y.ctor)}, ${Expr(y.templ)})} - def liftDefnClass(y: scala.meta.Defn.Class) = '{scala.meta.Defn.Class(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.tparamClause)}, ${Expr(y.ctor)}, ${Expr(y.templ)})} - def liftDefnTrait(y: scala.meta.Defn.Trait) = '{scala.meta.Defn.Trait(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.tparamClause)}, ${Expr(y.ctor)}, ${Expr(y.templ)})} - def liftDefnObject(y: scala.meta.Defn.Object) = '{scala.meta.Defn.Object(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.templ)})} - def liftDeclVal(y: scala.meta.Decl.Val) = '{scala.meta.Decl.Val(${Expr(y.mods)}, ${Expr(y.pats)}, ${Expr(y.decltpe)})} - def liftDeclVar(y: scala.meta.Decl.Var) = '{scala.meta.Decl.Var(${Expr(y.mods)}, ${Expr(y.pats)}, ${Expr(y.decltpe)})} - def liftDeclDef(y: scala.meta.Decl.Def) = '{scala.meta.Decl.Def(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.paramClauseGroups)}, ${Expr(y.decltpe)})} - def liftDeclType(y: scala.meta.Decl.Type) = '{scala.meta.Decl.Type(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.tparamClause)}, ${Expr(y.bounds)})} - def liftDeclGiven(y: scala.meta.Decl.Given) = '{scala.meta.Decl.Given(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.paramClauseGroup)}, ${Expr(y.decltpe)})} + def liftTermApplyUsing(y: scala.meta.Term.ApplyUsing) = makeByMode('{scala.meta.Term.ApplyUsing.After_4_6_0}, term(y.fun), term(y.argClause)) + def liftTermApplyType(y: scala.meta.Term.ApplyType) = makeByMode('{scala.meta.Term.ApplyType.After_4_6_0}, term(y.fun), term(y.targClause)) + def liftTermApplyInfix(y: scala.meta.Term.ApplyInfix) = makeByMode('{scala.meta.Term.ApplyInfix.After_4_6_0}, term(y.lhs), term(y.op), term(y.targClause), term(y.argClause)) + def liftTermAssign(y: scala.meta.Term.Assign) = makeByMode('{scala.meta.Term.Assign.Initial}, term(y.lhs), term(y.rhs)) + def liftTermReturn(y: scala.meta.Term.Return) = makeByMode('{scala.meta.Term.Return.Initial}, term(y.expr)) + def liftTermThrow(y: scala.meta.Term.Throw) = makeByMode('{scala.meta.Term.Throw.Initial}, term(y.expr)) + def liftTermAscribe(y: scala.meta.Term.Ascribe) = makeByMode('{scala.meta.Term.Ascribe.Initial}, term(y.expr), term(y.tpe)) + def liftTermAnnotate(y: scala.meta.Term.Annotate) = makeByMode('{scala.meta.Term.Annotate.Initial}, term(y.expr), term(y.annots)) + def liftTermTuple(y: scala.meta.Term.Tuple) = makeByMode('{scala.meta.Term.Tuple.Initial}, term(y.args)) + def liftTermBlock(y: scala.meta.Term.Block) = makeByMode('{scala.meta.Term.Block.Initial}, term(y.stats)) + def liftTermEndMarker(y: scala.meta.Term.EndMarker) = makeByMode('{scala.meta.Term.EndMarker.Initial}, term(y.name)) + def liftTermIf(y: scala.meta.Term.If) = makeByMode('{scala.meta.Term.If.After_4_4_0}, term(y.cond), term(y.thenp), term(y.elsep), term(y.mods)) + def liftTermQuotedMacroExpr(y: scala.meta.Term.QuotedMacroExpr) = makeByMode('{scala.meta.Term.QuotedMacroExpr.Initial}, term(y.body)) + def liftTermQuotedMacroType(y: scala.meta.Term.QuotedMacroType) = makeByMode('{scala.meta.Term.QuotedMacroType.Initial}, term(y.tpe)) + def liftTermSplicedMacroExpr(y: scala.meta.Term.SplicedMacroExpr) = makeByMode('{scala.meta.Term.SplicedMacroExpr.Initial}, term(y.body)) + def liftTermSplicedMacroPat(y: scala.meta.Term.SplicedMacroPat) = makeByMode('{scala.meta.Term.SplicedMacroPat.Initial}, term(y.pat)) + def liftTermMatch(y: scala.meta.Term.Match) = makeByMode('{scala.meta.Term.Match.After_4_4_5}, term(y.expr), term(y.cases), term(y.mods)) + def liftTermTry(y: scala.meta.Term.Try) = makeByMode('{scala.meta.Term.Try.Initial}, term(y.expr), term(y.catchp), term(y.finallyp)) + def liftTermTryWithHandler(y: scala.meta.Term.TryWithHandler) = makeByMode('{scala.meta.Term.TryWithHandler.Initial}, term(y.expr), term(y.catchp), term(y.finallyp)) + def liftTermAnonymousFunction(y: scala.meta.Term.AnonymousFunction) = makeByMode('{scala.meta.Term.AnonymousFunction.Initial}, term(y.body)) + def liftTermPolyFunction(y: scala.meta.Term.PolyFunction) = makeByMode('{scala.meta.Term.PolyFunction.After_4_6_0}, term(y.tparamClause), term(y.body)) + def liftTermPartialFunction(y: scala.meta.Term.PartialFunction) = makeByMode('{scala.meta.Term.PartialFunction.Initial}, term(y.cases)) + def liftTermWhile(y: scala.meta.Term.While) = makeByMode('{scala.meta.Term.While.Initial}, term(y.expr), term(y.body)) + def liftTermDo(y: scala.meta.Term.Do) = makeByMode('{scala.meta.Term.Do.Initial}, term(y.body), term(y.expr)) + def liftTermFor(y: scala.meta.Term.For) = makeByMode('{scala.meta.Term.For.Initial}, term(y.enums), term(y.body)) + def liftTermForYield(y: scala.meta.Term.ForYield) = makeByMode('{scala.meta.Term.ForYield.Initial}, term(y.enums), term(y.body)) + def liftTermNew(y: scala.meta.Term.New) = makeByMode('{scala.meta.Term.New.Initial}, term(y.init)) + def liftTermNewAnonymous(y: scala.meta.Term.NewAnonymous) = makeByMode('{scala.meta.Term.NewAnonymous.Initial}, term(y.templ)) + def liftTermPlaceholder(y: scala.meta.Term.Placeholder) = makeByMode('{scala.meta.Term.Placeholder}) + def liftTermEta(y: scala.meta.Term.Eta) = makeByMode('{scala.meta.Term.Eta.Initial}, term(y.expr)) + def liftTermRepeated(y: scala.meta.Term.Repeated) = makeByMode('{scala.meta.Term.Repeated.Initial}, term(y.expr)) + def liftTermContextFunction(y: scala.meta.Term.ContextFunction) = makeByMode('{scala.meta.Term.ContextFunction.After_4_6_0}, term(y.paramClause), term(y.body)) + def liftTermFunction(y: scala.meta.Term.Function) = makeByMode('{scala.meta.Term.Function.After_4_6_0}, term(y.paramClause), term(y.body)) + def liftDefnGiven(y: scala.meta.Defn.Given) = makeByMode('{scala.meta.Defn.Given.After_4_6_0}, term(y.mods), term(y.name), term(y.paramClauseGroup), term(y.templ)) + def liftDefnEnum(y: scala.meta.Defn.Enum) = makeByMode('{scala.meta.Defn.Enum.After_4_6_0}, term(y.mods), term(y.name), term(y.tparamClause), term(y.ctor), term(y.templ)) + def liftDefnClass(y: scala.meta.Defn.Class) = makeByMode('{scala.meta.Defn.Class.After_4_6_0}, term(y.mods), term(y.name), term(y.tparamClause), term(y.ctor), term(y.templ)) + def liftDefnTrait(y: scala.meta.Defn.Trait) = makeByMode('{scala.meta.Defn.Trait.After_4_6_0}, term(y.mods), term(y.name), term(y.tparamClause), term(y.ctor), term(y.templ)) + def liftDefnObject(y: scala.meta.Defn.Object) = makeByMode('{scala.meta.Defn.Object.Initial}, term(y.mods), term(y.name), term(y.templ)) + def liftDeclVal(y: scala.meta.Decl.Val) = makeByMode('{scala.meta.Decl.Val.Initial}, term(y.mods), term(y.pats), term(y.decltpe)) + def liftDeclVar(y: scala.meta.Decl.Var) = makeByMode('{scala.meta.Decl.Var.Initial}, term(y.mods), term(y.pats), term(y.decltpe)) + def liftDeclDef(y: scala.meta.Decl.Def) = makeByMode('{scala.meta.Decl.Def.After_4_7_3}, term(y.mods), term(y.name), term(y.paramClauseGroups), term(y.decltpe)) + def liftDeclType(y: scala.meta.Decl.Type) = makeByMode('{scala.meta.Decl.Type.After_4_6_0}, term(y.mods), term(y.name), term(y.tparamClause), term(y.bounds)) + def liftDeclGiven(y: scala.meta.Decl.Given) = makeByMode('{scala.meta.Decl.Given.After_4_6_0}, term(y.mods), term(y.name), term(y.paramClauseGroup), term(y.decltpe)) def liftDefnVal(y: scala.meta.Defn.Val) = { - import quotes.reflect._ + import internalQuotes.reflect._ y.pats.foreach(((pat) => { def prohibitName(pat: scala.meta.Tree): _root_.scala.Unit = { pat match { @@ -251,17 +249,17 @@ trait ExprLifts(using Quotes) extends ReificationMacros with InternalTrait { val action = if (q.rank == 0) "unquote" else "splice" - report.errorAndAbort("can\'t " + action + " a name here, use a pattern instead (e.g. p\"x\")")//, q.pos) + report.errorAndAbort("can\'t " + action + " a name here, use a pattern instead (e.g. p\"x\")") } case _ => () } - }; + } prohibitName(pat) })) - '{scala.meta.Defn.Val(${Expr(y.mods)}, ${Expr(y.pats)}, ${Expr(y.decltpe)}, ${Expr(y.rhs)})} + makeByMode('{scala.meta.Defn.Val}, term(y.mods), term(y.pats), term(y.decltpe), term(y.rhs)) } def liftDefnVar(y: scala.meta.Defn.Var) = { - import quotes.reflect._ + import internalQuotes.reflect._ y.pats.foreach(((pat) => { def prohibitName(pat: scala.meta.Tree): _root_.scala.Unit = { pat match { @@ -269,65 +267,66 @@ trait ExprLifts(using Quotes) extends ReificationMacros with InternalTrait { val action = if (q.rank == 0) "unquote" else "splice" - report.errorAndAbort("can\'t " + action + " a name here, use a pattern instead (e.g. p\"x\")")//, q.pos) + report.errorAndAbort("can\'t " + action + " a name here, use a pattern instead (e.g. p\"x\")") } case _ => () } } prohibitName(pat) })) - '{scala.meta.Defn.Var(${Expr(y.mods)}, ${Expr(y.pats)}, ${Expr(y.decltpe)}, ${Expr(y.body)})} + makeByMode('{scala.meta.Defn.Var.After_4_7_2}, term(y.mods), term(y.pats), term(y.decltpe), term(y.body)) } - def liftDefnEnumCase(y: scala.meta.Defn.EnumCase) = '{scala.meta.Defn.EnumCase(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.tparamClause)}, ${Expr(y.ctor)}, ${Expr(y.inits)})} - def liftDefnRepeatedEnumCase(y: scala.meta.Defn.RepeatedEnumCase) = '{scala.meta.Defn.RepeatedEnumCase(${Expr(y.mods)}, ${Expr(y.cases)})} - def liftDefnGivenAlias(y: scala.meta.Defn.GivenAlias) = '{scala.meta.Defn.GivenAlias(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.paramClauseGroup)}, ${Expr(y.decltpe)}, ${Expr(y.body)})} - def liftDefnDef(y: scala.meta.Defn.Def) = '{scala.meta.Defn.Def(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.paramClauseGroups)}, ${Expr(y.decltpe)}, ${Expr(y.body)})} - def liftDefnMacro(y: scala.meta.Defn.Macro) = '{scala.meta.Defn.Macro(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.paramClauseGroups)}, ${Expr(y.decltpe)}, ${Expr(y.body)})} - def liftDefnType(y: scala.meta.Defn.Type) = '{scala.meta.Defn.Type(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.tparamClause)}, ${Expr(y.body)}, ${Expr(y.bounds)})} - def liftDefnExtensionGroup(y: scala.meta.Defn.ExtensionGroup) = '{scala.meta.Defn.ExtensionGroup(${Expr(y.paramClauseGroup)}, ${Expr(y.body)})} - def liftImport(y: scala.meta.Import) = '{scala.meta.Import(${Expr(y.importers)})} - def liftExport(y: scala.meta.Export) = '{scala.meta.Export(${Expr(y.importers)})} - def liftTermArgClause(y: scala.meta.Term.ArgClause) = '{scala.meta.Term.ArgClause(${Expr(y.values)}, ${Expr(y.mod)})} - def liftTypeArgClause(y: scala.meta.Type.ArgClause)(using Quotes) = '{scala.meta.Type.ArgClause(${Expr(y.values)})} - def liftPatArgClause(y: scala.meta.Pat.ArgClause)(using Quotes) = '{scala.meta.Pat.ArgClause(${Expr(y.values)})} - def liftTermParamClause(y: scala.meta.Term.ParamClause) = '{scala.meta.Term.ParamClause(${Expr(y.values)}, ${Expr(y.mod)})} - def liftTypeParamClause(y: scala.meta.Type.ParamClause) = '{scala.meta.Type.ParamClause(${Expr(y.values)})} - def liftEnumeratorGenerator(y: scala.meta.Enumerator.Generator) = '{scala.meta.Enumerator.Generator(${Expr(y.pat)}, ${Expr(y.rhs)})} - def liftEnumeratorCaseGenerator(y: scala.meta.Enumerator.CaseGenerator) = '{scala.meta.Enumerator.CaseGenerator(${Expr(y.pat)}, ${Expr(y.rhs)})} - def liftEnumeratorVal(y: scala.meta.Enumerator.Val) = '{scala.meta.Enumerator.Val(${Expr(y.pat)}, ${Expr(y.rhs)})} - def liftCase(y: scala.meta.Case) = '{scala.meta.Case(${Expr(y.pat)}, ${Expr(y.cond)}, ${Expr(y.body)})} - def liftTypeCase(y: scala.meta.TypeCase) = '{scala.meta.TypeCase(${Expr(y.pat)}, ${Expr(y.body)})} - def liftTypeParam(y: scala.meta.Type.Param) = '{scala.meta.Type.Param(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.tparamClause)}, ${Expr(y.tbounds)}, ${Expr(y.vbounds)}, ${Expr(y.cbounds)})} - def liftTermParam(y: scala.meta.Term.Param) = '{scala.meta.Term.Param(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.decltpe)}, ${Expr(y.default)})} - def liftSelf(y: scala.meta.Self) = '{scala.meta.Self(${Expr(y.name)}, ${Expr(y.decltpe)})} - def liftCtorPrimary(y: scala.meta.Ctor.Primary) = '{scala.meta.Ctor.Primary(${Expr(y.mods)}, ${Expr(y.name)}, ${Expr(y.paramClauses)})} - def liftModAnnot(y: scala.meta.Mod.Annot) = '{scala.meta.Mod.Annot(${Expr(y.init)})} - def liftModPrivate(y: scala.meta.Mod.Private) = '{scala.meta.Mod.Private(${Expr(y.within)})} - def liftModProtected(y: scala.meta.Mod.Protected) = '{scala.meta.Mod.Protected(${Expr(y.within)})} - def liftModFinal(y: scala.meta.Mod.Final) = '{scala.meta.Mod.Final()} - def liftModSealed(y: scala.meta.Mod.Sealed) = '{scala.meta.Mod.Sealed()} - def liftModOpen(y: scala.meta.Mod.Open) = '{scala.meta.Mod.Open()} - def liftModSuper(y: scala.meta.Mod.Super) = '{scala.meta.Mod.Super()} - def liftModOverride(y: scala.meta.Mod.Override) = '{scala.meta.Mod.Override()} - def liftModCase(y: scala.meta.Mod.Case) = '{scala.meta.Mod.Case()} - def liftModAbstract(y: scala.meta.Mod.Abstract) = '{scala.meta.Mod.Abstract()} - def liftModLazy(y: scala.meta.Mod.Lazy) = '{scala.meta.Mod.Lazy()} - def liftModValParam(y: scala.meta.Mod.ValParam) = '{scala.meta.Mod.ValParam()} - def liftModVarParam(y: scala.meta.Mod.VarParam) = '{scala.meta.Mod.VarParam()} - def liftModInfix(y: scala.meta.Mod.Infix) = '{scala.meta.Mod.Infix()} - def liftModInline(y: scala.meta.Mod.Inline) = '{scala.meta.Mod.Inline()} - def liftModOpaque(y: scala.meta.Mod.Opaque) = '{scala.meta.Mod.Opaque()} - def liftModTransparent(y: scala.meta.Mod.Transparent) = '{scala.meta.Mod.Transparent()} - def liftModErased(y: scala.meta.Mod.Erased) = '{scala.meta.Mod.Erased()} - def liftModImplicit(y: scala.meta.Mod.Implicit) = '{scala.meta.Mod.Implicit()} - def liftModUsing(y: scala.meta.Mod.Using) = '{scala.meta.Mod.Using()} - def liftModCovariant(y: scala.meta.Mod.Covariant) = '{scala.meta.Mod.Covariant()} - def liftModContravariant(y: scala.meta.Mod.Contravariant) = '{scala.meta.Mod.Contravariant()} - def liftEnumeratorGuard(y: scala.meta.Enumerator.Guard) = '{scala.meta.Enumerator.Guard(${Expr(y.cond)})} + def liftDefnEnumCase(y: scala.meta.Defn.EnumCase) = makeByMode('{scala.meta.Defn.EnumCase.After_4_6_0}, term(y.mods), term(y.name), term(y.tparamClause), term(y.ctor), term(y.inits)) + def liftDefnRepeatedEnumCase(y: scala.meta.Defn.RepeatedEnumCase) = makeByMode('{scala.meta.Defn.RepeatedEnumCase.Initial}, term(y.mods), term(y.cases)) + def liftDefnGivenAlias(y: scala.meta.Defn.GivenAlias) = makeByMode('{scala.meta.Defn.GivenAlias.After_4_6_0}, term(y.mods), term(y.name), term(y.paramClauseGroup), term(y.decltpe), term(y.body)) + // makeByMode('{scala.meta.Decl.Def.After_4_7_3}, term(y.mods), term(y.name), term(y.paramClauseGroups), term(y.decltpe)) + def liftDefnDef(y: scala.meta.Defn.Def) = makeByMode('{scala.meta.Defn.Def.After_4_7_3}, term(y.mods), term(y.name), term(y.paramClauseGroups), term(y.decltpe), term(y.body)) + def liftDefnMacro(y: scala.meta.Defn.Macro) = makeByMode('{scala.meta.Defn.Macro.After_4_7_3}, term(y.mods), term(y.name), term(y.paramClauseGroups), term(y.decltpe), term(y.body)) + def liftDefnType(y: scala.meta.Defn.Type) = makeByMode('{scala.meta.Defn.Type.After_4_6_0}, term(y.mods), term(y.name), term(y.tparamClause), term(y.body), term(y.bounds)) + def liftDefnExtensionGroup(y: scala.meta.Defn.ExtensionGroup) = makeByMode('{scala.meta.Defn.ExtensionGroup.After_4_6_0}, term(y.paramClauseGroup), term(y.body)) + def liftImport(y: scala.meta.Import) = makeByMode('{scala.meta.Import.Initial}, term(y.importers)) + def liftExport(y: scala.meta.Export) = makeByMode('{scala.meta.Export.Initial}, term(y.importers)) + def liftTermArgClause(y: scala.meta.Term.ArgClause) = makeByMode('{scala.meta.Term.ArgClause.Initial}, term(y.values), term(y.mod)) + def liftTypeArgClause(y: scala.meta.Type.ArgClause) = makeByMode('{scala.meta.Type.ArgClause.Initial}, term(y.values)) + def liftPatArgClause(y: scala.meta.Pat.ArgClause) = makeByMode('{scala.meta.Pat.ArgClause.Initial}, term(y.values)) + def liftTermParamClause(y: scala.meta.Term.ParamClause) = makeByMode('{scala.meta.Term.ParamClause.Initial}, term(y.values), term(y.mod)) + def liftTypeParamClause(y: scala.meta.Type.ParamClause) = makeByMode('{scala.meta.Type.ParamClause.Initial}, term(y.values)) + def liftEnumeratorGenerator(y: scala.meta.Enumerator.Generator) = makeByMode('{scala.meta.Enumerator.Generator.Initial}, term(y.pat), term(y.rhs)) + def liftEnumeratorCaseGenerator(y: scala.meta.Enumerator.CaseGenerator) = makeByMode('{scala.meta.Enumerator.CaseGenerator.Initial}, term(y.pat), term(y.rhs)) + def liftEnumeratorVal(y: scala.meta.Enumerator.Val) = makeByMode('{scala.meta.Enumerator.Val.Initial}, term(y.pat), term(y.rhs)) + def liftCase(y: scala.meta.Case) = makeByMode('{scala.meta.Case.Initial}, term(y.pat), term(y.cond), term(y.body)) + def liftTypeCase(y: scala.meta.TypeCase) = makeByMode('{scala.meta.TypeCase.Initial}, term(y.pat), term(y.body)) + def liftTypeParam(y: scala.meta.Type.Param) = makeByMode('{scala.meta.Type.Param.After_4_6_0}, term(y.mods), term(y.name), term(y.tparamClause), term(y.tbounds), term(y.vbounds), term(y.cbounds)) + def liftTermParam(y: scala.meta.Term.Param) = makeByMode('{scala.meta.Term.Param.Initial}, term(y.mods), term(y.name), term(y.decltpe), term(y.default)) + def liftSelf(y: scala.meta.Self) = makeByMode('{scala.meta.Self.Initial}, term(y.name), term(y.decltpe)) + def liftCtorPrimary(y: scala.meta.Ctor.Primary) = makeByMode('{scala.meta.Ctor.Primary.After_4_6_0}, term(y.mods), term(y.name), term(y.paramClauses)) + def liftModAnnot(y: scala.meta.Mod.Annot) = makeByMode('{scala.meta.Mod.Annot.Initial}, term(y.init)) + def liftModPrivate(y: scala.meta.Mod.Private) = makeByMode('{scala.meta.Mod.Private.Initial}, term(y.within)) + def liftModProtected(y: scala.meta.Mod.Protected) = makeByMode('{scala.meta.Mod.Protected.Initial}, term(y.within)) + def liftModFinal(y: scala.meta.Mod.Final) = makeByMode('{scala.meta.Mod.Final}) + def liftModSealed(y: scala.meta.Mod.Sealed) = makeByMode('{scala.meta.Mod.Sealed}) + def liftModOpen(y: scala.meta.Mod.Open) = makeByMode('{scala.meta.Mod.Open}) + def liftModSuper(y: scala.meta.Mod.Super) = makeByMode('{scala.meta.Mod.Super}) + def liftModOverride(y: scala.meta.Mod.Override) = makeByMode('{scala.meta.Mod.Override}) + def liftModCase(y: scala.meta.Mod.Case) = makeByMode('{scala.meta.Mod.Case}) + def liftModAbstract(y: scala.meta.Mod.Abstract) = makeByMode('{scala.meta.Mod.Abstract}) + def liftModLazy(y: scala.meta.Mod.Lazy) = makeByMode('{scala.meta.Mod.Lazy}) + def liftModValParam(y: scala.meta.Mod.ValParam) = makeByMode('{scala.meta.Mod.ValParam}) + def liftModVarParam(y: scala.meta.Mod.VarParam) = makeByMode('{scala.meta.Mod.VarParam}) + def liftModInfix(y: scala.meta.Mod.Infix) = makeByMode('{scala.meta.Mod.Infix}) + def liftModInline(y: scala.meta.Mod.Inline) = makeByMode('{scala.meta.Mod.Inline}) + def liftModOpaque(y: scala.meta.Mod.Opaque) = makeByMode('{scala.meta.Mod.Opaque}) + def liftModTransparent(y: scala.meta.Mod.Transparent) = makeByMode('{scala.meta.Mod.Transparent}) + def liftModErased(y: scala.meta.Mod.Erased) = makeByMode('{scala.meta.Mod.Erased}) + def liftModImplicit(y: scala.meta.Mod.Implicit) = makeByMode('{scala.meta.Mod.Implicit}) + def liftModUsing(y: scala.meta.Mod.Using) = makeByMode('{scala.meta.Mod.Using}) + def liftModCovariant(y: scala.meta.Mod.Covariant) = makeByMode('{scala.meta.Mod.Covariant}) + def liftModContravariant(y: scala.meta.Mod.Contravariant) = makeByMode('{scala.meta.Mod.Contravariant}) + def liftEnumeratorGuard(y: scala.meta.Enumerator.Guard) = makeByMode('{scala.meta.Enumerator.Guard.Initial}, term(y.cond)) // Apparently the order here is important - def liftableSubTree0[T <: MetaTree](y: T)(using Quotes): Expr[T] = { - val expr = y match { + def liftableSubTree0[T <: MetaTree](y: T)(using Quotes): Tree = { + y match { case (y @ (_: scala.meta.internal.trees.Quasi)) => liftQuasi(y.asInstanceOf[scala.meta.internal.trees.Quasi]) case (y @ (_: scala.meta.Type.FuncParamClause)) => liftTypeFuncParamClause(y.asInstanceOf[scala.meta.Type.FuncParamClause]) case (y @ (_: scala.meta.Type.Bounds)) => liftTypeBounds(y.asInstanceOf[scala.meta.Type.Bounds]) @@ -510,6 +509,5 @@ trait ExprLifts(using Quotes) extends ReificationMacros with InternalTrait { case (y @ (_: scala.meta.Enumerator.Guard)) => liftEnumeratorGuard(y.asInstanceOf[scala.meta.Enumerator.Guard]) case _ => sys.error("none of leafs matched " + (y.getClass)) } - expr.asInstanceOf[Expr[T]] } } \ No newline at end of file diff --git a/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/QuasiquoteType.scala b/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/QuasiquoteType.scala index 6533f95e86..d52af78be4 100644 --- a/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/QuasiquoteType.scala +++ b/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/QuasiquoteType.scala @@ -1,4 +1,19 @@ package scala.meta private[meta] enum QuasiquoteType: - case Q, P, T \ No newline at end of file + 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 \ No newline at end of file diff --git a/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ReificationMacros.scala b/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ReificationMacros.scala index 2ae7537740..5754373f78 100644 --- a/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ReificationMacros.scala +++ b/quasiquotes3/shared/src/main/scala/scala/meta/internal/quasiquotes/ReificationMacros.scala @@ -2,9 +2,6 @@ package scala.meta package internal package quasiquotes -import scala.runtime.ScalaRunTime -import scala.language.implicitConversions -import scala.collection.mutable import org.scalameta._ import org.scalameta.adt.{Liftables => AdtLiftables} import org.scalameta.invariants._ @@ -17,63 +14,95 @@ import scala.meta.internal.trees._ import scala.meta.internal.trees.{Liftables => AstLiftables, Reflection => AstReflection} import scala.meta.internal.parsers.Messages import scala.meta.internal.parsers.Absolutize._ -import scala.compat.Platform.EOL -import scala.meta.quasiquotes.Qunapply -import scala.meta.quasiquotes.q +import scala.meta.quasiquotes._ +import scala.runtime.ScalaRunTime +import scala.language.implicitConversions +import scala.collection.mutable +import scala.compat.Platform.EOL import scala.quoted._ object ReificationMacros { - def quasiquoteImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]], dialectExpr: Expr[Dialect]): Expr[Any] = - new ReificationMacros().expandApply(scExpr, argsExpr, dialectExpr, QuasiquoteType.Q) - def typeImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]], dialectExpr: Expr[Dialect]) = - new ReificationMacros().expandApply(scExpr, argsExpr, dialectExpr, QuasiquoteType.T) - def caseOrPatternImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]], dialectExpr: Expr[Dialect]) = - new ReificationMacros().expandApply(scExpr, argsExpr, dialectExpr, QuasiquoteType.P) + def termImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]) = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.Term).asExprOf[scala.meta.Tree] + def termParamImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]) = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.TermParam).asExprOf[scala.meta.Term.Param] + def typeImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]) = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.Type).asExprOf[scala.meta.Type] + def typeParamImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]) = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.TypeParam).asExprOf[scala.meta.Type.Param] + def caseOrPatternImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]): Expr[scala.meta.Tree] = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.CaseOrPattern).asExprOf[scala.meta.Tree] + def initImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]): Expr[scala.meta.Init] = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.Init).asExprOf[scala.meta.Init] + def selfImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]): Expr[scala.meta.Self] = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.Self).asExprOf[scala.meta.Self] + def templateImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]): Expr[scala.meta.Template] = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.Template).asExprOf[scala.meta.Template] + def modImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]): Expr[scala.meta.Mod] = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.Mod).asExprOf[scala.meta.Mod] + def enumeratorImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]): Expr[scala.meta.Enumerator] = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.Enumerator).asExprOf[scala.meta.Enumerator] + def importerImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]): Expr[scala.meta.Importer] = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.Importer).asExprOf[scala.meta.Importer] + def importeeImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]): Expr[scala.meta.Importee] = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.Importee).asExprOf[scala.meta.Importee] + def sourceImpl(using Quotes)(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]): Expr[scala.meta.Source] = + new ReificationMacros().expandApply(scExpr, argsExpr, QuasiquoteType.Source).asExprOf[scala.meta.Source] - - def unapplyQuasiquoteImpl(using Quotes)(qtodoExpr: Expr[Qunapply], argsExpr: Expr[Any], dialectExpr: Expr[Dialect]): Expr[Option[Seq[Any]]] = - val scExpr: Expr[StringContext] = - qtodoExpr match - case '{ ($stringContext: StringContext).q } => stringContext - case _ => quotes.reflect.report.errorAndAbort("Expected call to extension method `q(StringContext)`") - new ReificationMacros().expandUnapply(scExpr, argsExpr, dialectExpr, QuasiquoteType.Q) + def unapplyImpl(using Quotes)(scCallExpr: Expr[QuasiquoteUnapply], scrutineeExpr: Expr[Any]): Expr[Option[Seq[Any]]] = + val (stringContext, quasiquoteType) = scCallExpr match + case '{ ($sc: StringContext).q } => (sc, QuasiquoteType.Term) + case '{ ($sc: StringContext).param } => (sc, QuasiquoteType.TermParam) + case '{ ($sc: StringContext).t } => (sc, QuasiquoteType.Type) + case '{ ($sc: StringContext).tparam } => (sc, QuasiquoteType.TypeParam) + case '{ ($sc: StringContext).p } => (sc, QuasiquoteType.CaseOrPattern) + case '{ ($sc: StringContext).init } => (sc, QuasiquoteType.Init) + case '{ ($sc: StringContext).self } => (sc, QuasiquoteType.Self) + case '{ ($sc: StringContext).template } => (sc, QuasiquoteType.Template) + case '{ ($sc: StringContext).mod } => (sc, QuasiquoteType.Mod) + case '{ ($sc: StringContext).enumerator } => (sc, QuasiquoteType.Enumerator) + case '{ ($sc: StringContext).importer } => (sc, QuasiquoteType.Importer) + case '{ ($sc: StringContext).importee } => (sc, QuasiquoteType.Importee) + case '{ ($sc: StringContext).source } => (sc, QuasiquoteType.Source) + case _ => quotes.reflect.report.errorAndAbort("Expected call to quasiquote extension method. ") + new ReificationMacros().expandUnapply(stringContext, scrutineeExpr, quasiquoteType) } -class ReificationMacros(using val quotes: Quotes) { - import quotes.reflect._ - import scala.meta.{Tree => MetaTree, Dialect => Dialect} +class ReificationMacros(using val topLevelQuotes: Quotes) { rei => + import topLevelQuotes.reflect._ + import scala.meta.{Tree => MetaTree, Dialect} import scala.meta.inputs.{Position => MetaPosition, _} type MetaParser = (Input, Dialect) => MetaTree - lazy val RootPackage = quotes.reflect.Symbol.classSymbol("_root_") + lazy val RootPackage = topLevelQuotes.reflect.Symbol.classSymbol("_root_") private sealed trait Mode { def isTerm: Boolean = this.isInstanceOf[Mode.Term] def isPattern: Boolean = this.isInstanceOf[Mode.Pattern] def multiline: Boolean - def holes: List[Hole] } private object Mode { - case class Term(multiline: Boolean, holes: List[Hole]) extends Mode - case class Pattern(multiline: Boolean, holes: List[Hole], unapplySelector: Expr[Any]) extends Mode + case class Term(multiline: Boolean, holes: List[TermHole]) extends Mode + case class Pattern(multiline: Boolean, holes: List[PatternHole], unapplySelector: Expr[Any]) extends Mode } - private case class Hole(name: String, arg: Term, var reifier: Option[Term]) + private case class TermHole(name: String, arg: Term, var reifier: Option[Term]) + private case class PatternHole(name: String, posStart: Int, posEnd: Int, tpe: Option[TypeRepr], var symbol: Option[Symbol], var reifier: Option[Term]) lazy val ListClass = TypeRepr.of[scala.List] - def expandUnapply(strCtx: Expr[StringContext], unapplySelector: Expr[Any], dialectExpr: Expr[Dialect], qType: QuasiquoteType): Expr[Option[Seq[Any]]] = { + def expandUnapply(strCtx: Expr[StringContext], unapplySelector: Expr[Any], qType: QuasiquoteType): Expr[Option[Seq[Any]]] = { val mode = extractModePattern(strCtx, unapplySelector) - expand(strCtx, dialectExpr, qType, mode).asExprOf[Option[Seq[Any]]] + expand(strCtx, qType, mode).asExprOf[Option[Seq[Any]]] } - def expandApply(strCtx: Expr[StringContext], args: Expr[Seq[Any]], dialectExpr: Expr[Dialect], qType: QuasiquoteType): Expr[Any] = { + def expandApply(strCtx: Expr[StringContext], args: Expr[Seq[Any]], qType: QuasiquoteType): Expr[Any] = { val mode = extractModeTerm(strCtx, args) - expand(strCtx, dialectExpr, qType, mode) + expand(strCtx, qType, mode) } - private def expand(strCtx: Expr[StringContext], dialectExpr: Expr[Dialect], qType: QuasiquoteType, mode: Mode) = { + private def expand(strCtx: Expr[StringContext], qType: QuasiquoteType, mode: Mode) = { val input = metaInput() - val dialect = instantiateDialect(dialectExpr, mode) + val dialect = instantiateDialect(mode) val parser = instantiateParser(qType) val skeleton = parseSkeleton(parser, input, dialect) reifySkeleton(skeleton, mode, qType) @@ -82,41 +111,67 @@ class ReificationMacros(using val quotes: Quotes) { private def metaInput() = { val pos = Position.ofMacroExpansion val reflectInput = pos.sourceFile - val start = pos.start + 2 - val end = pos.end - 1 - val metaInput = Input.VirtualFile(reflectInput.path, new String(reflectInput.content.get)) + val content = new String(reflectInput.content.get) + val start = { + var i = 0 + while (content(pos.start + i) != '"') i += 1 // skip method name + while (content(pos.start + i) == '"') i += 1 // skip quotations + pos.start + i + } + val end = { + var i = 0 + while (content(pos.end - 1 - i) == '"') i += 1 // skip quotations + pos.end - i + } + val metaInput = Input.VirtualFile(reflectInput.path, content) Input.Slice(metaInput, start, end) } private def extractModeTerm(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]]): Mode = { val pos = Position.ofMacroExpansion - def isMultiline() = { - pos.startLine != pos.endLine - } + def isMultiline() = pos.startLine != pos.endLine def mkHole(argi: (Expr[Any], Int)) = { val (arg, i) = argi val name = "quasiquote" + "$hole$" + i - Hole(name, arg.asTerm, reifier = None) + TermHole(name, arg.asTerm, reifier = None) } - val Varargs(args) = argsExpr + val Varargs(args) = argsExpr: @unchecked val holes = args.zipWithIndex.map(mkHole) Mode.Term(isMultiline(), holes.toList) } private def extractModePattern(strCtxExpr: Expr[StringContext], selectorExpr: Expr[Any]): Mode = { + val '{StringContext(${Varargs(parts)}: _*)} = strCtxExpr: @unchecked val pos = Position.ofMacroExpansion - def isMultiline() = { - pos.startLine != pos.endLine - } - def mkHole(argi: (Expr[Any], Int)) = { - val (arg, i) = argi + + // EXPERIMENT: Workaround mechanism for getting type declarations from unapply pattern. + // Only works for `val q"${: T}" = (...)`, does nothing for pattern matching cases. + // Even then, it stops working if macro entry method is a transparent inline method (which we want to have). + val argTypes: Option[List[TypeRepr]] = None + // try + // Symbol.spliceOwner.owner.owner.owner.tree match + // case ValDef(_, tpe, Some(Match(_, List(CaseDef(Unapply(Select(Block(List(typeDef), _), "unapplySeq"), _, _), _, _))))) if typeDef == Symbol.spliceOwner.owner.owner.tree => + // if parts.length > 2 then + // tpe.tpe match + // case AppliedType(tuple, lst) => Some(lst) + // else + // Some(List(tpe.tpe)) + // case _ => None + // catch + // case _ => None + + def isMultiline() = pos.startLine != pos.endLine + def mkHole(i: Int) = { val name = "quasiquote" + "$hole$" + i - Hole(name, arg.asTerm, reifier = None) + val posStart = parts(i).asTerm.pos.end + val posEnd = parts(i + 1).asTerm.pos.start + val argType = argTypes.map(_(i)) + PatternHole(name, posStart, posEnd, argType, None, None) } - Mode.Pattern(isMultiline(), List(mkHole(selectorExpr, 0)), selectorExpr) // probably incorrect + Mode.Pattern(isMultiline(), List.range(0, parts.length - 1).map(mkHole(_)), selectorExpr) } - private def instantiateDialect(dialectExpr: Expr[Dialect], mode: Mode): Dialect = { + private def instantiateDialect(mode: Mode): Dialect = { // NOTE: We want to have a higher-order way to abstract over differences in dialects // and we're using implicits for that (implicits are values => values are higher-order => good). // @@ -130,18 +185,22 @@ class ReificationMacros(using val quotes: Quotes) { // delaying validation of resulting ASTs until runtime. val underlyingDialect = { def instantiateStandardDialect(sym: Symbol): Option[Dialect] = { - val dialectsSym = Symbol.classSymbol("scala.meta.dialects.package$") - if (dialectsSym != sym.owner) return None - if (dialectsSym.methodMember(sym.name) == Symbol.noSymbol) return None // TODO Seems redundant ?? - Dialect.standards.get(sym.name.toString) + val dialectsSym = Symbol.classSymbol("scala.meta.dialects.package$").companionModule + if (dialectsSym == sym.owner.companionModule) { + if (dialectsSym.methodMember(sym.name).isEmpty) None + else Dialect.standards.get(sym.name) + } else None } - val standardDialectSingleton = instantiateStandardDialect(dialectExpr.asTerm.tpe.termSymbol) + + val dialectExpr = Expr.summon[scala.meta.Dialect] + val standardDialectSingleton = dialectExpr.flatMap(expr => instantiateStandardDialect(expr.asTerm.tpe.termSymbol)) + standardDialectSingleton .getOrElse({ val suggestion = s"to fix this, import something from scala.meta.dialects, e.g. scala.meta.dialects.${Dialect.current}" val message = - s"${dialectExpr.show} of type ${dialectExpr.asTerm.tpe.show} is not supported by quasiquotes ($suggestion)" + s"${dialectExpr.get.show} of type ${dialectExpr.get.asTerm.tpe.show} is not supported by quasiquotes ($suggestion)" report.errorAndAbort(message) }) } @@ -149,11 +208,7 @@ class ReificationMacros(using val quotes: Quotes) { else dialects.QuasiquotePat(underlyingDialect, mode.multiline) } private def instantiateParser(qType: QuasiquoteType): MetaParser = { - val parserModule = - qType match - case QuasiquoteType.Q => Symbol.classSymbol("scala.meta.quasiquotes.Api.XTensionQuasiquoteTerm") - case QuasiquoteType.T => Symbol.classSymbol("scala.meta.quasiquotes.Api.XTensionQuasiquoteType") - case QuasiquoteType.P => Symbol.classSymbol("scala.meta.quasiquotes.Api.XTensionQuasiquoteCaseOrPattern") + val parserModule = Symbol.classSymbol(qType.parserClass()) val parsersModuleClass = Class.forName("scala.meta.quasiquotes.package$", true, this.getClass.getClassLoader) val parsersModule = parsersModuleClass.getField("MODULE$").get(null) @@ -170,30 +225,37 @@ class ReificationMacros(using val quotes: Quotes) { try { parser(input, dialect) } catch { - case TokenizeException(pos, message) => report.errorAndAbort(message) // todo set correct position - case ParseException(pos, message) => report.errorAndAbort(message) // todo set correct position + case TokenizeException(pos, message) => report.errorAndAbort(message) + case ParseException(pos, message) => report.errorAndAbort(message) } } private def reifySkeleton(meta: MetaTree, mode: Mode, qType: QuasiquoteType): Expr[Any] = { val pendingQuasis = mutable.Stack[Quasi]() - object Internal extends InternalTrait with ExprLifts { - def liftTree(tree: MetaTree)(using Quotes): Expr[Any] = { - this.liftableSubTree(tree) + object Internal extends InternalTrait with ExprLifts(using quotes)(mode.isPattern) { + import internalQuotes.reflect._ + def liftTree(tree: MetaTree): internalQuotes.reflect.Tree = { + this.liftableSubTree0(tree).asInstanceOf[internalQuotes.reflect.Tree] } - def liftOptionTree(maybeTree: Option[MetaTree]): Expr[Option[Any]] = { + def liftOptionTree[T: Type](maybeTree: Option[MetaTree]): internalQuotes.reflect.Tree = { maybeTree match { - case Some(tree: Quasi) => liftQuasi0(tree, optional = true).asExprOf[Option[Any]] - case Some(otherTree) => '{Some(${liftTree(otherTree)})} - case None => '{None} + case Some(tree: Quasi) => liftQuasi0(tree, optional = true) + case Some(otherTree) => + if mode.isTerm then Apply(TypeApply(Select.unique('{scala.Some}.asTerm, "apply"), List(TypeTree.of[T])), List(liftTree(otherTree).asInstanceOf[Term])) + else + Unapply(TypeApply(Select.unique(Ref(Symbol.classSymbol("scala.Some").companionModule), "unapply"), List(TypeTree.of[T])), Nil, List(liftTree(otherTree))) + + case None => + '{scala.None}.asTerm match + case Inlined(_, _, none) => none } } - def liftTrees[T: Type](trees: Seq[MetaTree])(using Quotes): Expr[List[Any]] = { + def liftTrees[T: Type](trees: Seq[MetaTree]): Tree = { @tailrec - def loop(trees: Seq[MetaTree], acc: Option[Expr[List[Any]]], prefix: List[MetaTree]): Expr[List[Any]] = + def loop(trees: Seq[MetaTree], acc: Option[Tree], prefix: List[MetaTree]): Tree = trees match { case (quasi: Quasi) +: rest if quasi.rank == 1 => if (acc.isEmpty) { - if (prefix.isEmpty) loop(rest, Some(liftQuasi(quasi).asExprOf[List[Any]]), Nil) + if (prefix.isEmpty) loop(rest, Some(liftQuasi0(quasi)), Nil) else loop( rest, @@ -204,96 +266,103 @@ class ReificationMacros(using val quotes: Quotes) { // because that still wouldn't work in pattern mode. // Finally, we can't do something like q"+:(${liftQuasi(quasi)}, (${liftTree(curr)}))", // because would violate evaluation order guarantees that we must keep. - val currElement = liftTree(curr).asExprOf[T] - val alreadyLiftedList = acc.getOrElse(liftQuasi(quasi)).asExprOf[List[T]] - if (mode.isTerm) Some('{$currElement +: $alreadyLiftedList})//q"$currElement +: $alreadyLiftedList" - else Some('{$currElement +: $alreadyLiftedList})//pq"$currElement +: $alreadyLiftedList" + val currElement = liftTree(curr) + val alreadyLiftedList = acc.getOrElse(liftQuasi(quasi)) + val tree = + if (mode.isTerm) Apply(TypeApply(Select.unique(alreadyLiftedList.asInstanceOf[Term], "+:"), List(TypeTree.of[T])), List(currElement.asInstanceOf[Term])) + else Unapply(TypeApply(Select.unique('{+:}.asTerm, "unapply"), List(TypeTree.of[T], TypeTree.of[List], TypeTree.of[List[T]])), Nil, List(currElement, alreadyLiftedList)) + Some(tree) }), Nil ) } else { - // require(prefix.isEmpty && debug(trees, acc, prefix)) - if (mode.isTerm) then - liftQuasi(quasi) match - case '{$expr: List[t]} => - loop(rest, Some('{${acc.get.asExprOf[List[t]]} ++ ${expr}}), Nil) - else report.errorAndAbort(Messages.QuasiquoteAdjacentEllipsesInPattern(quasi.rank))// TODO set position: quasi.pos + Predef.require(prefix.isEmpty && debug(trees, acc, prefix)) + if (mode.isTerm) then + val tree = Apply(TypeApply(Select.unique(acc.get.asInstanceOf[Term], "++"), List(TypeTree.of[T])), List(liftQuasi(quasi).asInstanceOf[Term])) + loop(rest, Some(tree), Nil) + else report.errorAndAbort(Messages.QuasiquoteAdjacentEllipsesInPattern(quasi.rank)) } case other +: rest => if (acc.isEmpty) loop(rest, acc, prefix :+ other) else { - // require(prefix.isEmpty && debug(trees, acc, prefix)) - if (mode.isTerm) - liftTree(other) match - case '{$expr: t} => loop(rest, Some('{${acc.get.asExprOf[List[t]]} :+ ${expr}}), Nil) - else - liftTree(other) match - case '{$expr: t} => loop(rest, Some('{${acc.get.asExprOf[List[t]]} :+ ${expr}}), Nil) //loop(rest, pq"$acc :+ ${liftTree(other)}", Nil) + Predef.require(prefix.isEmpty && debug(trees, acc, prefix)) + val otherTree = liftTree(other) + val tree = + if mode.isTerm then Apply(TypeApply(Select.unique(acc.get.asInstanceOf[Term], ":+"), List(TypeTree.of[T])), List(otherTree.asInstanceOf[Term])) + else Unapply(TypeApply(Select.unique('{:+}.asTerm, "unapply"), List(TypeTree.of[T], TypeTree.of[List], TypeTree.of[List[T]])), Nil, List(acc.get, otherTree)) + loop(rest, Some(tree), Nil) } case _ => - // NOTE: Luckily, at least this quasiquote works fine both in term and pattern modes if (acc.isEmpty) { - val args = prefix.map(liftTree(_).asExprOf[T]).toList - '{List[T](${Varargs(args)}: _*)} + val args = prefix.map(liftTree(_)).toList + val targs = List(TypeTree.of[T]) + if mode.isTerm then + Select.overloaded('{List}.asTerm, "apply", List(TypeRepr.of[T]), args.asInstanceOf[List[Term]]) + else + Unapply(TypeApply(Select.unique('{List}.asTerm, "unapplySeq"), List(TypeTree.of[T])), Nil, args) } - else acc.get.asExprOf[List[Any]] + else acc.get } loop(trees, None, Nil) } - // def liftTreess(treess: List[List[MetaTree]]): ReflectTree = { - // val tripleDotQuasis = treess.flatten.collect { - // case quasi: Quasi if quasi.rank == 2 => quasi - // } - // if (tripleDotQuasis.isEmpty) { - // Liftable.liftList[List[MetaTree]](Liftables.liftableSubTrees).apply(treess) - // } else if (tripleDotQuasis.length == 1) { - // if (treess.flatten.length == 1) liftQuasi(tripleDotQuasis(0)) - // else - // c.abort( - // tripleDotQuasis(0).pos, - // "implementation restriction: can't mix ...$ with anything else in parameter lists." + EOL + - // "See https://github.com/scalameta/scalameta/issues/406 for details." - // ) - // } else { - // c.abort(tripleDotQuasis(1).pos, Messages.QuasiquoteAdjacentEllipsesInPattern(2)) - // } - // } - def liftQuasi0(quasi: Quasi, optional: Boolean = false): Expr[Any] = { + def liftTreess(treess: List[List[MetaTree]]): Tree = { + val tripleDotQuasis = treess.flatten.collect { + case quasi: Quasi if quasi.rank == 2 => quasi + } + if (tripleDotQuasis.isEmpty) { + val args = treess.map(liftTrees) + if mode.isTerm then + Select.overloaded('{List}.asTerm, "apply", List(TypeRepr.of[Any]), args.asInstanceOf[List[Term]]) + else + Unapply(TypeApply(Select.unique('{List}.asTerm, "unapplySeq"), List(TypeTree.of[Any])), Nil, args) + } else if (tripleDotQuasis.length == 1) { + if (treess.flatten.length == 1) liftQuasi(tripleDotQuasis(0)) + else + report.errorAndAbort( + "implementation restriction: can't mix ...$ with anything else in parameter lists." + EOL + + "See https://github.com/scalameta/scalameta/issues/406 for details." + ) + } else { + report.errorAndAbort(Messages.QuasiquoteAdjacentEllipsesInPattern(2)) + } + } + def liftQuasi0(quasi: Quasi, optional: Boolean = false): Tree = { try { pendingQuasis.push(quasi) if (quasi.rank == 0) { val inferredPt = { val unwrappedPt = quasi.pt.wrap(pendingQuasis.map(_.rank).sum).toTpe - if (optional) AppliedType(TypeRepr.of[Option], List(unwrappedPt)) else unwrappedPt + if optional then + unwrappedPt.asType match + case '[t] => rei.topLevelQuotes.reflect.TypeRepr.of[Option[t]] + else unwrappedPt } val lifted = mode match { case Mode.Term(_, _) => inferredPt.asType match - case '[t] => - '{scala.meta.internal.quasiquotes.Lift[t](${quasi.hole.arg.asExpr})} - // case Mode.Pattern(_, _, _) => - // // NOTE: Here, we would like to say q"$InternalUnlift[$inferredPt](${quasi.hole.arg})". - // // Unfortunately, the way how patterns work prevents us from having it this easy: - // // 1) unapplications can't have explicitly specified type arguments - // // 2) pattern language is very limited and can't express what we want to express in Unlift - // // Therefore, we're forced to take a two-step unquoting scheme: a) match everything in the corresponding hole, - // // b) call Unlift.unapply as a normal method in the right-hand side part of the pattern matching clause. - // val hole = quasi.hole - // val unliftedPt = hole.arg match { - // case pq"_: $explicitPt" => explicitPt - // case pq"$_: $explicitPt" => explicitPt - // case _ => TypeTree(inferredPt) - // } - // hole.reifier = - // atPos(quasi.pos)(q"$InternalUnlift.unapply[$unliftedPt](${hole.name})") - // pq"${hole.name}" + case '[t] => '{scala.meta.internal.quasiquotes.Lift[t](${quasi.termHole.arg.asExpr})}.asTerm + case Mode.Pattern(_, _, _) => + // NOTE: Here, we would like to say q"$InternalUnlift[$inferredPt](${quasi.hole.arg})". + // Unfortunately, the way how patterns work prevents us from having it this easy: + // 1) unapplications can't have explicitly specified type arguments + // 2) pattern language is very limited and can't express what we want to express in Unlift + // Therefore, we're forced to take a two-step unquoting scheme: a) match everything in the corresponding hole, + // b) call Unlift.unapply as a normal method in the right-hand side part of the pattern matching clause. + val hole = quasi.patternHole + val symbol = Symbol.newBind(Symbol.spliceOwner, hole.name, Flags.EmptyFlags, inferredPt.asInstanceOf[TypeRepr]) + val reifier = + hole.tpe match + case Some(tpe) => Select.overloaded('{scala.meta.internal.quasiquotes.Unlift}.asTerm, "unapply", List(tpe.asInstanceOf[TypeRepr]), List(Ref(symbol))) + case None => Select.overloaded('{scala.meta.internal.quasiquotes.Unlift}.asTerm, "unapply", List(inferredPt.asInstanceOf[TypeRepr]), List(Ref(symbol))) + hole.symbol = Some(symbol).asInstanceOf[Option[rei.topLevelQuotes.reflect.Symbol]] + hole.reifier = Some(reifier).asInstanceOf[Option[rei.topLevelQuotes.reflect.Term]] + Bind(symbol, Wildcard()) } - // atPos(quasi.pos)(lifted) lifted } else { quasi.tree match { - case quasi: Quasi if quasi.rank == 0 => liftQuasi(quasi) - case _ => report.errorAndAbort("complex ellipses are not supported yet") //c.abort(quasi.pos, "complex ellipses are not supported yet") + case quasi: Quasi if quasi.rank == 0 => liftQuasi0(quasi) + case _ => report.errorAndAbort("complex ellipses are not supported yet") } } } finally { @@ -301,12 +370,12 @@ class ReificationMacros(using val quotes: Quotes) { } } - // TODO // Depending on pattern types, this is able to cause some custom errors to be thrown - // I do not think this is possible to port to scala 3. + // We cannot obtain the types of the pattern in Scala 3 for now protected def unquotesName(q: scala.meta.internal.trees.Quasi): Boolean = { - val tpe = q.hole.arg.tpe - tpe != (null) && tpe <:< (TypeRepr.of[scala.meta.Term.Name]) + // val tpe = q.hole.arg.tpe // works for TermMode + // tpe != (null) && tpe <:< (TypeRepr.of[scala.meta.Term.Name]) + false } } @@ -329,73 +398,117 @@ class ReificationMacros(using val quotes: Quotes) { } } } - // private implicit class XtensionRankedTree(tree: quotes.reflect.TypeRepr) { - // def wrap(rank: Int): TypeRepr = { - // if (rank == 0) tree - // else AppliedType(ListClass, List(tree.wrap(rank - 1))) //AppliedTypeTree(tq"$ListClass", List(tree.wrap(rank - 1))) - // } - // } implicit class XtensionQuasiHole(quasi: scala.meta.internal.trees.Quasi) { import quotes.reflect._ - def hole: Hole = { - val pos = quasi.pos.absolutize // hmm - val maybeHole = - mode.holes.find(h => pos.start <= h.arg.pos.start && h.arg.pos.start <= pos.end) - maybeHole.getOrElse( - //unreachable(debug(quasi, quasi.pos.absolutize, mode.holes, mode.holes.map(_.arg.pos))) - report.errorAndAbort("OOO") - ) + def termHole: TermHole = { + val pos = quasi.pos.absolutize + (mode: @unchecked) match + case Mode.Term(_, holes) => + val maybeHole = + holes.find(h => pos.start <= h.arg.pos.start && h.arg.pos.start <= pos.end) + maybeHole.getOrElse{ + val message = "this code path should've been unreachable" + val relevantValues = + s""" + |quasi = ${quasi} + |quasi.pos.absolutize = ${quasi.pos.absolutize} + |holes = ${holes} + |""".stripMargin + throw new UnreachableError(message + relevantValues) + } + } + def patternHole: PatternHole = { + val pos = quasi.pos.absolutize + (mode: @unchecked) match + case Mode.Pattern(_, holes, _) => + val maybeHole = + holes.find(h => pos.start <= h.posStart && h.posStart <= pos.end) + maybeHole.getOrElse{ + val message = "this code path should've been unreachable" + val relevantValues = + s""" + |quasi = ${quasi} + |quasi.pos.absolutize = ${quasi.pos.absolutize} + |holes = ${holes} + |""".stripMargin + throw new UnreachableError(message + relevantValues) + } } } mode match { case Mode.Term(_, _) => - val internalResult = Internal.liftTree(meta) + val internalResult = Internal.liftTree(meta).asInstanceOf[Term].asExpr if (sys.props("quasiquote.debug") != null) { println(internalResult) // println(showRaw(internalResult)) } val resType = qType match - case QuasiquoteType.Q => TypeRepr.of[scala.meta.Tree] - case QuasiquoteType.T => TypeRepr.of[scala.meta.Type] - case QuasiquoteType.P => TypeRepr.of[scala.meta.Tree] - val a = resType.asType match + case QuasiquoteType.Term => TypeRepr.of[scala.meta.Tree] + case QuasiquoteType.TermParam => TypeRepr.of[scala.meta.Term.Param] + case QuasiquoteType.Type => TypeRepr.of[scala.meta.Type] + case QuasiquoteType.TypeParam => TypeRepr.of[scala.meta.Type.Param] + case QuasiquoteType.CaseOrPattern => TypeRepr.of[scala.meta.Tree] + case QuasiquoteType.Init => TypeRepr.of[scala.meta.Init] + case QuasiquoteType.Self => TypeRepr.of[scala.meta.Self] + case QuasiquoteType.Template => TypeRepr.of[scala.meta.Template] + case QuasiquoteType.Mod => TypeRepr.of[scala.meta.Mod] + case QuasiquoteType.Enumerator => TypeRepr.of[scala.meta.Enumerator] + case QuasiquoteType.Importer => TypeRepr.of[scala.meta.Importer] + case QuasiquoteType.Importee => TypeRepr.of[scala.meta.Importee] + case QuasiquoteType.Source => TypeRepr.of[scala.meta.Source] + resType.asType match + case '[t] => '{scala.meta.internal.quasiquotes.Unlift[t]($internalResult)} + + case Mode.Pattern(_, holes, unapplySelector) => + import Internal.internalQuotes.reflect._ + + val pattern = Internal.liftTree(meta) + + val args = holes.map(hole => hole.reifier.get.asInstanceOf[Term]) + val argsContents = args.flatMap { _.tpe match + case AppliedType(tpe, content) if tpe =:= TypeRepr.of[Option] => content + } + val lst = Select.overloaded('{List}.asTerm, "apply", List(TypeRepr.of[Option[Any]]), args).asExprOf[List[Option[Any]]] + val returned = Select.overloaded('{List}.asTerm, "apply", List(TypeRepr.of[Any]), args.map(arg => '{${arg.asExprOf[Option[Any]]}.get}.asTerm)).asExpr + + //// TODO: for now making this produces compiler crashes, but ideally we would want to return a Tuple from transparent inline def unapply + //// (instead of returning Seq[Any] from inline def unapplySeq, like we do now). Ths would make the unapply calls correctly typed + //// (instead of always resolving to Any). + // val n = args.length + // val returned = Select.overloaded(Ref(Symbol.classSymbol("scala.Tuple" + n).companionModule), "apply", argsContents, args.map(arg => '{${arg.asExprOf[Option[Any]]}.get}.asTerm)).asExpr + returned.asTerm.tpe.asType match case '[t] => - '{scala.meta.internal.quasiquotes.Unlift[scala.meta.Tree]($internalResult)} // replace scala.meta.Tree depending on StringContext prefix - println(a.show) // TODO debug info - a - case Mode.Pattern(_, holes, unapplySelector) => ??? - // // inspired by https://github.com/densh/joyquote/blob/master/src/main/scala/JoyQuote.scala - // val pattern = Internal.liftTree(meta) - // val (thenp, elsep) = { - // if (holes.isEmpty) (q"true", q"false") - // else { - // val resultNames = holes.zipWithIndex.map({ case (_, i) => - // TermName(QuasiquotePrefix + "$result$" + i) - // }) - // val resultPatterns = resultNames.map(name => pq"_root_.scala.Some($name)") - // val resultTerms = resultNames.map(name => q"$name") - // val thenp = q""" - // (..${holes.map(_.reifier)}) match { - // case (..$resultPatterns) => _root_.scala.Some((..$resultTerms)) - // case _ => _root_.scala.None - // } - // """ - // (thenp, q"_root_.scala.None") - // } - // } - // val matchp = pattern match { - // case Bind(_, Ident(termNames.WILDCARD)) => q"input match { case $pattern => $thenp }" - // case _ => q"input match { case $pattern => $thenp; case _ => $elsep }" - // } - // val internalResult = - // q"new { def unapply(input: _root_.scala.meta.Tree) = $matchp }.unapply($unapplySelector)" - // if (sys.props("quasiquote.debug") != null) { - // println(internalResult) - // // println(showRaw(internalResult)) - // } - // internalResult + def thenp(inputExpr: Expr[Any])(using Quotes) = + import quotes.reflect._ + if (holes.isEmpty) then '{Some(List[Any]())} + else + '{ + val tpl = $lst + if tpl.toList.forall(_.asInstanceOf[Option[Any]].isDefined) then Some(${returned.asExprOf[t]}) + else None + } + def elsep(using Quotes) ='{scala.None} + + def matchp(input: Expr[Any])(using Quotes) = + Match( + input.asTerm, + List( + CaseDef(pattern, None, thenp(input).asTerm), + CaseDef(Wildcard(), None, elsep.asTerm) + ) + ).asExprOf[Option[t]] + + val internalResult ='{ ${matchp(unapplySelector)}.asInstanceOf[Option[t]] } + + if (sys.props("quasiquote.debug") != null) { + println(internalResult) + // println(showRaw(internalResult)) + } + + internalResult.asExprOf[Option[Seq[Any]]] + } } } \ No newline at end of file diff --git a/quasiquotes3/shared/src/main/scala/scala/meta/quasiquotes/Api.scala b/quasiquotes3/shared/src/main/scala/scala/meta/quasiquotes/Api.scala index 5037a2cc1f..5feb7daf7f 100644 --- a/quasiquotes3/shared/src/main/scala/scala/meta/quasiquotes/Api.scala +++ b/quasiquotes3/shared/src/main/scala/scala/meta/quasiquotes/Api.scala @@ -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 @@ -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 @@ -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 diff --git a/quasiquotes3/shared/src/test/scala/scala/meta/tests/Example.scala b/quasiquotes3/shared/src/test/scala/scala/meta/tests/Example.scala deleted file mode 100644 index b93dcf71ad..0000000000 --- a/quasiquotes3/shared/src/test/scala/scala/meta/tests/Example.scala +++ /dev/null @@ -1,102 +0,0 @@ -package scala.meta.tests -package quasiquotes - -import munit._ -import scala.meta._ -import scala.meta.dialects.Scala211 -import scala.meta.quasiquotes._ -import munit.Clue.generate -import scala.meta.trees._ - -import compat.Platform.EOL - -// import scala.meta.quasiquotes.Api._ -import meta.prettyprinters.XtensionSyntax - -class Example extends TreeSuiteBase { - test("rank-0 liftables") { - assertTree(q"foo[${42}]")(Term.ApplyType(Term.Name("foo"), List(Lit.Int(42)))) - assertTree(q"${42}")(Lit.Int(42)) - } - - test("rank-1 liftables") { - implicit def custom: Lift[List[Int], Term.ArgClause] = - Lift(lst => Term.ArgClause(lst.map(x => q"$x".asInstanceOf[Term]))) - assertTree(q"foo(..${List(1, 2, 3)})")( - Term.Apply(Term.Name("foo"), List(Lit.Int(1), Lit.Int(2), Lit.Int(3))) - ) - } - - test("construction ascriptions") { - val xs = List(q"x", q"y").asInstanceOf[List[Term]] - assertEquals(q"foo(..${xs})".syntax, "foo(x, y)") - val xss = List(List(q"x", q"y")).asInstanceOf[List[List[Term]]] - assertEquals(q"foo(...${xss})".syntax, "foo(x, y)") - val rhs = q"x".asInstanceOf[Term] - assertEquals(q"var foo = ${rhs}".syntax, "var foo = x") - } - - // test("deconstruction ascriptions") { - // val q"foo(${xs: Term}, ${ys: Term})" = q"foo(x, y)" - // assertEquals(xs.toString, "List(x, y)") - // val q"foo(...${xss: List[List[Term]]})" = q"foo(x, y)" - // assertEquals(xss.toString, "List(List(x, y))") - // val q"var foo = ${x: Term}" = q"var foo = x" - // assertEquals(x.toString, "x") - // } - - test("2 p\"case x @ y => \"") { - val x = p"x" - val y = p"List(1, 2, 3)" - assertTree(p"case $x @ $y => ")( - Case( - Pat.Bind( - Pat.Var(Term.Name("x")), - Pat.Extract(Term.Name("List"), List(Lit.Int(1), Lit.Int(2), Lit.Int(3))) - ), - None, - Term.Block(Nil) - ) - ) - } - - test("2 q\"foo(term, ..terms, term)\"") { - val term = q"x".asInstanceOf[Term] - val terms = List(q"y", q"z").asInstanceOf[List[Term]] - assertTree(q"foo($term, ..$terms, $term)")( - Term.Apply( - Term.Name("foo"), - List(Term.Name("x"), Term.Name("y"), Term.Name("z"), Term.Name("x")) - ) - ) - } - - test("2 q\"foo(x, ..ys, z, ..ts)\"") { - val x = q"1".asInstanceOf[Term] - val ys = List(q"2").asInstanceOf[List[Term]] - val z = q"3".asInstanceOf[Term] - val ts = Nil - assertTree(q"foo($x, ..$ys, $z, ..$ts)")( - Term.Apply(Term.Name("foo"), List(Lit.Int(1), Lit.Int(2), Lit.Int(3))) - ) - } - - test("2 q\"name.super[name].id\"") { - val clazz = q"A" - val tpe = t"B" - val id = q"x" - // inconsistency with the test above planned, since Name can't be constructed directly - assertTree(q"$clazz.super[$tpe].m")( - Term.Select(Term.Super(Term.Name("A"), Type.Name("B")), Term.Name("m")) - ) - } - - test("2 super variants") { - val clazz = t"C" - val tpe = t"M" - assertTree(q"super")(Term.Super(Name(""), Name(""))) - assertTree(q"super[$tpe]")(Term.Super(Name(""), Type.Name("M"))) - assertTree(q"$clazz.super")(Term.Super(Type.Name("C"), Name(""))) - assertTree(q"$clazz.super[$tpe]")(Term.Super(Type.Name("C"), Type.Name("M"))) - } -} diff --git a/quasiquotes3/shared/src/test/scala/scala/meta/tests/RoundtripSuite.scala b/quasiquotes3/shared/src/test/scala/scala/meta/tests/RoundtripSuite.scala new file mode 100644 index 0000000000..cdf99de7b9 --- /dev/null +++ b/quasiquotes3/shared/src/test/scala/scala/meta/tests/RoundtripSuite.scala @@ -0,0 +1,121 @@ +package scala.meta.tests +package quasiquotes + +import scala.meta._ +import scala.meta.dialects.Scala211 +import scala.meta.quasiquotes._ + +object RoundtripSuite { + val tree: Tree = ??? + tree match { + case q"${name: Name}.this" => q"$name.this" + case q"${name: Name}.super" => q"name.super" + case q"super[${name: Name}]" => q"super[$name]" + case q"${name1: Name}.super[${name2: Name}]" => q"$name1.super[$name2]" + case q"${name: Term.Name}" => q"${name: Term.Name}" + case q"${expr: Term}.${name: Term.Name}" => q"$expr.$name" + case q"${expr: Term}(...${exprssnel: List[Term.ArgClause]})" => q"$expr(...$exprssnel)" + case q"${expr: Term}(..${exprssnel: Term.ArgClause})" => q"$expr(..$exprssnel)" + case q"${expr: Term}[..${tpesnel: Type.ArgClause}]" => q"$expr[..$tpesnel]" + case q"${expr1: Term} ${name: Term.Name}[..${tpes: Type.ArgClause}] ${expr2: Term.Name}" => q"$expr1 $name[..$tpes] $expr2" + case q"${expr: Term.Name} ${name: Term.Name}[..${tpes: Type.ArgClause}] (..${exprs: Term.ArgClause})" => q"$expr $name[..$tpes] (..$exprs)" + case q"!${expr: Term}" => q"!$expr" + case q"~${expr: Term}" => q"~$expr" + case q"-${expr: Term}" => q"-$expr" + case q"+${expr: Term}" => q"+$expr" + case q"${ref: Term} = ${expr: Term}" => q"$ref = $expr" + case q"${expr1: Term}(...${exprssnel: List[Term.ArgClause]}) = ${expr2: Term}" => q"$expr1(...$exprssnel) = $expr2" + case q"${expr1: Term}(..${exprssnel: Term.ArgClause}) = ${expr2: Term}" => q"$expr1(..$exprssnel) = $expr2" + case q"return ${expr: Term}" => q"return $expr" + case q"throw ${expr: Term}" => q"throw $expr" + case q"${expr: Term}: ${tpe: Type}" => q"$expr: $tpe" + case q"${expr: Term}: ..@${annotsnel: List[Mod.Annot]}" => q"$expr: ..@$annotsnel" + case q"(..${exprsnel: List[Term]})" => q"(..$exprsnel)" + case q"{ ..${stats: List[Stat]} }" => q"{ ..${stats: List[Stat]} }" + case q"if (${expr1: Term}) ${expr2: Term} else ${expr3: Term}" => q"if ($expr1) $expr2 else $expr3" + case q"${expr: Term} match { ..case ${casesnel: List[Case]} }" => q"$expr match { ..case $casesnel }" + case q"try ${expr: Term} catch { ..case ${cases: List[Case]} } finally ${expropt: Option[Term]}" => + q"try $expr catch { ..case $cases } finally $expropt" + case q"try ${expr1: Term} catch ${expr2: Term} finally ${expropt: Option[Term]}" => q"try $expr1 catch $expr2 finally $expropt" + case q"(..${params: Term.ParamClause}) => ${expr: Term}" => q"(..$params) => $expr" + case q"{ ..case ${casesnel: List[Case]} }" => q"{ ..case $casesnel }" + case q"while (${expr1: Term}) ${expr2: Term}" => q"while ($expr1) $expr2" + case q"do ${expr1: Term} while(${expr2: Term})" => q"do $expr1 while($expr2)" + case q"for (..${enumeratorsnel: List[Enumerator]}) ${expr: Term}" => q"for (..$enumeratorsnel) $expr" + case q"for (..${enumeratorsnel: List[Enumerator]}) yield ${expr: Term}" => q"for (..$enumeratorsnel) yield $expr" + case q"new { ..${stat: List[Stat]} } with ..${ctorcalls: List[Init]} { ${param: Self} => ..${stats: List[Stat]} }" => + q"new { ..$stat } with ..$ctorcalls { $param => ..$stats }" + case q"${expr: Term} _" => q"$expr _" + case q"${expr: Term}: _*" => q"$expr: _*" + case q"${lit: Lit}" => q"${lit: Lit}" + case t"${name: Type.Name}" => t"${name: Type.Name}" + case t"${ref: Term.Ref}.${tname: Type.Name}" => t"$ref.$tname" + case t"${tpe: Type}#${tname: Type.Name}" => t"$tpe#$tname" + case t"${ref: Term.Ref}.type" => t"$ref.type" + case t"${tpe: Type}[..${tpesnel: Type.ArgClause}]" => t"$tpe[..$tpesnel]" + case t"${tpe1: Type} ${tname: Type.Name} ${tpe2: Type}" => t"$tpe1 $tname $tpe2" + case t"${tpe1: Type} with ${tpe2: Type}" => t"$tpe1 with $tpe2" + case t"${tpe1: Type} & ${tpe2: Type}" => t"$tpe1 & $tpe2" + case t"${tpe1: Type} | ${tpe2: Type}" => t"$tpe1 | $tpe2" + case t"(..${tpes: Type.FuncParamClause}) => ${tpe: Type}" => t"(..$tpes) => $tpe" + case t"(..${tpesnel: List[Type]})" => t"(..$tpesnel)" + case t"${tpeopt: Option[Type]} { ..${stats: List[Stat]} }" => t"$tpeopt { ..$stats }" + case t"${tpe: Type} forSome { ..${statsnel: List[Stat]} }" => t"$tpe forSome { ..$statsnel }" + case t"${tpe: Type} ..@${annotsnel: List[Mod.Annot]}" => t"$tpe ..@$annotsnel" + case t"_ >: ${tpeopt1: Option[Type]} <: ${tpeopt2: Option[Type]}" => t"_ >: $tpeopt1 <: $tpeopt2" + case t"=> ${tpe: Type}" => t"=> $tpe" + case t"${tpe: Type}*" => t"$tpe*" + case p"${pat1: Pat} @ ${pat2: Pat}" => p"$pat1 @ $pat2" + case p"${pat1: Pat} | ${pat2: Pat}" => p"$pat1 | $pat2" + case p"(..${patsnel: List[Pat]})" => p"(..$patsnel)" + case p"${ref: Term}[..${tpes: Type.ArgClause}](..${pats: Pat.ArgClause})" => p"$ref[..$tpes](..$pats)" + case p"${pat: Pat} ${name: Term.Name} (..${patsnel: Pat.ArgClause})" => p"$pat $name (..$patsnel)" + case p"${pat: Pat}: ${ptpe: Type}" => p"$pat: $ptpe" + case p"${expr: Term}.${name: Term.Name}" => p"$expr.$name" + case p"case ${pat: Pat} if ${expropt: Option[Term]} => ${expr: Term}" => p"case $pat if $expropt => $expr" + case q"import ..${importersnel: List[Importer]}" => q"import ..$importersnel" + case q"..${mods: List[Mod]} val ..${patsnel: List[Pat]}: ${tpe: Type}" => q"..$mods val ..$patsnel: $tpe" + case q"..${mods: List[Mod]} var ..${patsnel: List[Pat]}: ${tpe: Type}" => q"..$mods var ..$patsnel: $tpe" + case q"..${mods: List[Mod]} def ${name: Term.Name}[..${tparams: Type.ParamClause}](...${paramss: List[Term.ParamClause]}): ${tpe: Type}" => + q"..$mods def $name[..$tparams](...$paramss): $tpe" + case q"..${mods: List[Mod]} type ${tname: Type.Name}[..${tparams: Type.ParamClause}] >: ${tpeopt1: Option[Type]} <: ${tpeopt2: Option[Type]}" => + q"..$mods type $tname[..$tparams] >: $tpeopt1 <: $tpeopt2" + case q"..${mods: List[Mod]} val ..${patsnel: List[Pat]}: ${tpeopt: Type} = ${expr: Term}" => q"..$mods val ..$patsnel: $tpeopt = $expr" + case q"..${mods: List[Mod]} var ..${patsnel: List[Pat]}: ${tpeopt: Type} = ${expropt: Term}" => + q"..$mods var ..$patsnel: $tpeopt = $expropt" + case q"..${mods: List[Mod]} def ${name: Term.Name}[..${tparams: Type.ParamClause}](...${paramss: List[Term.ParamClause]}): ${tpeopt: Option[Type]} = ${expr: Term}" => + q"..$mods def $name[..$tparams](...$paramss): $tpeopt = $expr" + case q"..${mods: List[Mod]} def ${name: Term.Name}[..${tparams: Type.ParamClause}](...${paramss: List[Term.ParamClause]}): ${tpeopt: Option[Type]} = macro ${expr: Term}" => + q"..$mods def $name[..$tparams](...$paramss): $tpeopt = macro $expr" + case q"..${mods: List[Mod]} type ${tname: Type.Name}[..${tparams: Type.ParamClause}] = ${tpe: Type}" => + q"..$mods type $tname[..$tparams] = $tpe" + case q"..${mods: List[Mod]} class ${tname: Type.Name}[..${tparams: Type.ParamClause}] ..${ctorMods: List[Mod]} (...${paramss: List[Term.ParamClause]}) ${template: Template}" => + q"..$mods class $tname[..$tparams] ..$ctorMods (...$paramss) $template" + case q"..${mods: List[Mod]} trait ${tname: Type.Name}[..${tparams: Type.ParamClause}] ${template: Template}" => + q"..$mods trait $tname[..$tparams] $template" + case q"..${mods: List[Mod]} object ${name: Term.Name} ${template: Template}" => q"..$mods object $name $template" + case q"package object ${name: Term.Name} ${template: Template}" => q"package object $name $template" + case q"package ${ref: Term.Ref} { ..${stats: List[Stat]} }" => q"package $ref { ..$stats }" + case q"..${mods: List[Mod]} def this(...${paramss: List[Term.ParamClause]})" => q"..$mods def this(...$paramss)" + case q"..${mods: List[Mod]} def this(...${paramss: List[Term.ParamClause]}) = ${expr: Init}" => q"..$mods def this(...$paramss) = $expr" + case param"..${mods: List[Mod]} ${paramname: Name}: ${tpeopt: Option[Type]} = ${expropt: Option[Term]}" => + param"..$mods $paramname: $tpeopt = $expropt" + case tparam"..${mods: List[Mod]} ${tparamname: Name}[..${tparams: Type.ParamClause}] >: ${tpeopt1: Option[Type]} <: ${tpeopt2: Type} <% ..${tpes1: List[Type]} : ..${tpes2: List[Type]}" => + tparam"..$mods $tparamname[..$tparams] >: $tpeopt1 <: $tpeopt2 <% ..$tpes1 : ..$tpes2" + case init"${tpe: Type}(...${exprss: List[Term.ArgClause]})" => init"$tpe(...$exprss)" + case init"${tpe: Type}(..${exprss: Term.ArgClause})" => init"$tpe(..$exprss)" + case template"{ ..${stats1: List[Stat]} } with ..${ctorcalls: List[Init]} { ${param: Self} => ..${stats2: List[Stat]} }" => + template"{ ..$stats1 } with ..$ctorcalls { $param => ..$stats2 }" + case mod"@${annot: Mod.Annot}" => mod"@$annot" + case mod"private[${name: Ref}]" => mod"private[$name]" + case mod"protected[${name: Ref}]" => mod"protected[$name]" + case enumerator"${pat: Pat} <- ${expr: Term}" => enumerator"$pat <- $expr" + case enumerator"${pat: Pat} = ${expr: Term}" => enumerator"$pat = $expr" + case enumerator"if ${expr: Term}" => enumerator"if $expr" + case importer"${ref: Term.Ref}.{..${importeesnel: List[Importee]}}" => importer"$ref.{..$importeesnel}" + case importee"${iname: Name.Indeterminate}" => importee"${iname: Name.Indeterminate}" + case importee"${iname1: Name} => ${iname2: Name}" => importee"$iname1 => $iname2" + case importee"${iname: Name} => _" => importee"$iname => _" + case source"..${stats: List[Stat]}" => source"..$stats" + } +} diff --git a/quasiquotes3/shared/src/test/scala/scala/meta/tests/SuccessSuite.scala b/quasiquotes3/shared/src/test/scala/scala/meta/tests/SuccessSuite.scala new file mode 100644 index 0000000000..69fc023e33 --- /dev/null +++ b/quasiquotes3/shared/src/test/scala/scala/meta/tests/SuccessSuite.scala @@ -0,0 +1,2955 @@ +package scala.meta.tests +package quasiquotes + +import munit._ +import scala.meta._ +import scala.meta.dialects.Scala211 +import scala.meta.quasiquotes._ +import munit.Clue.generate +import scala.meta.trees._ +import meta.prettyprinters.XtensionStructure + +import compat.Platform.EOL + +import meta.prettyprinters.XtensionSyntax + +class Success extends TreeSuiteBase { + test("rank-0 liftables") { + assertTree(q"foo[${42}]")(Term.ApplyType(Term.Name("foo"), List(Lit.Int(42)))) + assertTree(q"${42}")(Lit.Int(42)) + } + + test("rank-1 liftables") { + implicit def custom: Lift[List[Int], Term.ArgClause] = + Lift(lst => Term.ArgClause(lst.map(x => q"$x".asInstanceOf[Term]))) + assertTree(q"foo(..${List(1, 2, 3)})")( + Term.Apply(Term.Name("foo"), List(Lit.Int(1), Lit.Int(2), Lit.Int(3))) + ) + } + + test("construction ascriptions") { + val xs = List(q"x", q"y").asInstanceOf[List[Term]] + assertEquals(q"foo(..${xs})".syntax, "foo(x, y)") + val xss = List(List(q"x", q"y")).asInstanceOf[List[List[Term]]] + assertEquals(q"foo(...${xss})".syntax, "foo(x, y)") + val rhs = q"x".asInstanceOf[Term] + assertEquals(q"var foo = ${rhs}".syntax, "var foo = x") + } + + // test("deconstruction ascriptions") { + // val q"foo(..${xs: List[Term]})" = q"foo(x, y)" + // assertEquals(xs.toString, "List(x, y)") + // // val q"foo(...${xss: List[List[Term]]})" = q"foo(x, y)" // List[ArgClause] + // // assertEquals(xss.toString, "List(List(x, y))") + // val q"var foo = ${x: Term}" = q"var foo = x" + // assertEquals(x.toString, "x") + // } + + // test("1 Type.Var or Type.Name") { + // val q"1 match { case _: List[..${tpes: List[Tree]}] => }" = q"1 match { case _: List[t] => }" + // assertTrees(tpes)(Type.Var(Type.Name("t"))) + // } + + test("2 Type.Var or Type.Name") { + val q"1 match {case x: ${tpe: Tree} => }" = q"1 match {case x: T => }" + assertTree(tpe)(Type.Name("T")) + } + + test("3 Type.Var or Type.Name") { + val q"1 match {case x: ${tpe: Tree} =>}" = q"1 match {case x: t =>}" + assertTree(tpe)(Type.Name("t")) + } + + test("1 p\"case x: T => \"") { + val p"case ${x: Tree}: T => " = p"case x: T =>" + assertTree(x)(Pat.Var(Term.Name("x"))) + } + + test("2 p\"case x: T => \"") { + val x = p"x" + assertTree(p"case $x: T => ")( + Case(Pat.Typed(Pat.Var(Term.Name("x")), Type.Name("T")), None, Term.Block(Nil)) + ) + } + + test("1 p\"case x @ y => \"") { + val p"case ${x: Pat} @ ${y: Pat} => " = p"case x @ List(1, 2, 3) =>" + assertTree(x)(Pat.Var(Term.Name("x"))) + assertTree(y)(Pat.Extract(Term.Name("List"), List(Lit.Int(1), Lit.Int(2), Lit.Int(3)))) + } + + test("2 p\"case x @ y => \"") { + val x = p"x" + val y = p"List(1, 2, 3)" + assertTree(p"case $x @ $y => ")( + Case( + Pat.Bind( + Pat.Var(Term.Name("x")), + Pat.Extract(Term.Name("List"), List(Lit.Int(1), Lit.Int(2), Lit.Int(3))) + ), + None, + Term.Block(Nil) + ) + ) + } + + test("1 q\"foo(term, ..terms, term)\"") { + val q"foo(${term1: Term}, ..${terms: List[Term]}, ${term2: Term})" = q"foo(x, y, z, q)" + assertTree(term1)(Term.Name("x")) + assertEquals(terms.toString, "List(y, z)") + assertTrees(terms)(Term.Name("y"), Term.Name("z")) + assertTree(term2)(Term.Name("q")) + } + + test("2 q\"foo(term, ..terms, term)\"") { + val term = q"x" + val terms = List(q"y", q"z") + assertTree(q"foo($term, ..$terms, $term)")( + Term.Apply( + Term.Name("foo"), + List(Term.Name("x"), Term.Name("y"), Term.Name("z"), Term.Name("x")) + ) + ) + } + + test("case q\"foo({x: Int})\"") { + q"foo(42)" match { + case q"${foo: Tree}(${x: Tree})" => + assertTree(foo)(Term.Name("foo")) + assertEquals(x.toString, Lit.Int(42).toString) + } + } + + test("case q\"foo({x: Int}, ..ys, z)\"") { + q"foo(1, 2, 3)" match { + case q"$_(${x: Tree}, ..${y: List[Tree]}, ${z: Tree})" => + assertEquals(x.toString, "1") + assertEquals(y.map(_.structure), List("Lit.Int(2)")) + assertTree(z)(Lit.Int(3)) + } + } + + test("1 q\"foo(x, ..ys, z)\"") { + val q"foo(${x: Term}, ..${ys: List[Term]}, ${z: Term})" = q"foo(1, 2, 3)" + assertTree(x)(Lit.Int(1)) + assertEquals(ys.toString, "List(2)") + assertTrees(ys)(Lit.Int(2)) + assertTree(z)(Lit.Int(3)) + } + + test("2 q\"foo(x, ..ys, z, ..ts)\"") { + val x = q"1" + val ys = List(q"2") + val z = q"3" + val ts = Nil + assertTree(q"foo($x, ..$ys, $z, ..$ts)")( + Term.Apply(Term.Name("foo"), List(Lit.Int(1), Lit.Int(2), Lit.Int(3))) + ) + } + + test("1 val q\"type name[_] = _\"") { + val q"type ${name: Type}[$_] = $_" = q"type List[+A] = List[A]" + assertTree(name)(Type.Name("List")) + } + + test("2 val q\"type name[a] = b\"") { + val q"type ${name: Type.Name}[${a: Type.Param}] = ${b: Type}" = q"type List[+A] = List[A]" + assertTree(name)(Type.Name("List")) + assertTree(a)( + Type.Param(List(Mod.Covariant()), Type.Name("A"), Nil, Type.Bounds(None, None), Nil, Nil) + ) + assertTree(b)(Type.Apply(Type.Name("List"), List(Type.Name("A")))) + } + + test("3 val q\"type name[a] = b\"") { + val name = t"List" + val a = tparam"+A" + val b = t"B" + assertTree(q"type $name[$a] = $b")( + Defn.Type( + Nil, + Type.Name("List"), + List( + Type.Param(List(Mod.Covariant()), Type.Name("A"), Nil, Type.Bounds(None, None), Nil, Nil) + ), + Type.Name("B"), + Type.Bounds(None, None) + ) + ) + } + + test("1 val q\"def x = {body: Int}\"") { + val q"def x = ${body: Term}" = q"def x = 42" + assertEquals(body.toString, Lit.Int(42).toString) + } + + test("2 val q\"def x = {body: Int}\"") { + val body = 42 + assertTree(q"def x = ${body: Int}")(Defn.Def(Nil, Term.Name("x"), Nil, Nil, None, Lit.Int(42))) + } + + test("1 q\"name.this.id\"") { + val q"${name: Name}.this.${x: Term}" = q"SuccessSuite.this.x" + assertTree(name)(Name("SuccessSuite")) + assertTree(x)(Term.Name("x")) + } + + test("2 q\"name.this.id\"") { + val name = q"A" + val x = q"B" + // inconsistency with the test above planned, since Name can't be constructed directly + assertTree(q"$name.this.$x")(Term.Select(Term.This(Term.Name("A")), Term.Name("B"))) + } + + test("1 this variants") { + val q"this" = q"this" + val q"${clazz: Name}.this" = q"C.this" + assertTree(clazz)(Name("C")) + } + + test("2 this variants") { + val clazz = t"C" + assertTree(q"this")(Term.This(Name(""))) + assertTree(q"$clazz.this")(Term.This(Type.Name("C"))) + } + + test("1 q\"name.super[name].id\"") { + val q"${clazz: Name}.super[${tpe: Name}].${id: Term}" = q"A.super[B].x" + assertTree(clazz)(Name("A")) + assertTree(tpe)(Name("B")) + assertTree(id)(Term.Name("x")) + } + + test("2 q\"name.super[name].id\"") { + val clazz = q"A" + val tpe = t"B" + val id = q"x" + // inconsistency with the test above planned, since Name can't be constructed directly + assertTree(q"$clazz.super[$tpe].m")( + Term.Select(Term.Super(Term.Name("A"), Type.Name("B")), Term.Name("m")) + ) + } + + test("1 super variants") { + val q"super" = q"super" + val q"super[${tpe1: Name}]" = q"super[M]" + val q"${clazz1: Name}.super" = q"C.super" + val q"${clazz2: Name}.super[${tpe2: Name}]" = q"C.super[M]" + assertTree(tpe1)(Name("M")) + assertTree(tpe2)(Name("M")) + assertTree(clazz1)(Name("C")) + assertTree(clazz2)(Name("C")) + } + + test("2 super variants") { + val clazz = t"C" + val tpe = t"M" + assertTree(q"super")(Term.Super(Name(""), Name(""))) + assertTree(q"super[$tpe]")(Term.Super(Name(""), Type.Name("M"))) + assertTree(q"$clazz.super")(Term.Super(Type.Name("C"), Name(""))) + assertTree(q"$clazz.super[$tpe]")(Term.Super(Type.Name("C"), Type.Name("M"))) + } + + test("1 q\"expr.name\"") { + val q"${expr: Term}.${name: Term}" = q"foo.bar" + assertTree(expr)(Term.Name("foo")) + assertTree(name)(Term.Name("bar")) + } + + test("2 q\"expr.name\"") { + val expr = q"foo" + val name = q"bar" + assertTree(q"$expr.$name")(Term.Select(Term.Name("foo"), Term.Name("bar"))) + } + + test("1 q\"expr(name)\"") { + val q"${expr: Term}(${name: Term})" = q"foo(bar)" + assertTree(expr)(Term.Name("foo")) + assertTree(name)(Term.Name("bar")) + } + + test("2 q\"expr(name)\"") { + val expr = q"foo" + val name = q"bar" + assertTree(q"$expr($name)")(Term.Apply(Term.Name("foo"), List(Term.Name("bar")))) + } + + test("1 q\"foo[..tpes]\"") { + val q"${foo: Term}[..${types: Type.ArgClause}]" = q"foo[T, U]" + assertEquals(foo.toString, "foo") + assertEquals(types.toString, "[T, U]") + assertTree(types)(Type.ArgClause(List(Type.Name("T"), Type.Name("U")))) + } + + test("2 q\"foo[..tpes]\"") { + val foo = q"foo" + val types = List(t"T", t"U") + assertTree(q"$foo[..$types]")( + Term.ApplyType(Term.Name("foo"), List(Type.Name("T"), Type.Name("U"))) + ) + } + + test("1 q\"expr name[..tpes] (..exprs)\"") { + val q"${expr: Term} ${name: Term}[..${tpes: scala.meta.Type.ArgClause}] (..${exprs: Term.ArgClause})" = q"x method[T, U] (1, b)" + assertTree(expr)(Term.Name("x")) + assertTree(name)(Term.Name("method")) + assertEquals(tpes.toString, "[T, U]") + assertTree(tpes)(Type.ArgClause(List(Type.Name("T"), Type.Name("U")))) + assertEquals(exprs.toString, "(1, b)") + assertTrees(exprs: _*)(Lit.Int(1), Term.Name("b")) + } + + test("2 q\"expr name[..tpes] (..exprs)\"") { + val expr = q"x" + val name = q"method" + val tpes = List(t"T", t"U") + val exprs = List(q"1", q"b") + assertTree(q"$expr $name[..$tpes] (..$exprs)")( + Term.ApplyInfix( + Term.Name("x"), + Term.Name("method"), + List(Type.Name("T"), Type.Name("U")), + List(Lit.Int(1), Term.Name("b")) + ) + ) + } + + test("1 q\"a b c\"") { + val q"${a: Term} ${b: Term} ${c: Term}" = q"x y z" + assertTree(a)(Term.Name("x")) + assertTree(b)(Term.Name("y")) + assertTree(c)(Term.Name("z")) + } + + test("2 q\"a b c\"") { + val a = q"x" + val b = q"y" + val c = q"z" + assertTree(q"$a $b $c")( + Term.ApplyInfix(Term.Name("x"), Term.Name("y"), Nil, List(Term.Name("z"))) + ) + } + + test("1 q\"!expr\"") { + val q"!${x: Term}" = q"!foo" + assertTree(x)(Term.Name("foo")) + } + + test("2 q\"!expr\"") { + val x = q"foo" + assertTree(q"!$x")(Term.ApplyUnary(Term.Name("!"), Term.Name("foo"))) + } + + test("1 q\"~expr\"") { + val q"~${x: Term}" = q"~foo" + assertTree(x)(Term.Name("foo")) + } + + test("2 q\"~expr\"") { + val expr = q"foo" + assertTree(q"~$expr")(Term.ApplyUnary(Term.Name("~"), Term.Name("foo"))) + } + + test("1 q\"-expr\"") { + val q"-${x: Term}" = q"-foo" + assertTree(x)(Term.Name("foo")) + } + + test("2 q\"-expr\"") { + val x = q"foo" + assertTree(q"-$x")(Term.ApplyUnary(Term.Name("-"), Term.Name("foo"))) + } + + test("1 q\"+expr\"") { + val q"+${x: Term}" = q"+foo" + assertTree(x)(Term.Name("foo")) + } + + test("2 q\"+expr\"") { + val x = q"foo" + assertTree(q"+$x")(Term.ApplyUnary(Term.Name("+"), Term.Name("foo"))) + } + + test("1 q\"ref = expr\"") { + val q"${ref: Term} = ${expr: Term}" = q"a = b" + assertTree(ref)(Term.Name("a")) + assertTree(expr)(Term.Name("b")) + } + + test("2 q\"ref = expr\"") { + val ref = q"a" + val expr = q"b" + assertTree(q"$ref = $expr")(Term.Assign(Term.Name("a"), Term.Name("b"))) + } + + test("1 val q\"x.y = z.w\" = q\"a.b = c.d\"") { + val q"${x: Term}.${y: Term} = ${z: Term}.${w: Term}" = q"a.b = c.d" + assertTree(x)(Term.Name("a")) + assertTree(y)(Term.Name("b")) + assertTree(z)(Term.Name("c")) + assertTree(w)(Term.Name("d")) + } + + test("2 val q\"x.y = z.w\" = q\"a.b = c.d\"") { + val x = q"a" + val y = q"b" + val z = q"c" + val w = q"d" + assertTree(q"$x.$y = $z.$w")( + Term.Assign( + Term.Select(Term.Name("a"), Term.Name("b")), + Term.Select(Term.Name("c"), Term.Name("d")) + ) + ) + } + + test("q\"1 expr(...exprs) = expr\"") { + val q"${expr1: Term}(...${exprs: List[Term.ArgClause]}) = ${expr2: Term}" = q"foo(a, b) = bar" + assertTree(expr1)(Term.Name("foo")) + assertEquals(exprs.map(_.toString), List("(a, b)")) + assertTrees(exprs)(Term.ArgClause(List(Term.Name("a"), Term.Name("b")))) + assertTree(expr2)(Term.Name("bar")) + } + + test("2 q\"expr(...exprs) = expr\"") { + val expr1 = q"foo" + val exprs = List(List(q"a", q"b")) + val expr2 = q"bar" + assertTree(q"$expr1(...$exprs) = $expr2")( + Term.Assign( + Term.Apply(Term.Name("foo"), List(Term.Name("a"), Term.Name("b"))), + Term.Name("bar") + ) + ) + } + + test("1 q\"expr(..exprs)(..exprs) = expr\"") { + val q"${expr1: Term}(..${exprs1: Term.ArgClause})(..${exprs2: Term.ArgClause}) = ${expr2: Term}" = q"foo(a, b)(c) = bar" + assertTree(expr1)(Term.Name("foo")) + assertEquals(exprs1.toString, "(a, b)") + assertEquals(exprs2.toString, "(c)") + assertTrees(exprs1: _*)(Term.Name("a"), Term.Name("b")) + assertTrees(exprs2: _*)(Term.Name("c")) + assertTree(expr2)(Term.Name("bar")) + } + + test("2 q\"expr(..exprs)(..exprs) = expr\"") { + val expr1 = q"foo" + val exprs1 = List(q"a", q"b") + val exprs2 = List(q"c") + val expr2 = q"bar" + assertTree(q"$expr1(..$exprs1)(..$exprs2) = $expr2")( + Term.Assign( + Term.Apply( + Term.Apply(Term.Name("foo"), List(Term.Name("a"), Term.Name("b"))), + List(Term.Name("c")) + ), + Term.Name("bar") + ) + ) + } + + test("1 q\"(x, y: Int)\"") { + val q"(${x: Term}, y: Int)" = q"(x: X, y: Int)" + assertTree(x)(Term.Ascribe(Term.Name("x"), Type.Name("X"))) + } + + test("2 q\"(x, y: Int)\"") { + val x = q"x: X" + assertTree(q"($x, y: Int)")( + Term.Tuple( + List( + Term.Ascribe(Term.Name("x"), Type.Name("X")), + Term.Ascribe(Term.Name("y"), Type.Name("Int")) + ) + ) + ) + } + + test("1 q\"f(q, y: Y)") { + val q"f(${q: Term}, y: Y) = ${r: Lit}" = q"f(x: X, y: Y) = 1" + assertTree(q)(Term.Ascribe(Term.Name("x"), Type.Name("X"))) + assertTree(r)(Lit.Int(1)) + } + + test("2 q\"f(q, y: Y)") { + val q = q"x: X" + val r = q"1" + assertTree(q"f($q, y: Y) = $r")( + Term.Assign( + Term.Apply( + Term.Name("f"), + List( + Term.Ascribe(Term.Name("x"), Type.Name("X")), + Term.Ascribe(Term.Name("y"), Type.Name("Y")) + ) + ), + Lit.Int(1) + ) + ) + } + + test("1 q\"return expr\"") { + val q"return $expr" = q"return foo == bar" + assertTree(expr)( + Term.ApplyInfix(Term.Name("foo"), Term.Name("=="), Nil, List(Term.Name("bar"))) + ) + } + + test("2 q\"return expr\"") { + val expr = q"foo == bar" + assertTree(q"return $expr")( + Term.Return(Term.ApplyInfix(Term.Name("foo"), Term.Name("=="), Nil, List(Term.Name("bar")))) + ) + } + + test("1 q\"throw expr\"") { + val q"throw $expr" = q"throw new RuntimeException" + assertTree(expr)(Term.New(Init(Type.Name("RuntimeException"), Name(""), List.empty[List[Term]]))) + } + + test("2 q\"throw expr\"") { + val expr = q"new RuntimeException" + assertTree(q"throw $expr")( + Term.Throw(Term.New(Init(Type.Name("RuntimeException"), Name(""), List.empty[List[Term]]))) + ) + } + + test("1 q\"expr: tpe\"") { + val q"$exp: $tpe" = q"1: Double" + assertTree(exp)(Lit.Int(1)) + assertTree(tpe)(Type.Name("Double")) + } + + test("2 q\"expr: tpe\"") { + val exp = q"1" + val tpe = t"Double" + assertTree(q"$exp: $tpe")(Term.Ascribe(Lit.Int(1), Type.Name("Double"))) + } + + test("1 q\"expr: ..@annots\"") { + val q"$exprr: @q ..@$annotz @$ar" = q"foo: @q @w @e @r" + assertTree(exprr)(Term.Name("foo")) + assertEquals(annotz.toString, "List(@w, @e)") + assertTrees(annotz)( + Mod.Annot(Init(Type.Name("w"), Name(""), List.empty[List[Term]])), + Mod.Annot(Init(Type.Name("e"), Name(""), List.empty[List[Term]])) + ) + assertTree(ar)(Mod.Annot(Init(Type.Name("r"), Name(""), List.empty[List[Term]]))) + } + + test("2 q\"expr: ..@annots\"") { + val mods = List(mod"@w", mod"@e") + assertTree(q"foo: @q ..@$mods @r")( + Term.Annotate( + Term.Name("foo"), + List( + Mod.Annot(Init(Type.Name("q"), Name(""), List.empty[List[Term]])), + Mod.Annot(Init(Type.Name("w"), Name(""), List.empty[List[Term]])), + Mod.Annot(Init(Type.Name("e"), Name(""), List.empty[List[Term]])), + Mod.Annot(Init(Type.Name("r"), Name(""), List.empty[List[Term]])) + ) + ) + ) + } + + test("q\"(..exprs)\"") { + val q"(..$terms)" = q"(y, z)" + assertEquals(terms.toString, "List(y, z)") + assertTrees(terms)(Term.Name("y"), Term.Name("z")) + } + + test("2 q\"(..exprs)\"") { + val terms = List(q"y", q"z") + assertTree(q"(..$terms)")(Term.Tuple(List(Term.Name("y"), Term.Name("z")))) + } + + test("1 val q\"(..params)\" = q\"(x: Int, y: String)\"") { + val q"(..$params)" = q"(x: Int, y: String)" + assertEquals(params.toString, "List(x: Int, y: String)") + assertTrees(params)( + Term.Ascribe(Term.Name("x"), Type.Name("Int")), + Term.Ascribe(Term.Name("y"), Type.Name("String")) + ) + } + + test("2 val q\"(..params)\" = q\"(x: Int, y: String)\"") { + val params = List(q"x: Int", q"y: String") + assertTree(q"(..$params)")( + Term.Tuple( + List( + Term.Ascribe(Term.Name("x"), Type.Name("Int")), + Term.Ascribe(Term.Name("y"), Type.Name("String")) + ) + ) + ) + } + + test("1 q\"{ ..stats }\"") { + val q"{foo; ..$statz; $astat}" = q"{foo; val a = x; val b = y; val c = z}" + assertEquals(statz.toString, "List(val a = x, val b = y)") + assertTrees(statz)( + Defn.Val(Nil, List(Pat.Var(Term.Name("a"))), None, Term.Name("x")), + Defn.Val(Nil, List(Pat.Var(Term.Name("b"))), None, Term.Name("y")) + ) + assertTree(astat)(Defn.Val(Nil, List(Pat.Var(Term.Name("c"))), None, Term.Name("z"))) + } + + test("2 q\"{ ..stats }\"") { + val stats = List(q"val x = 1", q"val y = 2") + assertTree(q"{ ..$stats }")( + Term.Block( + List( + Defn.Val(Nil, List(Pat.Var(Term.Name("x"))), None, Lit.Int(1)), + Defn.Val(Nil, List(Pat.Var(Term.Name("y"))), None, Lit.Int(2)) + ) + ) + ) + } + + test("1 q\"if (expr) expr else expr\"") { + val q"if ($expr1) $expr2 else $expr3" = q"if (1 > 2) a else b" + assertTree(expr1)(Term.ApplyInfix(Lit.Int(1), Term.Name(">"), Nil, List(Lit.Int(2)))) + assertTree(expr2)(Term.Name("a")) + assertTree(expr3)(Term.Name("b")) + } + + test("2 q\"if (expr) expr else expr\"") { + val expr1 = q"1 > 2" + val expr2 = q"a" + val expr3 = q"b" + assertTree(q"if ($expr1) $expr2 else $expr3")( + Term.If( + Term.ApplyInfix(Lit.Int(1), Term.Name(">"), Nil, List(Lit.Int(2))), + Term.Name("a"), + Term.Name("b"), + Nil + ) + ) + } + + test("1 q\"expr match { ..case cases }\"") { + val q"$expr match { case bar => baz; ..case $casez; case q => w}" = + q"foo match { case bar => baz; case _ => foo ; case q => w }" + assertTree(expr)(Term.Name("foo")) + assertEquals(casez.toString, "List(case _ => foo)") + assertTrees(casez)(Case(Pat.Wildcard(), None, Term.Name("foo"))) + } + + test("2 q\"expr match { ..case cases }\"") { + val q"$expr match { case bar => baz; ..case $casez; case _ => foo }" = + q"foo match { case bar => baz; case _ => foo }" + assertTree(expr)(Term.Name("foo")) + assert(casez.asInstanceOf[Seq[Tree]].isEmpty) + } + + test("3 q\"expr match { ..case cases }\"") { + val q"$expr match { ..case $casez }" = q"foo match { case bar => baz; case _ => foo }" + assertTree(expr)(Term.Name("foo")) + assertEquals(casez.toString, "List(case bar => baz, case _ => foo)") + assertTrees(casez)( + Case(Pat.Var(Term.Name("bar")), None, Term.Name("baz")), + Case(Pat.Wildcard(), None, Term.Name("foo")) + ) + } + + test("4 q\"expr match { ..case cases }\"") { + val expr = q"foo" + val casez = List(p"case a => b", p"case q => w") + assertTree(q"$expr match { ..case $casez }")( + Term.Match( + Term.Name("foo"), + List( + Case(Pat.Var(Term.Name("a")), None, Term.Name("b")), + Case(Pat.Var(Term.Name("q")), None, Term.Name("w")) + ), + Nil + ) + ) + } + + test("1 q\"try expr catch { ..case cases } finally expropt\"") { + val q"try $expr catch { case $case1 ..case $cases; case $case2 } finally $expropt" = + q"try foo catch { case a => b; case _ => bar; case 1 => 2; case q => w} finally baz" + assertTree(expr)(Term.Name("foo")) + assertEquals(cases.toString, "List(case _ => bar, case 1 => 2)") + assertTrees(cases)( + Case(Pat.Wildcard(), None, Term.Name("bar")), + Case(Lit.Int(1), None, Lit.Int(2)) + ) + assertTree(case1)(Case(Pat.Var(Term.Name("a")), None, Term.Name("b"))) + assertTree(case2)(Case(Pat.Var(Term.Name("q")), None, Term.Name("w"))) + assertTree(expropt)(Some(Term.Name("baz"))) + } + + test("2 q\"try expr catch { ..case cases } finally expropt\"") { + val expr = q"foo" + val cases = List(p"case _ => bar", p"case 1 => 2") + val case1 = p"case a => b" + val case2 = p"case q => w" + val expropt = q"baz" + assertTree(q"try $expr catch { case $case1 ..case $cases; case $case2 } finally $expropt")( + Term.Try( + Term.Name("foo"), + List( + Case(Pat.Var(Term.Name("a")), None, Term.Name("b")), + Case(Pat.Wildcard(), None, Term.Name("bar")), + Case(Lit.Int(1), None, Lit.Int(2)), + Case(Pat.Var(Term.Name("q")), None, Term.Name("w")) + ), + Some(Term.Name("baz")) + ) + ) + } + + test("0 q\"try expr catch expr finally expropt\"") { + val q"try $expr catch $exprr finally $expropt" = q"try foo catch pf finally bar" + assertTree(expr)(Term.Name("foo")) + assertTree(exprr)(Term.Name("pf")) + assertTree(expropt)(Some(Term.Name("bar"))) + } + + test("1 q\"try expr catch expr finally expropt\"") { + val q"try $expr catch $exprr finally $expropt" = q"try { foo } catch { pf } finally { bar }" + assertTree(expr)(Term.Block(List(Term.Name("foo")))) + assertTree(exprr)(Term.Block(List(Term.Name("pf")))) + assertTree(expropt)(Some(Term.Block(List(Term.Name("bar"))))) + } + + test("2 q\"try expr catch expr finally expropt\"") { + val expr = q"{ foo }" + val exprr = q"pf" + val expropt = q"{ bar }" + assertTree(q"try $expr catch $exprr finally $expropt")( + Term.TryWithHandler( + Term.Block(List(Term.Name("foo"))), + Term.Name("pf"), + Some(Term.Block(List(Term.Name("bar")))) + ) + ) + } + + test("q\"(i: Int) => 42\"") { + assertTree(q"(i: Int) => 42")( + Term.Function( + List(Term.Param(Nil, Term.Name("i"), Some(Type.Name("Int")), None)), + Lit.Int(42) + ) + ) + } + + test("1 q\"(..params) => expr\"") { + val q"(..${paramz: Term.ParamClause}) => $expr" = q"(x: Int, y: String) => 42" + assertEquals(paramz.toString, "(x: Int, y: String)") + assertTrees(paramz: _*)( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("Int")), None), + Term.Param(Nil, Term.Name("y"), Some(Type.Name("String")), None) + ) + assertTree(expr)(Lit.Int(42)) + } + + test("2 q\"(..params) => expr\"") { + val paramz = List(param"x: Int", param"y: String") + val expr = q"42" + assertTree(q"(..$paramz) => $expr")( + Term.Function( + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("Int")), None), + Term.Param(Nil, Term.Name("y"), Some(Type.Name("String")), None) + ), + Lit.Int(42) + ) + ) + } + + // test("1 val q\"(..q, y: Y, e) => r\" = q\"(x: X, y: Y, z: Z) => 1\"") { // TODO crash owner erasure + // val q"(..$q, y: Y, $e) => $r" = q"(x: X, y: Y, z: Z) => 1" + // assertEquals(q.toString, "List(x: X)") + // assertTrees(q)(Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None)) + // assertTree(e)(Term.Param(Nil, Term.Name("z"), Some(Type.Name("Z")), None)) + // assertTree(r)(Lit.Int(1)) + // } + + test("2 val q\"(..q, y: Y, e) => r\" = q\"(x: X, y: Y, z: Z) => 1\"") { + val q = List(param"x: X") + val e = param"z: Z" + val r = q"1" + assertTree(q"(..$q, y: Y, $e) => $r")( + Term.Function( + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("y"), Some(Type.Name("Y")), None), + Term.Param(Nil, Term.Name("z"), Some(Type.Name("Z")), None) + ), + Lit.Int(1) + ) + ) + } + + test("1 q\"{ ..case cases }\"") { + val q"{ ..case $cases }" = q"{ case i: Int => i + 1 }" + assertTrees(cases)( + Case( + Pat.Typed(Pat.Var(Term.Name("i")), Type.Name("Int")), + None, + Term.ApplyInfix(Term.Name("i"), Term.Name("+"), Nil, List(Lit.Int(1))) + ) + ) + } + + test("2 q\"{ ..case cases }\"") { + val cases = List(p"case i: Int => i + 1") + assertTree(q"{ ..case $cases }")( + Term.PartialFunction( + List( + Case( + Pat.Typed(Pat.Var(Term.Name("i")), Type.Name("Int")), + None, + Term.ApplyInfix(Term.Name("i"), Term.Name("+"), Nil, List(Lit.Int(1))) + ) + ) + ) + ) + } + + test("1 q\"while (expr) expr\"") { + val q"while ($expr1) $expr2" = q"while (foo) bar" + assertTree(expr1)(Term.Name("foo")) + assertTree(expr2)(Term.Name("bar")) + } + + test("2 q\"while (expr) expr\"") { + val expr1 = q"foo" + val expr2 = q"bar" + assertTree(q"while ($expr1) $expr2")(Term.While(Term.Name("foo"), Term.Name("bar"))) + } + + test("1 q\"do expr while(expr)\"") { + val q"do $expr1 while($expr2)" = q"do foo while (bar)" + assertTree(expr1)(Term.Name("foo")) + assertTree(expr2)(Term.Name("bar")) + } + + test("2 q\"do expr while(expr)\"") { + val expr1 = q"foo" + val expr2 = q"bar" + assertTree(q"do $expr1 while($expr2)")(Term.Do(Term.Name("foo"), Term.Name("bar"))) + } + + test("1 q\"for (..enumerators) expr\"") { + val q"for ($enum1; ..$enumerators; if $cond; $enum2) $exprr" = + q"for (a <- as; x <- xs; y <- ys; if bar; b <- bs) foo(x, y)" + assertEquals(enumerators.toString, "List(x <- xs, y <- ys)") + assertTrees(enumerators)( + Enumerator.Generator(Pat.Var(Term.Name("x")), Term.Name("xs")), + Enumerator.Generator(Pat.Var(Term.Name("y")), Term.Name("ys")) + ) + assertTree(cond)(Term.Name("bar")) + assertTree(enum1)(Enumerator.Generator(Pat.Var(Term.Name("a")), Term.Name("as"))) + assertTree(enum2)(Enumerator.Generator(Pat.Var(Term.Name("b")), Term.Name("bs"))) + assertTree(exprr)(Term.Apply(Term.Name("foo"), List(Term.Name("x"), Term.Name("y")))) + } + + test("2 q\"for (..enumerators) expr\"") { + val a = enumerator"a <- as" + val b = enumerator"b <- bs" + val ab = List(a, b) + assertTree(q"for (..$ab) foo")( + Term.For( + List( + Enumerator.Generator(Pat.Var(Term.Name("a")), Term.Name("as")), + Enumerator.Generator(Pat.Var(Term.Name("b")), Term.Name("bs")) + ), + Term.Name("foo") + ) + ) + } + + test("1 q\"for (..enumerators) yield expr\"") { + val q"for (a <- as; ..$enumerators; b <- bs) yield $expr" = + q"for (a <- as; x <- xs; y <- ys; b <- bs) yield foo(x, y)" + assertEquals(enumerators.toString, "List(x <- xs, y <- ys)") + assertTrees(enumerators)( + Enumerator.Generator(Pat.Var(Term.Name("x")), Term.Name("xs")), + Enumerator.Generator(Pat.Var(Term.Name("y")), Term.Name("ys")) + ) + assertTree(expr)(Term.Apply(Term.Name("foo"), List(Term.Name("x"), Term.Name("y")))) + } + + test("2 q\"for (..enumerators) yield expr\"") { + val a = enumerator"a <- as" + val b = enumerator"b <- bs" + val ab = List(a, b) + assertTree(q"for (..$ab) yield foo")( + Term.ForYield( + List( + Enumerator.Generator(Pat.Var(Term.Name("a")), Term.Name("as")), + Enumerator.Generator(Pat.Var(Term.Name("b")), Term.Name("bs")) + ), + Term.Name("foo") + ) + ) + } + + test("1 q\"new { ..stat } with ..inits { self => ..stats }\"") { + val q"new $x" = q"new Foo" + assertTree(x)(Init(Type.Name("Foo"), Name(""), List.empty[List[Term]])) + } + + test("2 q\"new { ..stat } with ..inits { self => ..stats }\"") { + val q"new {..$stats; val b = 4} with $a {$self => ..$statz}" = + q"new {val a = 2; val b = 4} with A { self => val b = 3 }" + assertEquals(stats.toString, "List(val a = 2)") + assertTrees(stats)(Defn.Val(Nil, List(Pat.Var(Term.Name("a"))), None, Lit.Int(2))) + assertTree(a)(Init(Type.Name("A"), Name(""), List.empty[List[Term]])) + assertTree(self)(Self(Term.Name("self"), None)) + assertEquals(statz.toString, "List(val b = 3)") + assertTrees(statz)(Defn.Val(Nil, List(Pat.Var(Term.Name("b"))), None, Lit.Int(3))) + } + + test("3 q\"new { ..stat } with ..inits { self => ..stats }\"") { + val q"new X with T { $self => def m = 42}" = q"new X with T { def m = 42 }" + assertTree(self)(Self(Name(""), None)) + } + + test("4 q\"new { ..stat } with ..inits { self => ..stats }\"") { + val stats = List(q"val a = 2") + val a = init"A" + val self = self"self: A" + val statz = List(q"val b = 3") + assertTree(q"new {..$stats; val b = 4} with $a {$self => ..$statz}")( + Term.NewAnonymous( + Template( + List( + Defn.Val(Nil, List(Pat.Var(Term.Name("a"))), None, Lit.Int(2)), + Defn.Val(Nil, List(Pat.Var(Term.Name("b"))), None, Lit.Int(4)) + ), + List(Init(Type.Name("A"), Name(""), List.empty[List[Term]])), + Self(Term.Name("self"), Some(Type.Name("A"))), + List(Defn.Val(Nil, List(Pat.Var(Term.Name("b"))), None, Lit.Int(3))), + Nil + ) + ) + ) + } + + test("q\"_\"") { + assertTree(q"_")(Term.Placeholder()) + } + + test("1 q\"expr _\"") { + val q"$expr _" = q"foo _" + assertTree(expr)(Term.Name("foo")) + } + + test("2 q\"expr _\"") { + val expr = q"foo" + assertTree(q"$expr _")(Term.Eta(Term.Name("foo"))) + } + + test("1 q\"expr: _*\"") { + val q"$expr: _*" = q"foo: _*" + assertTree(expr)(Term.Name("foo")) + } + + test("2 arg\"expr: _*\"") { + val expr = q"foo" + assertTree(q"$expr: _*")(Term.Repeated(Term.Name("foo"))) + } + + test("1 q\"lit\"") { + val q"$x" = q"42" + assertTree(x)(Lit.Int(42)) + } + + test("2 q\"lit\"") { + val lit = q"42" + assertTree(q"$lit")(Lit.Int(42)) + } + + test("1 t\"ref.tname\"") { + val t"$ref.$tname" = t"X.Y" + assertTree(ref)(Term.Name("X")) + assertTree(tname)(Type.Name("Y")) + } + + test("2 t\"ref.tname\"") { + val ref = q"X" + val tname = t"Y" + assertTree(t"$ref.$tname")(Type.Select(Term.Name("X"), Type.Name("Y"))) + } + + test("1 t\"tpe#tname\"") { + val t"$tpe#$tname" = t"X#Y" + assertTree(tpe)(Type.Name("X")) + assertTree(tname)(Type.Name("Y")) + } + + test("2 t\"tpe#tname\"") { + val tpe = t"X" + val tname = t"Y" + assertTree(t"$tpe#$tname")(Type.Project(Type.Name("X"), Type.Name("Y"))) + } + + test("1 t\"ref.type\"") { + val t"$ref.type" = t"X.type" + assertTree(ref)(Term.Name("X")) + } + + test("2 t\"ref.type\"") { + val ref = q"X" + assertTree(t"$ref.type")(Type.Singleton(Term.Name("X"))) + } + /* + Issue #462 + */ + test("3 t\"ref.type\"") { + val ref = q"X.a" + assertTree(t"$ref.type")(Type.Singleton(Term.Select(Term.Name("X"), Term.Name("a")))) + } + + test("1 t\"tpe[..tpes]") { + val t"$tpe[..$tpes]" = t"X[Y, Z]" + assertTree(tpe)(Type.Name("X")) + assertEquals(tpes.toString, "[Y, Z]") + assertTree(tpes)(Type.ArgClause(List(Type.Name("Y"), Type.Name("Z")))) + } + + test("2 t\"tpe[..tpes]") { + val tpe = t"X" + val tpes = List(t"Y", t"Z") + assertTree(t"$tpe[..$tpes]")(Type.Apply(Type.Name("X"), List(Type.Name("Y"), Type.Name("Z")))) + } + + test("1 t\"tpe tname tpe\"") { + val t"$tpe1 $tname $tpe2" = t"X Y Z" + assertTree(tpe1)(Type.Name("X")) + assertTree(tname)(Type.Name("Y")) + assertTree(tpe2)(Type.Name("Z")) + } + + test("2 t\"tpe tname tpe\"") { + val tpe1 = t"X" + val tname = t"Y" + val tpe2 = t"Z" + assertTree(t"$tpe1 $tname $tpe2")( + Type.ApplyInfix(Type.Name("X"), Type.Name("Y"), Type.Name("Z")) + ) + } + + test("1 t\"(..tpes) => tpe\"") { + val t"(..$tpes) => $tpe" = t"(X, Y) => Z" + assertEquals(tpes.toString, "(X, Y)") + assertTree(tpes)(Type.FuncParamClause(List(Type.Name("X"), Type.Name("Y")))) + assertTree(tpe)(Type.Name("Z")) + } + + test("2 t\"(..tpes) => tpe\"") { + val tpes: List[Type] = List(t"X", t"Y") + val tpe = t"Z" + assertTree(t"(..$tpes) => $tpe")( + Type.Function(List(Type.Name("X"), Type.Name("Y")), Type.Name("Z")) + ) + } + + test("1 t\"(..tpes)\"") { + val t"(..$tpes)" = t"(X, Y)" + assertEquals(tpes.toString, "List(X, Y)") + assertTrees(tpes)(Type.Name("X"), Type.Name("Y")) + } + + test("t\"(..tpes)\"") { + val tpes = List(t"X", t"Y") + assertTree(t"(..$tpes)")(Type.Tuple(List(Type.Name("X"), Type.Name("Y")))) + } + + test("1 t\"tpe { ..stats }\"") { + val t"$tpe {..$stats}" = t"A with B with C { val a: A; val b: B }" + assertEquals(tpe.toString, "Some(A with B with C)") + assertTree(tpe)(Some(Type.With(Type.With(Type.Name("A"), Type.Name("B")), Type.Name("C")))) + assertEquals(stats.toString, "List(val a: A, val b: B)") + assertTrees(stats)( + Decl.Val(Nil, List(Pat.Var(Term.Name("a"))), Type.Name("A")), + Decl.Val(Nil, List(Pat.Var(Term.Name("b"))), Type.Name("B")) + ) + } + + test("2 t\"tpe { ..stats }\"") { + val tpe = t"X with Y" + val stats = List(q"val a: A", q"val b: B") + assertTree(t"$tpe { ..$stats }")( + Type.Refine( + Some(Type.With(Type.Name("X"), Type.Name("Y"))), + List( + Decl.Val(Nil, List(Pat.Var(Term.Name("a"))), Type.Name("A")), + Decl.Val(Nil, List(Pat.Var(Term.Name("b"))), Type.Name("B")) + ) + ) + ) + } + + test("1 t\"tpe forSome { ..stats }\"") { + val t"$tpe forSome { ..$stats }" = t"X forSome { val a: A; val b: B }" + assertTree(tpe)(Type.Name("X")) + assertEquals(stats.toString, "List(val a: A, val b: B)") + assertTrees(stats)( + Decl.Val(Nil, List(Pat.Var(Term.Name("a"))), Type.Name("A")), + Decl.Val(Nil, List(Pat.Var(Term.Name("b"))), Type.Name("B")) + ) + } + + test("2 t\"tpe forSome { ..stats }\"") { + val tpe = t"X" + val stats = List(q"val a:A", q"val b:B") + assertTree(t"$tpe forSome { ..$stats }")( + Type.Existential( + Type.Name("X"), + List( + Decl.Val(Nil, List(Pat.Var(Term.Name("a"))), Type.Name("A")), + Decl.Val(Nil, List(Pat.Var(Term.Name("b"))), Type.Name("B")) + ) + ) + ) + } + + test("1 t\"tpe ..@annots\"") { + val t"$tpe ..@$annots" = t"X @a @b" + assertTree(tpe)(Type.Name("X")) + assertEquals(annots.toString, "List(@a, @b)") + assertTrees(annots)( + Mod.Annot(Init(Type.Name("a"), Name(""), List.empty[List[Term]])), + Mod.Annot(Init(Type.Name("b"), Name(""), List.empty[List[Term]])) + ) + } + + test("2 t\"tpe ..@annots\"") { + val tpe = t"X" + val annots = List(mod"@a", mod"@b") + assertTree(t"$tpe ..@$annots")( + Type.Annotate( + Type.Name("X"), + List( + Mod.Annot(Init(Type.Name("a"), Name(""), List.empty[List[Term]])), + Mod.Annot(Init(Type.Name("b"), Name(""), List.empty[List[Term]])) + ) + ) + ) + } + + test("1 t\"[..tparams] =>> tpe\"") { + val t"[..$tparams] =>> $tpe" = t"[T] =>> (T, T)" + assertEquals(tparams.toString, "[T]") + assertTree(tparams)(Type.ParamClause { + Type.Param( + Nil, + Type.Name("T"), + Type.ParamClause(Nil), + Type.Bounds(None, None), + Nil, + Nil + ) :: Nil + }) + assertEquals(tpe.toString, "(T, T)") + } + + test("2 t\"(..tparams) =>> tpe\"") { + val tparams = List(tparam"T") + val tpe = t"(T, T)" + assertTree(t"[..$tparams] =>> $tpe")( + Type.Lambda( + List(Type.Param(Nil, Type.Name("T"), Nil, Type.Bounds(None, None), Nil, Nil)), + Type.Tuple(List(Type.Name("T"), Type.Name("T"))) + ) + ) + } + + test("1 t\"_ >: tpeopt <: tpeopt\"") { + val t"_ >: $tpe1 <: $tpe2" = t"_ >: X <: Y" + assertTree(tpe1)(Some(Type.Name("X"))) + assertTree(tpe2)(Some(Type.Name("Y"))) + } + + test("2 t\"_ >: tpeopt <: tpeopt\"") { + val tpe1 = t"X" + val tpe2 = t"Y" + assertTree(t"_ >: $tpe1 <: $tpe2")( + Type.Wildcard(Type.Bounds(Some(Type.Name("X")), Some(Type.Name("Y")))) + ) + } + + test("1 t\"=> tpe\"") { + val t"=> $tpe" = t"=> X" + assertTree(tpe)(Type.Name("X")) + } + + test("2 t\"=> tpe\"") { + val tpe = t"X" + assertTree(t"=> $tpe")(Type.ByName(Type.Name("X"))) + } + + test("1 t\"tpe *\"") { + val t"$tpe*" = t"X*" + assertTree(tpe)(Type.Name("X")) + } + + test("2 t\"tpe *\"") { + val tpe = t"X" + assertTree(t"$tpe*")(Type.Repeated(Type.Name("X"))) + } + + test("t\"lit\"") { + val lit = q"1" + assertTree(t"$lit")(Lit.Int(1)) + } + + test("p\"_\"") { + assertTree(p"_")(Pat.Wildcard()) + } + + test("p\"name\"") { + assertTree(p"name")(Pat.Var(Term.Name("name"))) + } + + test("p\"x\"") { + assertTree(p"x")(Pat.Var(Term.Name("x"))) + } + + test("p\"X\"") { + assertTree(p"X")(Pat.Var(Term.Name("X"))) + } + + test("p\"`x`\"") { + assertTree(p"`x`")(Term.Name("x")) + } + + test("p\"`X`\"") { + assertTree(p"`X`")(Term.Name("X")) + } + + test("1 p\"pat @ pat\"") { + val p"$pat1 @ $pat2" = p"x @ y" + assertTree(pat1)(Pat.Var(Term.Name("x"))) + assertTree(pat2)(Pat.Var(Term.Name("y"))) + } + + test("2 p\"pat1 @ pat\"") { + val pat1 = p"x" + val pat2 = p"y" + assertTree(p"$pat1 @ $pat2")(Pat.Bind(Pat.Var(Term.Name("x")), Pat.Var(Term.Name("y")))) + } + + test("1 p\"pat | pat\"") { + val p"$pat1 | $pat2" = p"x | y" + assertTree(pat1)(Pat.Var(Term.Name("x"))) + assertTree(pat2)(Pat.Var(Term.Name("y"))) + } + + test("2 p\"pat | pat\"") { + val pat1 = q"X" + val pat2 = q"Y" + assertTree(p"$pat1 | $pat2")(Pat.Alternative(Term.Name("X"), Term.Name("Y"))) + } + + test("3 p\"pat | pat\"") { + val pat1 = p"`X`" + val pat2 = q"Y" + assertTree(p"$pat1 | $pat2")(Pat.Alternative(Term.Name("X"), Term.Name("Y"))) + } + + test("1 p\"(..pats)\"") { + val p"(..$pats)" = p"(X, Y)" + assertEquals(pats.toString, "List(X, Y)") + assertTrees(pats)(Term.Name("X"), Term.Name("Y")) + } + + test("2 p\"(..pats)\"") { + val pats = List(p"x", p"y") + assertTree(p"(..$pats)")(Pat.Tuple(List(Pat.Var(Term.Name("x")), Pat.Var(Term.Name("y"))))) + } + + test("3 p\"(..pats)\"") { + val pats = List(p"`X`", q"Y") + assertTree(p"(..$pats)")(Pat.Tuple(List(Term.Name("X"), Term.Name("Y")))) + } + + test("1 p\"expr(..pats)\"") { + val p"$expr(..${pats: Pat.ArgClause})" = p"x[A, B](Q, W)" + assertTree(expr)(Term.ApplyType(Term.Name("x"), List(Type.Name("A"), Type.Name("B")))) + assertEquals(pats.toString, "(Q, W)") + assertTrees(pats: _*)(Term.Name("Q"), Term.Name("W")) + } + + test("2 p\"expr(..pats)\"") { + val p"$expr(..${pats: Pat.ArgClause})" = p"x(Q, W)" + assertTree(expr)(Term.Name("x")) + assertEquals(pats.toString, "(Q, W)") + assertTrees(pats: _*)(Term.Name("Q"), Term.Name("W")) + } + + test("3 p\"expr(..pats)\"") { + val ref = q"x" + val tpes = List(t"A", t"B") + val pats = List(q"Q", q"W") + assertTree(p"$ref[..$tpes](..$pats)")( + Pat.Extract( + Term.ApplyType(Term.Name("x"), List(Type.Name("A"), Type.Name("B"))), + List(Term.Name("Q"), Term.Name("W")) + ) + ) + } + + test("4 p\"expr(..pats)\"") { + val ref = q"`x`" + val tpes = List(t"`A`", t"B") + val pats = List(p"`Q`", q"W") + assertTree(p"$ref[..$tpes](..$pats)")( + Pat.Extract( + Term.ApplyType(Term.Name("x"), List(Type.Name("A"), Type.Name("B"))), + List(Term.Name("Q"), Term.Name("W")) + ) + ) + } + + /* + Issue #462 + */ + test("5 p\"expr(..pats)\"") { + val ref = q"x.a" + val tpes = List(t"A", t"B") + val pats = List(q"Q", q"W") + assertTree(p"$ref[..$tpes](..$pats)")( + Pat.Extract( + Term.ApplyType( + Term.Select(Term.Name("x"), Term.Name("a")), + List(Type.Name("A"), Type.Name("B")) + ), + List(Term.Name("Q"), Term.Name("W")) + ) + ) + } + + test("1 p\"pat name (..pats)\"") { + val p"$pat $name (..${pats: Pat.ArgClause})" = p"x y (Q, W)" + assertTree(pat)(Pat.Var(Term.Name("x"))) + assertTree(name)(Term.Name("y")) + assertEquals(pats.toString, "(Q, W)") + assertTrees(pats: _*)(Term.Name("Q"), Term.Name("W")) + } + + test("2 p\"pat name (..pats)\"") { + val pat = p"x" + val name = q"y" + val pats = List(q"Q", q"W") + assertTree(p"$pat $name (..$pats)")( + Pat.ExtractInfix( + Pat.Var(Term.Name("x")), + Term.Name("y"), + List(Term.Name("Q"), Term.Name("W")) + ) + ) + } + + test("3 p\"pat name (..pats)\"") { + val pat = p"`x`" + val name = q"y" + val pats = List(q"Q", q"W") + assertTree(p"$pat $name (..$pats)")( + Pat.ExtractInfix(Term.Name("x"), Term.Name("y"), List(Term.Name("Q"), Term.Name("W"))) + ) + } + + test("1 p\"pat: ptpe\"") { + val p"$pat: $ptpe" = p"x: Y" + assertTree(pat)(Pat.Var(Term.Name("x"))) + assertTree(ptpe)(Type.Name("Y")) + } + + test("2 p\"pat: ptpe\"") { + val pat = p"x" + val ptpe = t"Y" + assertTree(p"$pat: $ptpe")(Pat.Typed(Pat.Var(Term.Name("x")), Type.Name("Y"))) + } + + test("1 p\"expr.name\"") { + val p"$expr.$name" = p"x.y" + assertTree(expr)(Term.Name("x")) + assertTree(name)(Term.Name("y")) + } + + test("2 p\"expr.name\"") { + val expr = q"x" + val name = q"y" + assertTree(p"$expr.$name")(Term.Select(Term.Name("x"), Term.Name("y"))) + } + + test("3 p\"expr.name\"") { + val expr = q"`x`" + val name = q"y" + assertTree(p"$expr.$name")(Term.Select(Term.Name("x"), Term.Name("y"))) + } + + test("p\"lit\"") { + val lit = q"1" + assertTree(p"$lit")(Lit.Int(1)) + } + + test("1 p\"case pat if expropt => expr\"") { + val p"case $pat if $expropt => $expr" = p"case X if foo => bar" + assertTree(pat)(Term.Name("X")) + assertTree(expropt)(Some(Term.Name("foo"))) + assertTree(expr)(Term.Name("bar")) + } + + test("2 p\"case pat if expropt => expr\"") { + val pat = q"X" + val expropt = q"foo" + val expr = q"bar" + assertTree(p"case $pat if $expropt => $expr")( + Case(Term.Name("X"), Some(Term.Name("foo")), Term.Name("bar")) + ) + } + + test("3 p\"case pat if expropt => expr\"") { + val pat = p"`X`" + val expropt = q"`foo`" + val expr = q"`bar`" + assertTree(p"case $pat if $expropt => $expr")( + Case(Term.Name("X"), Some(Term.Name("foo")), Term.Name("bar")) + ) + } + + test("1 p\"_*\"") { + assertTree(p"case List(_*) =>")( + Case(Pat.Extract(Term.Name("List"), List(Pat.SeqWildcard())), None, Term.Block(Nil)) + ) + } + + test("2 p\"_*\"") { + assertTree(p"_*")(Pat.SeqWildcard()) + } + + test("1 p\"pat\"") { + val pat = p"X" + assertTree(p"$pat")(Pat.Var(Term.Name("X"))) + } + + test("2 p\"pat\"") { + val pat = p"`X`" + assertTree(p"$pat")(Term.Name("X")) + } + + test("1 q\"..mods val ..pats: tpe\"") { + val q"..$mods val ..$pats: $tpe" = q"private final val x, y: T" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertEquals(pats.toString, "List(x, y)") + assertTrees(pats)(Pat.Var(Term.Name("x")), Pat.Var(Term.Name("y"))) + assertTree(tpe)(Type.Name("T")) + } + + test("2 q\"..mods val ..pats: tpe\"") { + val mods = List(mod"private", mod"final") + val pats = List(p"x", p"y") + val tpe = t"T" + assertTree(q"..$mods val ..$pats: $tpe")( + Decl.Val( + List(Mod.Private(Name("")), Mod.Final()), + List(Pat.Var(Term.Name("x")), Pat.Var(Term.Name("y"))), + Type.Name("T") + ) + ) + } + + test("1 q\"..mods var ..pats: tpe\"") { + val q"..$mods var ..$pats: $tpe" = q"private final var x, y: T" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertEquals(pats.toString, "List(x, y)") + assertTrees(pats)(Pat.Var(Term.Name("x")), Pat.Var(Term.Name("y"))) + assertTree(tpe)(Type.Name("T")) + } + + test("2 q\"..mods var ..pats: tpe\"") { + val mods = List(mod"private", mod"final") + val pats = List(p"x", p"y") + val tpe = t"T" + assertTree(q"..$mods var ..$pats: $tpe")( + Decl.Var( + List(Mod.Private(Name("")), Mod.Final()), + List(Pat.Var(Term.Name("x")), Pat.Var(Term.Name("y"))), + Type.Name("T") + ) + ) + } + + test("1 q\"..mods def name[..tparams](...paramss): tpe\"") { + val q"..$mods def $name[..$tparams](...${paramss: List[Tree]}): $tpe" = + q"private final def m[T, W](x: X, y: Y): R" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertTree(name)(Term.Name("m")) + checkTree(tparams, "[T, W]")(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("T"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + assertEquals(paramss.lengthCompare(1), 0) + checkTreesWithSyntax(paramss: _*)("(x: X, y: Y)")(Term.ParamClause { + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("y"), Some(Type.Name("Y")), None) + ) + }) + assertTree(tpe)(Type.Name("R")) + } + + test("2 q\"..mods def name[..tparams](...paramss): tpe\"") { + val mods = List(mod"private", mod"final") + val name = q"m" + val tparams = List(tparam"T", tparam"W") + val paramss = List(List(param"x: X", param"x: Y")) + val tpe = t"R" + assertTree(q"..$mods def $name[..$tparams](...$paramss): $tpe")( + Decl.Def( + List(Mod.Private(Name("")), Mod.Final()), + Term.Name("m"), + List( + Type.Param(Nil, Type.Name("T"), Nil, Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Nil, Type.Bounds(None, None), Nil, Nil) + ), + List( + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("x"), Some(Type.Name("Y")), None) + ) + ), + Type.Name("R") + ) + ) + } + + test("1 q\"..mods type tname[..tparams] >: tpeopt <: tpeopt\"") { + val q"..$mods type $tname[..$tparams] >: $tpeopt1 <: $tpeopt2" = + q"private final type T[T, W] >: A <: B" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertTree(tname)(Type.Name("T")) + assertEquals(tparams.toString, "[T, W]") + assertTree(tparams)(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("T"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + assertTree(tpeopt1)(Some(Type.Name("A"))) + assertTree(tpeopt2)(Some(Type.Name("B"))) + } + + test("2 q\"..mods type tname[..tparams] >: tpeopt <: tpeopt\"") { + val mods = List(mod"private", mod"final") + val tname = t"T" + val tparams = List(tparam"T", tparam"W") + val tpeopt1 = t"A" + val tpeopt2 = t"A" + assertTree(q"..$mods type $tname[..$tparams] >: $tpeopt1 <: $tpeopt2")( + Decl.Type( + List(Mod.Private(Name("")), Mod.Final()), + Type.Name("T"), + List( + Type.Param(Nil, Type.Name("T"), Nil, Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Nil, Type.Bounds(None, None), Nil, Nil) + ), + Type.Bounds(Some(Type.Name("A")), Some(Type.Name("A"))) + ) + ) + } + + test("1 q\"..mods val ..pats: tpeopt = expr\"") { + val q"..$mods val ..$pats: $tpeopt = $expr" = q"private final val x, y: T = t" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertEquals(pats.toString, "List(x, y)") + assertTrees(pats)(Pat.Var(Term.Name("x")), Pat.Var(Term.Name("y"))) + assertTree(tpeopt)(Some(Type.Name("T"))) + assertTree(expr)(Term.Name("t")) + } + + test("2 q\"..mods val ..pats: tpeopt = expr\"") { + val mods = List(mod"private", mod"final") + val pats = List(p"x", p"y") + val tpeopt = t"T" + val expr = q"t" + assertTree(q"..$mods val ..$pats: $tpeopt = $expr")( + Defn.Val( + List(Mod.Private(Name("")), Mod.Final()), + List(Pat.Var(Term.Name("x")), Pat.Var(Term.Name("y"))), + Some(Type.Name("T")), + Term.Name("t") + ) + ) + } + + test("1 q\"..mods var ..pats: tpeopt = expropt\"") { + val q"..$mods var ..$pats: $tpeopt = $expr" = q"private final var x, y: T = t" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertEquals(pats.toString, "List(x, y)") + assertTrees(pats)(Pat.Var(Term.Name("x")), Pat.Var(Term.Name("y"))) + assertTree(tpeopt)(Some(Type.Name("T"))) + assertTree(expr)(Term.Name("t")) + } + + test("2 q\"..mods var ..pats: tpeopt = expropt\"") { + val mods = List(mod"private", mod"final") + val pats = List(p"x", p"y") + val tpeopt = t"T" + val expropt = q"t" + assertTree(q"..$mods var ..$pats: $tpeopt = $expropt")( + Defn.Var( + List(Mod.Private(Name("")), Mod.Final()), + List(Pat.Var(Term.Name("x")), Pat.Var(Term.Name("y"))), + Some(Type.Name("T")), + Some(Term.Name("t")) + ) + ) + } + + test("1 q\"..mods def name[..tparams](...paramss): tpeopt = expr\"") { + val q"..$mods def $name[..$tparams](...${paramss: List[Tree]}): $tpeopt = $expr" = + q"private final def m[T, W](x: X, y: Y): R = r" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertTree(name)(Term.Name("m")) + checkTree(tparams, "[T, W]")(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("T"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + checkTreesWithSyntax(paramss: _*)("(x: X, y: Y)")(Term.ParamClause { + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("y"), Some(Type.Name("Y")), None) + ) + }) + assertTree(tpeopt)(Some(Type.Name("R"))) + assertTree(expr)(Term.Name("r")) + } + + test("2 q\"..mods def name[..tparams](...paramss): tpeopt = expr\"") { + val mods = List(mod"private", mod"final") + val name = q"m" + val tparams = List(tparam"T", tparam"W") + val paramss = List(List(param"x: X", param"x: Y")) + val tpeopt = t"R" + val expr = q"r" + assertTree(q"..$mods def $name[..$tparams](...$paramss): $tpeopt = $expr")( + Defn.Def( + List(Mod.Private(Name("")), Mod.Final()), + Term.Name("m"), + List( + Type.Param(Nil, Type.Name("T"), Nil, Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Nil, Type.Bounds(None, None), Nil, Nil) + ), + List( + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("x"), Some(Type.Name("Y")), None) + ) + ), + Some(Type.Name("R")), + Term.Name("r") + ) + ) + } + + test("1 q\"..mods def name[..tparams](...paramss): tpeopt = macro expr\"") { + val q"..$mods def $name[..$tparams](...${paramss: List[Tree]}): $tpeopt = macro $expr" = + q"private final def m[T, W](x: X, y: Y): R = macro r" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertTree(name)(Term.Name("m")) + checkTree(tparams, "[T, W]")(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("T"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + checkTreesWithSyntax(paramss: _*)("(x: X, y: Y)")(Term.ParamClause { + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("y"), Some(Type.Name("Y")), None) + ) + }) + assertTree(tpeopt)(Some(Type.Name("R"))) + assertTree(expr)(Term.Name("r")) + } + + test("2 q\"..mods def name[..tparams](...paramss): tpeopt = macro expr\"") { + val mods = List(mod"private", mod"final") + val name = q"m" + val tparams = List(tparam"T", tparam"W") + val paramss = List(List(param"x: X", param"x: Y")) + val tpeopt = Some(t"R") + val expr = q"r" + assertTree(q"..$mods def $name[..$tparams](...$paramss): $tpeopt = macro $expr")( + Defn.Macro( + List(Mod.Private(Name("")), Mod.Final()), + Term.Name("m"), + List( + Type.Param(Nil, Type.Name("T"), Nil, Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Nil, Type.Bounds(None, None), Nil, Nil) + ), + List( + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("x"), Some(Type.Name("Y")), None) + ) + ), + Some(Type.Name("R")), + Term.Name("r") + ) + ) + } + + test("1 q\"..mods type tname[..tparams] = tpe\"") { + val q"..$mods type $tname[..$tparams] = $tpe" = q"private final type Q[T, W] = R" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertTree(tname)(Type.Name("Q")) + assertEquals(tparams.toString, "[T, W]") + assertTree(tparams)(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("T"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + assertTree(tpe)(Type.Name("R")) + } + + test("2 q\"..mods type tname[..tparams] = tpe\"") { + val mods = List(mod"private", mod"final") + val tname = t"Q" + val tparams = List(tparam"T", tparam"W") + val tpe = t"R" + assertTree(q"..$mods type $tname[..$tparams] = $tpe")( + Defn.Type( + List(Mod.Private(Name("")), Mod.Final()), + Type.Name("Q"), + List( + Type.Param(Nil, Type.Name("T"), Nil, Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Nil, Type.Bounds(None, None), Nil, Nil) + ), + Type.Name("R"), + Type.Bounds(None, None) + ) + ) + } + + test("1 q\"..mods class tname[..tparams] mod (...paramss) template\"") { + val q"..$mods class $tname[..$tparams] $mod (...${paramss: List[Term.ParamClause]}) $template" = + q"private final class Q[T, W] private (x: X, y: Y) extends Y" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertTree(tname)(Type.Name("Q")) + assertEquals(tparams.toString, "[T, W]") + assertTree(tparams)(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("T"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + assertTree(mod)(Mod.Private(Name(""))) + checkTreesWithSyntax(paramss: _*)("(x: X, y: Y)")(Term.ParamClause { + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("y"), Some(Type.Name("Y")), None) + ) + }) + assertTree(template)( + Template(Nil, List(Init(Type.Name("Y"), Name(""), List.empty[List[Term]])), Self(Name(""), None), Nil, Nil) + ) + } + + test("2 q\"..mods class tname[..tparams] mod (...paramss) template\"") { + val q"..$mods class $tname[..$tparams] $mod (...${paramss: List[Tree]}) $template" = + q"private final class Q[T, W] protected (x: X, y: Y) extends { def m1 = 42; def m2 = 666 }" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertTree(tname)(Type.Name("Q")) + assertEquals(tparams.toString, "[T, W]") + assertTree(tparams)(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("T"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + assertTree(mod)(Mod.Protected(Name(""))) + checkTreesWithSyntax(paramss: _*)("(x: X, y: Y)")(Term.ParamClause { + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("y"), Some(Type.Name("Y")), None) + ) + }) + assertTree(template)( + Template( + Nil, + Nil, + Self(Name(""), None), + List( + Defn.Def(Nil, Term.Name("m1"), Nil, Nil, None, Lit.Int(42)), + Defn.Def(Nil, Term.Name("m2"), Nil, Nil, None, Lit.Int(666)) + ), + Nil + ) + ) + } + + test("3 q\"..mods class tname[..tparams] mod (...paramss) template\"") { + val mods = List(mod"private", mod"final") + val tname = t"Q" + val tparams = List(tparam"T", tparam"W") + val mod = mod"protected" + val paramss = List(List(param"x: X", param"x: Y")) + val template = template"F { def m = 42 }" + assertTree(q"..$mods class $tname[..$tparams] $mod (...$paramss) $template")( + Defn.Class( + List(Mod.Private(Name("")), Mod.Final()), + Type.Name("Q"), + List( + Type.Param(Nil, Type.Name("T"), Nil, Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Nil, Type.Bounds(None, None), Nil, Nil) + ), + Ctor.Primary( + List(Mod.Protected(Name(""))), + Name(""), + List( + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("x"), Some(Type.Name("Y")), None) + ) + ) + ), + Template( + Nil, + List(Init(Type.Name("F"), Name(""), List.empty[List[Term]])), + Self(Name(""), None), + List(Defn.Def(Nil, Term.Name("m"), Nil, Nil, None, Lit.Int(42))), + Nil + ) + ) + ) + } + + test("1 q\"..mods trait tname[..tparams] template\"") { + val q"..$mods trait $tname[..$tparams] $template" = + q"private sealed trait Q[T, W] extends Y" + assertEquals(mods.toString, "List(private, sealed)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Sealed()) + assertTree(tname)(Type.Name("Q")) + assertEquals(tparams.toString, "[T, W]") + assertTree(tparams)(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("T"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + assertTree(template)( + Template(Nil, List(Init(Type.Name("Y"), Name(""), List.empty[List[Term]])), Self(Name(""), None), Nil, Nil) + ) + } + + test("2 q\"..mods trait tname[..tparams] template\"") { + val q"..$mods trait $tname[..$tparams] $template" = + q"private sealed trait Q[T, W] extends { def m1 = 42; def m2 = 666 }" + assertEquals(mods.toString, "List(private, sealed)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Sealed()) + assertTree(tname)(Type.Name("Q")) + assertEquals(tparams.toString, "[T, W]") + assertTree(tparams)(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("T"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + assertTree(template)( + Template( + Nil, + Nil, + Self(Name(""), None), + List( + Defn.Def(Nil, Term.Name("m1"), Nil, Nil, None, Lit.Int(42)), + Defn.Def(Nil, Term.Name("m2"), Nil, Nil, None, Lit.Int(666)) + ), + Nil + ) + ) + } + + test("3 q\"..mods trait tname[..tparams] template\"") { + val mods = List(mod"private", mod"sealed") + val tname = t"Q" + val tparams = List(tparam"T", tparam"W") + val template = template"F { def m = 42 }" + assertTree(q"..$mods trait $tname[..$tparams] $template")( + Defn.Trait( + List(Mod.Private(Name("")), Mod.Sealed()), + Type.Name("Q"), + List( + Type.Param(Nil, Type.Name("T"), Nil, Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Nil, Type.Bounds(None, None), Nil, Nil) + ), + Ctor.Primary(Nil, Name(""), List.empty[List[Term.Param]]), + Template( + Nil, + List(Init(Type.Name("F"), Name(""), List.empty[List[Term]])), + Self(Name(""), None), + List(Defn.Def(Nil, Term.Name("m"), Nil, Nil, None, Lit.Int(42))), + Nil + ) + ) + ) + } + + test("1 q\"..mods object name template\"") { + val q"..$mods object $name $template" = q"private final object Q extends Y" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertTree(name)(Term.Name("Q")) + assertTree(template)( + Template(Nil, List(Init(Type.Name("Y"), Name(""), List.empty[List[Term]])), Self(Name(""), None), Nil, Nil) + ) + } + + test("2 q\"..mods object name template\"") { + val q"..$mods object $name $template" = + q"private final object Q extends { def m1 = 42; def m2 = 666 }" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + assertTree(name)(Term.Name("Q")) + assertTree(template)( + Template( + Nil, + Nil, + Self(Name(""), None), + List( + Defn.Def(Nil, Term.Name("m1"), Nil, Nil, None, Lit.Int(42)), + Defn.Def(Nil, Term.Name("m2"), Nil, Nil, None, Lit.Int(666)) + ), + Nil + ) + ) + } + + test("3 q\"..mods object name template\"") { + val mods = List(mod"private", mod"final") + val name = q"Q" + val template = template"F { def m = 42 }" + assertTree(q"..$mods object $name $template")( + Defn.Object( + List(Mod.Private(Name("")), Mod.Final()), + Term.Name("Q"), + Template( + Nil, + List(Init(Type.Name("F"), Name(""), List.empty[List[Term]])), + Self(Name(""), None), + List(Defn.Def(Nil, Term.Name("m"), Nil, Nil, None, Lit.Int(42))), + Nil + ) + ) + ) + } + + test("1 q\"package object name template\"") { + val q"package object $name $template" = q"package object Q extends Y" + assertTree(name)(Term.Name("Q")) + assertTree(template)( + Template(Nil, List(Init(Type.Name("Y"), Name(""), List.empty[List[Term]])), Self(Name(""), None), Nil, Nil) + ) + } + + test("2 q\"package object name template\"") { + val q"package object $name $template" = + q"package object Q extends { def m1 = 42; def m2 = 666 }" + assertTree(name)(Term.Name("Q")) + assertTree(template)( + Template( + Nil, + Nil, + Self(Name(""), None), + List( + Defn.Def(Nil, Term.Name("m1"), Nil, Nil, None, Lit.Int(42)), + Defn.Def(Nil, Term.Name("m2"), Nil, Nil, None, Lit.Int(666)) + ), + Nil + ) + ) + } + + test("3 q\"package object name template\"") { + val name = q"Q" + val template = template"F { def m = 42 }" + assertTree(q"package object $name $template")( + Pkg.Object( + Nil, + Term.Name("Q"), + Template( + Nil, + List(Init(Type.Name("F"), Name(""), List.empty[List[Term]])), + Self(Name(""), None), + List(Defn.Def(Nil, Term.Name("m"), Nil, Nil, None, Lit.Int(42))), + Nil + ) + ) + ) + } + + test("1 q\"package ref { ..stats }\"") { + val q"package $ref { ..$stats }" = q"package p { class A; object B }" + assertTree(ref)(Term.Name("p")) + assertEquals(stats.toString, "List(class A, object B)") + assertTrees(stats)( + Defn.Class( + Nil, + Type.Name("A"), + Nil, + Ctor.Primary(Nil, Name(""), List.empty[List[Term.Param]]), + Template(Nil, Nil, Self(Name(""), None), Nil, Nil) + ), + Defn.Object(Nil, Term.Name("B"), Template(Nil, Nil, Self(Name(""), None), Nil, Nil)) + ) + } + + test("2 q\"package ref { ..stats }\"") { + val ref = q"p" + val stats = List(q"class A", q"object B") + assertTree(q"package $ref { ..$stats }")( + Pkg( + Term.Name("p"), + List( + Defn.Class( + Nil, + Type.Name("A"), + Nil, + Ctor.Primary(Nil, Name(""), List.empty[List[Term.Param]]), + Template(Nil, Nil, Self(Name(""), None), Nil, Nil) + ), + Defn.Object(Nil, Term.Name("B"), Template(Nil, Nil, Self(Name(""), None), Nil, Nil)) + ) + ) + ) + } + + /* + Issue #462 + */ + test("3 q\"package ref { ..stats }\"") { + val ref = q"p.a" + val stats = List(q"class A", q"object B") + assertTree(q"package $ref { ..$stats }")( + Pkg( + Term.Select(Term.Name("p"), Term.Name("a")), + List( + Defn.Class( + Nil, + Type.Name("A"), + Nil, + Ctor.Primary(Nil, Name(""), List.empty[List[Term.Param]]), + Template(Nil, Nil, Self(Name(""), None), Nil, Nil) + ), + Defn.Object(Nil, Term.Name("B"), Template(Nil, Nil, Self(Name(""), None), Nil, Nil)) + ) + ) + ) + } + + test("1 q\"..mods def this(...paramss)\"") { + val q"..$mods def this(...${paramss: List[Tree]})" = q"private def this(x: X, y: Y)" + assertEquals(mods.toString, "List(private)") + assertTrees(mods)(Mod.Private(Name(""))) + checkTreesWithSyntax(paramss: _*)("(x: X, y: Y)")(Term.ParamClause { + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("y"), Some(Type.Name("Y")), None) + ) + }) + } + + test("2 q\"..mods def this(...paramss)\"") { + val mods = List(mod"private") + val paramss = List(List(param"x: X", param"x: Y")) + assertTree(q"..$mods def this(...$paramss)")( + Ctor.Primary( + List(Mod.Private(Name(""))), + Name(""), + List( + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("x"), Some(Type.Name("Y")), None) + ) + ) + ) + ) + } + + test("1 q\"..mods def this(...paramss) = expr\"") { + val q"..$mods def this(...${paramss: List[Term.ParamClause]}) = $init" = + q"private final def this(x: X, y: Y) = this(foo, bar)" + assertEquals(mods.toString, "List(private, final)") + assertTrees(mods)(Mod.Private(Name("")), Mod.Final()) + checkTreesWithSyntax(paramss: _*)("(x: X, y: Y)")(Term.ParamClause { + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("y"), Some(Type.Name("Y")), None) + ) + }) + assertTree(init)( + Init( + Type.Singleton(Term.This(Name(""))), + Name(""), + List(List(Term.Name("foo"), Term.Name("bar"))) + ) + ) + } + + test("2 q\"..mods def this(...paramss) = expr\"") { + val mods = List(mod"private", mod"final") + val paramss = List(List(param"x: X", param"x: Y")) + val init = init"C(foo, bar)" + assertTree(q"..$mods def this(...$paramss) = $init")( + Ctor.Secondary( + List(Mod.Private(Name("")), Mod.Final()), + Name.This(), + List( + List( + Term.Param(Nil, Term.Name("x"), Some(Type.Name("X")), None), + Term.Param(Nil, Term.Name("x"), Some(Type.Name("Y")), None) + ) + ), + Init(Type.Name("C"), Name(""), List(List(Term.Name("foo"), Term.Name("bar")))), + Nil + ) + ) + } + + test("1 param\"..mods paramname: tpeopt = expropt\"") { + val param"..$mods $paramname: $tpeopt = $expropt" = param"private final val x: X = 42" + assertTrees(mods)(Mod.Private(Name("")), Mod.Final(), Mod.ValParam()) + assertTree(paramname)(Term.Name("x")) + assertTree(tpeopt)(Some(Type.Name("X"))) + assertTree(expropt)(Some(Lit.Int(42))) + } + + test("2 param\"..mods paramname: tpeopt = expropt\"") { + val mods = List(mod"private", mod"final") + val paramname = q"x" + val tpeopt = t"X" + val expropt = q"42" + assertTree(param"..$mods $paramname: $tpeopt = $expropt")( + Term.Param( + List(Mod.Private(Name("")), Mod.Final()), + Term.Name("x"), + Some(Type.Name("X")), + Some(Lit.Int(42)) + ) + ) + } + + test("1 tparam\"..mods tparamname[..tparams] >: tpeopt <: tpeopt <% ..tpes : ..tpes\"") { + val tparam"..$mods $tparamname[..$tparams] >: $tpeopt1 <: $tpeopt2 <% ..$tpes1 : ..$tpes2" = + tparam"+Z[Q,W] >: E <: R <% T with Y : U with I" + assertEquals(mods.toString, "List(+)") + assertTrees(mods)(Mod.Covariant()) + assertTree(tparamname)(Type.Name("Z")) + assertEquals(tparams.toString, "[Q, W]") + assertTree(tparams)(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("Q"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + assertTree(tpeopt1)(Some(Type.Name("E"))) + assertTree(tpeopt2)(Some(Type.Name("R"))) + assertEquals(tpes1.toString, "List(T with Y)") + assertTrees(tpes1)(Type.With(Type.Name("T"), Type.Name("Y"))) + assertEquals(tpes2.toString, "List(U with I)") + assertTrees(tpes2)(Type.With(Type.Name("U"), Type.Name("I"))) + } + + test("2 tparam\"..mods tparamname[..tparams] >: tpeopt <: tpeopt <% ..tpes : ..tpes\"") { + val mods = List(mod"+") + val tparamname = t"Z" + val tparams = List(tparam"Q", tparam"W") + val tpeopt1 = t"E" + val tpeopt2 = t"R" + val tpes1 = List(t"T with Y") + val tpes2 = List(t"U with I") + assertTree( + tparam"..$mods $tparamname[..$tparams] >: $tpeopt1 <: $tpeopt2 <% ..$tpes1 : ..$tpes2" + )( + Type.Param( + List(Mod.Covariant()), + Type.Name("Z"), + List( + Type.Param(Nil, Type.Name("Q"), Nil, Type.Bounds(None, None), Nil, Nil), + Type.Param(Nil, Type.Name("W"), Nil, Type.Bounds(None, None), Nil, Nil) + ), + Type.Bounds(Some(Type.Name("E")), Some(Type.Name("R"))), + List(Type.With(Type.Name("T"), Type.Name("Y"))), + List(Type.With(Type.Name("U"), Type.Name("I"))) + ) + ) + } + + test("1 init\"tpe(...exprss)\"") { + val init"$tpe(...${exprss: List[Tree]})" = init"C(40)(2)" + assertEquals(tpe.toString, "C") + assertTree(tpe)(Type.Name("C")) + assertEquals(exprss.map(_.toString), List("(40)", "(2)")) + assertTrees(exprss)( + Term.ArgClause(List(Lit.Int(40))), + Term.ArgClause(List(Lit.Int(2))) + ) + } + + test("2 init\"tpe(...exprss)\"") { + val tpe = t"C" + val exprss = List(List(q"40"), List(q"2")) + assertTree(init"$tpe(...$exprss)")( + Init(Type.Name("C"), Name(""), List(List(Lit.Int(40)), List(Lit.Int(2)))) + ) + } + + test("1 init\"this(...exprss)\"") { + val init"this(...${exprss: List[Tree]})" = init"this(40)(2)" + assertEquals(exprss.map(_.toString), List("(40)", "(2)")) + assertTrees(exprss)( + Term.ArgClause(List(Lit.Int(40))), + Term.ArgClause(List(Lit.Int(2))) + ) + } + + test("2 init\"this(...exprss)\"") { + val exprss = List(List(q"40"), List(q"2")) + assertTree(init"this(...$exprss)")( + Init(Type.Singleton(Term.This(Name(""))), Name(""), List(List(Lit.Int(40)), List(Lit.Int(2)))) + ) + } + + test("1 self\"name: tpeopt\"") { + val self"$name: $tpeopt" = self"x: T" + assertEquals(name.toString, "x") + assertTree(name)(Term.Name("x")) + assertEquals(tpeopt.toString, "Some(T)") + assertTree(tpeopt)(Some(Type.Name("T"))) + } + + test("2 self\"name: tpeopt\"") { + val name = q"x" + val tpeopt = t"T" + assertTree(self"$name: $tpeopt")(Self(Term.Name("x"), Some(Type.Name("T")))) + } + + test("1 self\"this: tpeopt\"") { + val self"$name: $tpeopt" = self"this: T" + assertEquals(name.toString, "this") + assertTree(name)(Name.This()) + assertEquals(tpeopt.toString, "Some(T)") + assertTree(tpeopt)(Some(Type.Name("T"))) + } + + test("2 self\"this: tpeopt\"") { + val tpeopt = t"T" + assertTree(self"this: $tpeopt")(Self(Name.This(), Some(Type.Name("T")))) + } + + test("1 template\"{ ..stats } with ..inits { self => ..stats }\"") { + val template"{ ..$stats1 } with ..$inits { $self => ..$stats2 }" = + template"{ val a = 2; val b = 2 } with T with U { self: Z => def m = 2; def n = 2 }" + assertEquals(stats1.toString, "List(val a = 2, val b = 2)") + assertTrees(stats1)( + Defn.Val(Nil, List(Pat.Var(Term.Name("a"))), None, Lit.Int(2)), + Defn.Val(Nil, List(Pat.Var(Term.Name("b"))), None, Lit.Int(2)) + ) + assertEquals(inits.toString, "List(T, U)") + assertTrees(inits)(Init(Type.Name("T"), Name(""), List.empty[List[Term]]), Init(Type.Name("U"), Name(""), List.empty[List[Term]])) + assertTree(self)(Self(Term.Name("self"), Some(Type.Name("Z")))) + assertEquals(stats2.toString, "List(def m = 2, def n = 2)") + assertTrees(stats2)( + Defn.Def(Nil, Term.Name("m"), Nil, Nil, None, Lit.Int(2)), + Defn.Def(Nil, Term.Name("n"), Nil, Nil, None, Lit.Int(2)) + ) + } + + test("2 template\"{ ..stats } with ..inits { self => ..stats }\"") { + val stats1 = List(q"val a = 2", q"val b = 2") + val inits = List(init"T", init"U") + val self = self"self: S" + val stats2 = List(q"def m = 2", q"def n = 2") + assertTree(template"{ ..$stats1 } with ..$inits { $self => ..$stats2 }")( + Template( + List( + Defn.Val(Nil, List(Pat.Var(Term.Name("a"))), None, Lit.Int(2)), + Defn.Val(Nil, List(Pat.Var(Term.Name("b"))), None, Lit.Int(2)) + ), + List(Init(Type.Name("T"), Name(""), List.empty[List[Term]]), Init(Type.Name("U"), Name(""), List.empty[List[Term]])), + Self(Term.Name("self"), Some(Type.Name("S"))), + List( + Defn.Def(Nil, Term.Name("m"), Nil, Nil, None, Lit.Int(2)), + Defn.Def(Nil, Term.Name("n"), Nil, Nil, None, Lit.Int(2)) + ), + Nil + ) + ) + } + + test("1 mod\"@expr\"") { + val mod"@$expr" = mod"@a" + assertTree(expr)(Mod.Annot(Init(Type.Name("a"), Name(""), List.empty[List[Term]]))) + } + + test("2 mod\"@expr\"") { + val expr = mod"@a" + assertTree(mod"@$expr")(Mod.Annot(Init(Type.Name("a"), Name(""), List.empty[List[Term]]))) + } + + test("1 mod\"private[name]\"") { + val mod"private[$name]" = mod"private[X]" + assertTree(name)(Name("X")) + } + + test("2 mod\"private[name]\"") { + val mod"private[$name]" = mod"private" + assertTree(name)(Name("")) + } + + test("3 mod\"private[this]\"") { + val mod"private[this]" = mod"private[this]" + } + + test("4 mod\"private[name]\"") { + val name = q"q" + assertTree(mod"private[$name]")(Mod.Private(Term.Name("q"))) + } + + test("1 mod\"protected[name]\"") { + val mod"protected[$name]" = mod"protected[X]" + assertTree(name)(Name("X")) + } + + test("2 mod\"protected[name]\"") { + val mod"protected[$name]" = mod"protected" + assertTree(name)(Name("")) + } + + test("3 mod\"protected[this]\"") { + val mod"protected[this]" = mod"protected[this]" + } + + test("4 mod\"protected[name]\"") { + val name = q"q" + assertTree(mod"protected[$name]")(Mod.Protected(Term.Name("q"))) + } + + test("mod\"implicit\"") { + assertTree(mod"implicit")(Mod.Implicit()) + } + + test("mod\"final\"") { + assertTree(mod"final")(Mod.Final()) + } + + test("mod\"sealed\"") { + assertTree(mod"sealed")(Mod.Sealed()) + } + + test("mod\"override\"") { + assertTree(mod"override")(Mod.Override()) + } + + test("mod\"case\"") { + assertTree(mod"case")(Mod.Case()) + } + + test("mod\"abstract\"") { + assertTree(mod"abstract")(Mod.Abstract()) + } + + test("mod\"+\"") { + assertTree(mod"+")(Mod.Covariant()) + } + + test("mod\"-\"") { + assertTree(mod"-")(Mod.Contravariant()) + } + + test("mod\"lazy\"") { + assertTree(mod"lazy")(Mod.Lazy()) + } + + test("mod\"val\"") { + assertTree(mod"valparam")(Mod.ValParam()) + } + + test("mod\"var\"") { + assertTree(mod"varparam")(Mod.VarParam()) + } + + test("1 enumerator\"pat <- expr\"") { + val enumerator"$pat <- $expr" = enumerator"x <- xs" + assertTree(pat)(Pat.Var(Term.Name("x"))) + } + + test("2 enumerator\"pat <- expr\"") { + val pat = p"x" + val expr = q"xs" + assertTree(enumerator"$pat <- $expr")( + Enumerator.Generator(Pat.Var(Term.Name("x")), Term.Name("xs")) + ) + } + + test("3 enumerator\"pat <- expr\"") { + val pat = p"X" + val expr = q"xs" + assertTree(enumerator"$pat <- $expr")( + Enumerator.Generator(Pat.Var(Term.Name("X")), Term.Name("xs")) + ) + } + + test("1 enumerator\"pat = expr\"") { + val enumerator"$pat = $expr" = enumerator"x = xs" + assertTree(pat)(Pat.Var(Term.Name("x"))) + } + + test("2 enumerator\"pat = expr\"") { + val pat = p"x" + val expr = q"xs" + assertTree(enumerator"$pat = $expr")(Enumerator.Val(Pat.Var(Term.Name("x")), Term.Name("xs"))) + } + + test("1 enumerator\"if expr\"") { + val enumerator"if $expr" = enumerator"if x" + assertTree(expr)(Term.Name("x")) + } + + test("2 enumerator\"if expr\"") { + val expr = q"x" + assertTree(enumerator"if $expr")(Enumerator.Guard(Term.Name("x"))) + } + + test("1 q\"import ..importers\"") { + val importers = List(importer"foo.bar", importer"bar.{baz, _}") + assertEquals(q"import ..$importers".syntax, "import foo.bar, bar.{ baz, _ }") + } + + test("2 q\"import ..importers\"") { + val q"import ..${importers: List[Tree]}" = q"import a.A" + assertEquals(importers.map(_.syntax), List("a.A")) + } + + test("1 importer\"ref.{..importees}\"") { + val ref = q"bar" + val importees = List(importee"baz", importee"_") + assertEquals(importer"$ref.{..$importees}".syntax, "bar.{ baz, _ }") + } + + test("2 importer\"ref. ..importees\"") { + val importer"${ref: Tree}.{..${importees: List[Tree]}}" = importer"bar.{baz, _}" + assertEquals(ref.syntax, "bar") + assertEquals(importees.map(_.syntax), List("baz", "_")) + } + + /* + Issue #462 + */ + test("3 importer\"ref.{..importees}\"") { + val ref = q"bar.a" + val importees = List(importee"baz", importee"_") + assertEquals(importer"$ref.{..$importees}".syntax, "bar.a.{ baz, _ }") + } + + test("1 importee\"iname\"") { + val importee"$iname" = importee"x" + assertTree(iname)(Name("x")) + } + + test("2 importee\"iname\"") { + // $iname can't be constructed, only extracted from importee"..." and mod"..." + val importee"${iname: Name}" = importee"x" + assertTree(importee"$iname")(Importee.Name(Name("x"))) + } + + test("1 importee\"iname => iname\"") { + val importee"$iname1 => $iname2" = importee"x => y" + assertTree(iname1)(Name("x")) + assertTree(iname2)(Name("y")) + } + + test("2 importee\"iname => iname\"") { + // $iname can't be constructed, only extracted from importee"..." and mod"..." + val importee"${iname1: Name} => ${iname2: Name}" = importee"x => y" + assertTree(importee"$iname1 => $iname2")(Importee.Rename(Name("x"), Name("y"))) + } + + test("1 importee\"iname => _\"") { + val importee"$iname => _" = importee"x => _" + assertTree(iname)(Name("x")) + } + + test("2 importee\"iname => _\"") { + // $iname can't be constructed, only extracted from importee"..." and mod"..." + val importee"${iname: Name} => _" = importee"x => _" + assertTree(importee"$iname => _")(Importee.Unimport(Name("x"))) + } + + test("importee\"_\"") { + assertTree(importee"_")(Importee.Wildcard()) + } + + test("1 source\"..stats\"") { + val source"..$stats" = source"class A { val a = 'a'}" + assertEquals(stats.toString, "List(class A { val a = 'a' })") + assertTrees(stats)( + Defn.Class( + Nil, + Type.Name("A"), + Nil, + Ctor.Primary(Nil, Name(""), List.empty[List[Term.Param]]), + Template( + Nil, + Nil, + Self(Name(""), None), + List(Defn.Val(Nil, List(Pat.Var(Term.Name("a"))), None, Lit.Char('a'))), + Nil + ) + ) + ) + } + + test("2 source\"..stats\"") { + val source"class B { val b = 'b'}; ..$stats" = + source"class B { val b = 'b'}; class A { val a = 'a'}" + assertEquals(stats.toString, "List(class A { val a = 'a' })") + assertTrees(stats)( + Defn.Class( + Nil, + Type.Name("A"), + Nil, + Ctor.Primary(Nil, Name(""), List.empty[List[Term.Param]]), + Template( + Nil, + Nil, + Self(Name(""), None), + List(Defn.Val(Nil, List(Pat.Var(Term.Name("a"))), None, Lit.Char('a'))), + Nil + ) + ) + ) + } + + test("3 source\"..stats\"") { + val stats = List(q"class A { val x = 1 }", q"object B") + assertTree(source"..$stats")( + Source( + List( + Defn.Class( + Nil, + Type.Name("A"), + Nil, + Ctor.Primary(Nil, Name(""), List.empty[List[Term.Param]]), + Template( + Nil, + Nil, + Self(Name(""), None), + List(Defn.Val(Nil, List(Pat.Var(Term.Name("x"))), None, Lit.Int(1))), + Nil + ) + ), + Defn.Object(Nil, Term.Name("B"), Template(Nil, Nil, Self(Name(""), None), Nil, Nil)) + ) + ) + ) + } + + test("unquote T into Option[T]") { + val cond = q"cond" + assertTree(p"case _ if $cond =>")( + Case(Pat.Wildcard(), Some(Term.Name("cond")), Term.Block(Nil)) + ) + } + + test("unquote Option[T] into Option[T]") { + val condopt = Some(q"cond") + assertTree(p"case _ if $condopt =>")( + Case(Pat.Wildcard(), Some(Term.Name("cond")), Term.Block(Nil)) + ) + } + + test("extract Some[T] from Option[T]") { + val p"case _ if $condopt =>" = p"case _ if cond =>" + assertTree(condopt)(Some(Term.Name("cond"))) + } + + test("extract None from Option[T]") { + val p"case _ if $condopt =>" = p"case _ =>" + assertTree(condopt)(None) + } + + test("initial support for ...") { + val q"..${mods: List[Mod]} def ${name: Term.Name}[..${tparams: Type.ParamClause}](...${paramss: List[Term.ParamClause]}): ${tpe: Option[Type]} = ${rhs: Term}" = q"def f(x: Int) = ???" + checkTree(tparams, "")(Type.ParamClause(Nil)) + checkTreesWithSyntax(paramss: _*)("(x: Int)")(Term.ParamClause { + List(Term.Param(Nil, Term.Name("x"), Some(Type.Name("Int")), None)) + }) + assertTree(q"..$mods def $name[..$tparams](...$paramss): $tpe = $rhs")( + Defn.Def( + Nil, + Term.Name("f"), + Nil, + List(List(Term.Param(Nil, Term.Name("x"), Some(Type.Name("Int")), None))), + None, + Term.Name("???") + ) + ) + } + + test("initial support for ..., with tparams") { + val q"..${mods: List[Mod]} def ${name: Term.Name}[..${tparams: Type.ParamClause}](...${paramss: List[Term.ParamClause]}): ${tpe: Option[Type]} = ${rhs: Term}" = q"def f[A](x: Int) = ???" + assertTree(tparams)(Type.ParamClause { + List( + Type.Param(Nil, Type.Name("A"), Type.ParamClause(Nil), Type.Bounds(None, None), Nil, Nil) + ) + }) + checkTreesWithSyntax(paramss: _*)("(x: Int)")(Term.ParamClause { + List(Term.Param(Nil, Term.Name("x"), Some(Type.Name("Int")), None)) + }) + assertTree(q"..$mods def $name[..$tparams](...$paramss): $tpe = $rhs")( + Defn.Def( + Nil, + Term.Name("f"), + List(Type.Param(Nil, Type.Name("A"), Nil, Type.Bounds(None, None), Nil, Nil)), + List(List(Term.Param(Nil, Term.Name("x"), Some(Type.Name("Int")), None))), + None, + Term.Name("???") + ) + ) + } + + test("ellipses in template stats") { + val mods = List(mod"private") + val tree = q"class C { ..$mods def x = 2 }" + assertTree(tree)( + Defn.Class( + Nil, + Type.Name("C"), + Nil, + Ctor.Primary(Nil, Name(""), List.empty[List[Term.Param]]), + Template( + Nil, + Nil, + Self(Name(""), None), + List(Defn.Def(List(Mod.Private(Name(""))), Term.Name("x"), Nil, Nil, None, Lit.Int(2))), + Nil + ) + ) + ) + } + + test("#300") { + val q"class ${tname1: Type.Name} ..${mods1: List[Mod]}" = q"class C" + assertEquals(q"class $tname1 ..$mods1".syntax, "class C") + val q"class ${tname2: Type.Name} ..${mods2: List[Mod]}" = q"class C private" + assertEquals(q"class $tname2 ..$mods2".syntax, "class C private") + } + + test("#448") { + val parent = init"_root_.scala.AnyVal" + val template = template"$parent" + assertEquals(q"class C $template".syntax, "class C extends _root_.scala.AnyVal") + assertEquals(q"class C extends $parent {}".syntax, "class C extends _root_.scala.AnyVal") + assertEquals(q"class C extends $parent".syntax, "class C extends _root_.scala.AnyVal") + assert( + q"class C extends $parent with $parent".syntax == + "class C extends _root_.scala.AnyVal with _root_.scala.AnyVal" + ) + } + + test("#452") { + val stat = q"class C" + assertEquals( + q"$stat; $stat".syntax, + """ + |{ + | class C + | class C + |}""".trim.stripMargin.split('\n').mkString(EOL) + ) + assertEquals( + q"{ $stat; $stat }".syntax, + """ + |{ + | class C + | class C + |}""".trim.stripMargin.split('\n').mkString(EOL) + ) + } + + test("#450") { + val defDefns = List(q"def baz {}") + val objectDefn = q""" + object M { + def foo = bar + println("another stat") + ..$defDefns + } + """ + assertEquals( + objectDefn.syntax, + """ + |object M { + | def foo = bar + | println("another stat") + | def baz: Unit = {} + |} + """.trim.stripMargin.split('\n').mkString(EOL) + ) + } + + test("#458") { + val name = q"x" + val tpe = t"T" + val lambda = q"($name: $tpe) => ???" + assertEquals(lambda.syntax, "(x: T) => ???") + } + + test("#458 II") { + val name = q"x" + val lambda = q"($name: T) => ???" + assertEquals(lambda.syntax, "(x: T) => ???") + } + + test("#455 - unquote None") { + val defnopt: Option[Stat] = None + assertTree(q"..$defnopt")(Term.Block(Nil)) + } + + test("#455 - unquote Some") { + val defnoptSomeOption: Some[Stat] = Some(q"val x = 42") + assertTree(q"..$defnoptSomeOption")( + Term.Block(List(Defn.Val(Nil, List(Pat.Var(Term.Name("x"))), None, Lit.Int(42)))) + ) + } + + test("#455 - unquote Option") { + val defnopt: Option[Stat] = Option(q"val x = 42") + assertTree(q"..$defnopt")( + Term.Block(List(Defn.Val(Nil, List(Pat.Var(Term.Name("x"))), None, Lit.Int(42)))) + ) + } + + test("#468 - primary constructor I") { + val q"case class A(${param: Tree})" = q"case class A(a: Int)" + assertEquals(param.syntax, "a: Int") + } + + test("#468 - primary constructor II") { + val q"case class A(${param: Tree}, ..${params: List[Tree]})" = q"case class A(a: Int, b: Int, c: Int)" + assertEquals(param.syntax, "a: Int") + assertEquals(params.map(_.syntax), List("b: Int", "c: Int")) + } + + test("#468 - primary constructor III") { + val q"case class A(..$params)" = q"case class A(a: Int, b: String)" + checkTreesWithSyntax(params)("(a: Int, b: String)")(Term.ParamClause { + List( + Term.Param(Nil, Term.Name("a"), Some(Type.Name("Int")), None), + Term.Param(Nil, Term.Name("b"), Some(Type.Name("String")), None) + ) + }) + } + + test("#468 - primary constructor IV") { + val q"case class A(...${paramss: List[Tree]})" = q"case class A(a: Int)(b: String)" + assertEquals(paramss.length, 2) + checkTreesWithSyntax(paramss: _*)("(a: Int)", "(b: String)")( + Term.ParamClause(List(Term.Param(Nil, Term.Name("a"), Some(Type.Name("Int")), None))), + Term.ParamClause(List(Term.Param(Nil, Term.Name("b"), Some(Type.Name("String")), None))) + ) + } + + // test("#468 - function parameter list I") { // TODO owner crash + // val q"def foo(${param: Tree}): Int = a" = q"def foo(a: Int): Int = a" + // assertEquals(param.syntax, "a: Int") + // } + + // test("#468 - function parameter list II") { // TODO owner crash + // val q"def foo(${param: Tree}, ..${params: List[Tree]}): Int = a" = q"def foo(a: Int, b: Int, c: Int): Int = a" + // assertEquals(param.syntax, "a: Int") + // assertEquals(params.map(_.syntax), List("b: Int", "c: Int")) + // } + + // test("#468 - function parameter list III") { // TODO owner crash + // val q"def foo(..${params: Term.ParamClause}): Int = a" = q"def foo(a: Int, b: String): Int = a" + // checkTreesWithSyntax(params)("(a: Int, b: String)")(Term.ParamClause { + // List( + // Term.Param(Nil, Term.Name("a"), Some(Type.Name("Int")), None), + // Term.Param(Nil, Term.Name("b"), Some(Type.Name("String")), None) + // ) + // }) + // } + + // test("#468 - function parameter list IV") { // TODO owner crash + // val q"def foo(...${paramss: List[Tree]}): Int = a" = q"def foo(a: Int)(b: String): Int = a" + // assertEquals(paramss.length, 2) + // checkTreesWithSyntax(paramss: _*)("(a: Int)", "(b: String)")( + // Term.ParamClause(List(Term.Param(Nil, Term.Name("a"), Some(Type.Name("Int")), None))), + // Term.ParamClause(List(Term.Param(Nil, Term.Name("b"), Some(Type.Name("String")), None))) + // ) + // } + + // test("#468 - function parameter list V") { // TODO owner crash + // val q"def foo(...${paramss: List[Tree]})(..$params)($param): Int = a" = + // q"def foo(a: Int)(b: String)(c: Long): Int = a" + // checkTreesWithSyntax(paramss: _*)("(a: Int)")(Term.ParamClause { + // List(Term.Param(Nil, Term.Name("a"), Some(Type.Name("Int")), None)) + // }) + // checkTree(params, "(b: String)") { + // Term.ParamClause(Term.Param(Nil, Term.Name("b"), Some(Type.Name("String")), None) :: Nil) + // } + // checkTree(param, "c: Long") { + // Term.Param(Nil, Term.Name("c"), Some(Type.Name("Long")), None) + // } + // } + + test("#230 - tparam extensions I") { + val tparam = tparam"@foo ${Mod.Covariant()} T" + assertEquals(tparam.syntax, "@foo +T") + } + + test("#1006 - tparam extensions II") { + val t1 = Type.Name("T1") + val t2 = Type.Name("T2") + val tparam1 = tparam"$t1" + assertEquals(tparam1.syntax, "T1") + val tparam2 = tparam"$t1 : $t2" + assertEquals(tparam2.syntax, "T1: T2") + } + + test("#829 - lambda extensions I") { + val param = param"x:Int" + val lambda = q"map($param => 3)" + assertEquals(lambda.syntax, "map((x: Int) => 3)") + } + + test("#843") { + val t = t"x.${Type.Name("T")}" + assertEquals(t.syntax, "x.T") + } + + test("#915") { + val a = q"a" + val importer = importer"$a.b" + assertEquals(importer.syntax, "a.b") + } + + test("#833") { + val ys = List(Term.Name("y")) + val block = q"x; ..$ys; z" + assertEquals( + block.syntax, + """ + |{ + | x + | y + | z + |} + """.trim.stripMargin.split('\n').mkString(EOL) + ) + } + + test("#2841 empty, with extends") { + val q"..$mods object $ename extends $template" = q"object X extends Y" + assertTree(template) { + Init(Type.Name("Y"), Name(""), List.empty[List[Term]]) + } + assertEquals(mods, Nil) + } + + test("#2841 empty") { + val q"..$mods object $ename $template" = q"object X extends Y" + assertTree(template) { + Template(Nil, List(Init(Type.Name("Y"), Name(""), List.empty[List[Term]])), Self(Name(""), None), Nil, Nil) + } + assertEquals(mods, Nil) + } + + test("#2841 non-empty, with extends") { + intercept[MatchError] { + val q"..$mods object $ename extends $template" = q"object X extends Y { def foo }" + } + } + + test("#2841 non-empty, no extends") { + val q"..$mods object $ename $template" = q"object X extends Y { def foo }" + assertTree(template) { + Template( + Nil, + List(Init(Type.Name("Y"), Name(""), List.empty[List[Term]])), + Self(Name(""), None), + List(Decl.Def(Nil, Term.Name("foo"), Nil, Nil, Type.Name("Unit"))), + Nil + ) + } + assertEquals(mods, Nil) + } + + test("#2841 empty, full sig") { + val q"..$mods object $ename extends { ..$earlydefns } with ..$parents { $self => ..$stats }" = + q"object X extends Y" + assertEquals(mods, Nil) + assertEquals(earlydefns, Nil) + assertTrees(parents) { + Init(Type.Name("Y"), Name.Anonymous(), List.empty[List[Term]]) + } + assertTree(self)(Self(Name(""), None)) + assertEquals(stats, Nil) + } + + test("#2841 non-empty, full sig") { + val q"..$mods object $ename extends { ..$earlydefns } with ..$parents { $self => ..$stats }" = + q"object X extends Y { def foo }" + assertEquals(mods, Nil) + assertEquals(earlydefns, Nil) + assertTrees(parents) { + Init(Type.Name("Y"), Name.Anonymous(), List.empty[List[Term]]) + } + assertTree(self)(Self(Name(""), None)) + assertTrees(stats) { + Decl.Def(Nil, Term.Name("foo"), Nil, Nil, Type.Name("Unit")) + } + } + + test("#2841 empty, partial sig") { + val q"..$mods object $ename extends ..$parents { ..$stats }" = + q"object X extends Y" + assertEquals(mods, Nil) + assertTrees(parents) { + Init(Type.Name("Y"), Name.Anonymous(), List.empty[List[Term]]) + } + assertEquals(stats, Nil) + } + + test("#2841 non-empty, partial sig") { + val q"..$mods object $ename extends ..$parents { ..$stats }" = + q"object X extends Y { def foo }" + assertEquals(mods, Nil) + assertTrees(parents) { + Init(Type.Name("Y"), Name.Anonymous(), List.empty[List[Term]]) + } + assertTrees(stats) { + Decl.Def(Nil, Term.Name("foo"), Nil, Nil, Type.Name("Unit")) + } + } + +} diff --git a/quasiquotes3/shared/src/test/scala/scala/meta/tests/TreeSuiteBase.scala b/quasiquotes3/shared/src/test/scala/scala/meta/tests/TreeSuiteBase.scala index b4335522e3..37317349ba 100644 --- a/quasiquotes3/shared/src/test/scala/scala/meta/tests/TreeSuiteBase.scala +++ b/quasiquotes3/shared/src/test/scala/scala/meta/tests/TreeSuiteBase.scala @@ -5,11 +5,21 @@ import munit._ import scala.meta._ import meta.prettyprinters.XtensionStructure +// Since currently the UnApply signatures are not being typed (instead always producing `Any`) +// in the scala 3 version of quasiquotes, we naively cast to the correct type here, to keep +// the test suites themselves simple abstract class TreeSuiteBase extends FunSuite { + protected def assertTree(obtained: Any)(expected: Tree)(implicit loc: munit.Location): Unit = + assertNoDiff(obtained.asInstanceOf[Tree].structure, expected.structure) + protected def assertTree(obtained: Tree)(expected: Tree)(implicit loc: munit.Location): Unit = assertNoDiff(obtained.structure, expected.structure) + protected def assertTrees( + obtained: Any + )(expected: Tree*)(implicit loc: munit.Location): Unit = assertTrees(obtained.asInstanceOf[Seq[Tree]]: _*)(expected: _*) + protected def assertTrees( obtained: Tree* )(expected: Tree*)(implicit loc: munit.Location): Unit = { @@ -17,6 +27,14 @@ abstract class TreeSuiteBase extends FunSuite { obtained.zip(expected).foreach { case (o, e) => assertTree(o)(e) } } + protected def assertTree(obtained: Any)(expected: Option[Tree])( + implicit loc: munit.Location + ): Unit = + (obtained.asInstanceOf[Option[Tree]], expected) match { + case (Some(o), Some(e)) => assertTree(o)(e) + case _ => assertEquals(obtained, expected) + } + protected def assertTree(obtained: Option[Tree])(expected: Option[Tree])( implicit loc: munit.Location ): Unit = @@ -25,13 +43,13 @@ abstract class TreeSuiteBase extends FunSuite { case _ => assertEquals(obtained, expected) } - protected def assertSyntax(obtained: Tree, syntax: String = null)(expected: Tree)( + protected def assertSyntax(obtained: Any, syntax: String = null)(expected: Tree)( implicit loc: munit.Location, dialect: Dialect ): Unit = - assertNoDiff(obtained.reprint, Option(syntax).getOrElse(expected.reprint), expected.structure) + assertNoDiff(obtained.asInstanceOf[Tree].reprint, Option(syntax).getOrElse(expected.reprint), expected.structure) - protected def checkTree(obtained: Tree, syntax: String = null)(expected: Tree)( + protected def checkTree(obtained: Any, syntax: String = null)(expected: Tree)( implicit loc: munit.Location, dialect: Dialect ): Unit = { @@ -47,7 +65,7 @@ abstract class TreeSuiteBase extends FunSuite { obtained.zip(expected).foreach { case (o, e) => checkTree(o)(e) } } - protected def checkTreesWithSyntax(obtained: Tree*)(syntax: String*)(expected: Tree*)( + protected def checkTreesWithSyntax(obtained: Any*)(syntax: String*)(expected: Tree*)( implicit loc: munit.Location, dialect: Dialect ): Unit = { @@ -55,7 +73,7 @@ abstract class TreeSuiteBase extends FunSuite { checkTreesWithSyntax(obtained.zip(syntax): _*)(expected: _*) } - protected def checkTreesWithSyntax(obtained: (Tree, String)*)(expected: Tree*)( + protected def checkTreesWithSyntax(obtained: (Any, String)*)(expected: Tree*)( implicit loc: munit.Location, dialect: Dialect ): Unit = {