mirror of https://github.com/sbt/sbt.git
Fix InputTask macro
This commit is contained in:
parent
7e5fbcd92b
commit
66fa46a912
|
|
@ -93,4 +93,20 @@ trait ContextUtil[C <: Quotes & scala.Singleton](val qctx: C):
|
|||
case _ => super.transformTerm(tree)(owner)
|
||||
end refTransformer
|
||||
refTransformer.transformTerm(tree)(Symbol.spliceOwner)
|
||||
|
||||
def collectDefs(tree: Term, isWrapper: (String, TypeRepr, Term) => Boolean): Set[Symbol] =
|
||||
val defs = mutable.HashSet[Symbol]()
|
||||
object traverser extends TreeTraverser:
|
||||
override def traverseTree(tree: Tree)(owner: Symbol): Unit =
|
||||
tree match
|
||||
case Ident(_) => ()
|
||||
case Apply(TypeApply(Select(_, nme), tpe :: Nil), qual :: Nil)
|
||||
if isWrapper(nme, tpe.tpe, qual) =>
|
||||
()
|
||||
case _ =>
|
||||
if tree.symbol ne null then defs += tree.symbol
|
||||
super.traverseTree(tree)(owner)
|
||||
end traverser
|
||||
traverser.traverseTree(tree)(Symbol.spliceOwner)
|
||||
defs.toSet
|
||||
end ContextUtil
|
||||
|
|
|
|||
|
|
@ -23,10 +23,11 @@ trait Convert[C <: Quotes & Singleton](override val qctx: C) extends ContextUtil
|
|||
|
||||
def convert[A: Type](nme: String, in: Term): Converted
|
||||
|
||||
def asPredicate[A]: (String, Type[A], Term) => Boolean =
|
||||
(n, tpe, tree) =>
|
||||
val tag = tpe
|
||||
convert(n, tree)(tag).isSuccess
|
||||
def asPredicate: (String, TypeRepr, Term) => Boolean =
|
||||
(n: String, tpe: TypeRepr, tree: Term) =>
|
||||
tpe.asType match
|
||||
case '[a] =>
|
||||
convert[a](n, tree)(Type.of[a]).isSuccess
|
||||
|
||||
/**
|
||||
* Substitutes wrappers in tree `t` with the result of `subWrapper`. A wrapper is a Tree of the
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits:
|
|||
// def settingDyn[T](t: Def.Initialize[T]): Def.Initialize[T] = macro settingDynMacroImpl[T]
|
||||
|
||||
inline def inputTask[A1](inline a: A1): Def.Initialize[InputTask[A1]] =
|
||||
${ TaskMacro.inputTaskMacroImpl[A1]('a) }
|
||||
${ InputTaskMacro.inputTaskMacroImpl[A1]('a) }
|
||||
|
||||
// def taskIf[T](a: T): Def.Initialize[Task[T]] = macro taskIfMacroImpl[T]
|
||||
|
||||
|
|
@ -308,11 +308,17 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits:
|
|||
// result of type A1, previously implemented using ParserInput.parsedMacroImpl[A1].
|
||||
|
||||
extension [A1](in: Initialize[Parser[A1]])
|
||||
inline def parsed: A1 = ParserInput.wrapInit[A1](Def.toISParser(in))
|
||||
inline def parsed: A1 = ParserInput.`initParser_\u2603\u2603`[A1](Def.toISParser(in))
|
||||
|
||||
extension [A1](in: Initialize[State => Parser[A1]])
|
||||
@targetName("parsedISPA1")
|
||||
inline def parsed: A1 = ParserInput.wrapInit[A1](in)
|
||||
inline def parsed: A1 = ParserInput.`initParser_\u2603\u2603`[A1](in)
|
||||
|
||||
extension [A1](in: Def.Initialize[InputTask[A1]])
|
||||
inline def parsed: Task[A1] =
|
||||
ParserInput.`initParser_\u2603\u2603`[Task[A1]](Def.toIParser[A1](in))
|
||||
|
||||
inline def evaluated: A1 = InputWrapper.`wrapInitInputTask_\u2603\u2603`[A1](in)
|
||||
|
||||
inline def settingKey[A1](inline description: String): SettingKey[A1] =
|
||||
${ std.KeyMacro.settingKeyImpl[A1]('description) }
|
||||
|
|
@ -379,7 +385,8 @@ end Def
|
|||
// because the target doesn't involve Initialize or anything in Def
|
||||
trait TaskMacroExtra:
|
||||
import sbt.std.ParserInput
|
||||
// implicit def macroValueT[T](@deprecated("unused", "") in: Task[T]): std.MacroValue[T] = ???
|
||||
extension [A1](in: Task[A1])
|
||||
inline def value: A1 = std.InputWrapper.`wrapTask_\u2603\u2603`[A1](in)
|
||||
|
||||
// implicit def macroValueIn[T](@deprecated("unused", "") in: InputTask[T]): std.InputEvaluated[T] =
|
||||
// ???
|
||||
|
|
|
|||
|
|
@ -69,37 +69,42 @@ object InputTask:
|
|||
def static[T](p: Parser[Task[T]]): InputTask[T] = free(_ => p)
|
||||
|
||||
def static[I, T](p: Parser[I])(c: I => Task[T]): InputTask[T] = static(p map c)
|
||||
*/
|
||||
|
||||
def free[T](p: State => Parser[Task[T]]): InputTask[T] = make(p)
|
||||
def free[A1](p: State => Parser[Task[A1]]): InputTask[A1] = make(p)
|
||||
|
||||
def free[I, T](p: State => Parser[I])(c: I => Task[T]): InputTask[T] = free(s => p(s) map c)
|
||||
def free[A1, A2](p: State => Parser[A1])(c: A1 => Task[A2]): InputTask[A2] =
|
||||
free(s => p(s) map c)
|
||||
|
||||
def separate[I, T](
|
||||
p: State => Parser[I]
|
||||
)(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] =
|
||||
separate(Def value p)(action)
|
||||
def separate[A1, A2](
|
||||
p: State => Parser[A1]
|
||||
)(action: Initialize[A1 => Task[A2]]): Initialize[InputTask[A2]] =
|
||||
separate(Def.value(p))(action)
|
||||
|
||||
def separate[I, T](
|
||||
p: Initialize[State => Parser[I]]
|
||||
)(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] =
|
||||
def separate[A1, A2](
|
||||
p: Initialize[State => Parser[A1]]
|
||||
)(action: Initialize[A1 => Task[A2]]): Initialize[InputTask[A2]] =
|
||||
p.zipWith(action)((parser, act) => free(parser)(act))
|
||||
|
||||
/*
|
||||
/** Constructs an InputTask that accepts no user input. */
|
||||
def createFree[T](action: Initialize[Task[T]]): Initialize[InputTask[T]] =
|
||||
action { tsk =>
|
||||
free(emptyParser)(const(tsk))
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructs an InputTask from:
|
||||
* a) a Parser constructed using other Settings, but not Tasks
|
||||
* b) a dynamically constructed Task that uses Settings, Tasks, and the result of parsing.
|
||||
*/
|
||||
def createDyn[I, T](
|
||||
p: Initialize[State => Parser[I]]
|
||||
)(action: Initialize[Task[I => Initialize[Task[T]]]]): Initialize[InputTask[T]] =
|
||||
separate(p)(std.FullInstance.flattenFun[I, T](action))
|
||||
def createDyn[A1, A2](
|
||||
p: Initialize[State => Parser[A1]]
|
||||
)(action: Initialize[Task[A1 => Initialize[Task[A2]]]]): Initialize[InputTask[A2]] =
|
||||
separate(p)(std.FullInstance.flattenFun[A1, A2](action))
|
||||
|
||||
/*
|
||||
/** A dummy parser that consumes no input and produces nothing useful (unit). */
|
||||
def emptyParser: State => Parser[Unit] =
|
||||
Types.const(sbt.internal.util.complete.DefaultParsers.success(()))
|
||||
|
|
|
|||
|
|
@ -236,7 +236,11 @@ sealed trait InputKey[A1]
|
|||
def in(scope: Scope): InputKey[A1] =
|
||||
Scoped.scopedInput(Scope.replaceThis(this.scope)(scope), this.key)
|
||||
|
||||
// inline def :=(inline v: A1): Setting[InputTask[A1]] = macro std.TaskMacro.inputTaskAssignMacroImpl[A1]
|
||||
private inline def inputTaskMacro[A2](inline a: A2): Def.Initialize[InputTask[A2]] =
|
||||
${ std.InputTaskMacro.inputTaskMacroImpl('a) }
|
||||
|
||||
inline def :=(inline a: A1): Setting[InputTask[A1]] =
|
||||
set(inputTaskMacro[A1](a))
|
||||
|
||||
final inline def ~=(f: A1 => A1): Setting[InputTask[A1]] = transform(f)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt
|
||||
package std
|
||||
|
||||
import sbt.internal.util.Types.Id
|
||||
import sbt.internal.util.complete.Parser
|
||||
import scala.quoted.*
|
||||
|
||||
object InputTaskMacro:
|
||||
import TaskMacro.ContSyntax.*
|
||||
|
||||
def inputTaskMacroImpl[A1: Type](tree: Expr[A1])(using
|
||||
qctx: Quotes
|
||||
): Expr[Def.Initialize[InputTask[A1]]] =
|
||||
inputTaskMacro0[A1](tree)
|
||||
|
||||
// def inputTaskDynMacroImpl[A1: Type](t: c.Expr[Initialize[Task[A1]]])(using qctx: Quotes): c.Expr[Initialize[InputTask[A1]]] =
|
||||
// inputTaskDynMacro0[A1](c)(t)
|
||||
|
||||
private[this] def inputTaskMacro0[A1: Type](tree: Expr[A1])(using
|
||||
qctx: Quotes
|
||||
): Expr[Def.Initialize[InputTask[A1]]] =
|
||||
import qctx.reflect.*
|
||||
// println(s"tree = ${tree.show}")
|
||||
iInitializeMacro(tree) { et =>
|
||||
val pt: Expr[State => Parser[Task[A1]]] = iParserMacro(et) { pt =>
|
||||
val tt = iTaskMacro(pt)
|
||||
// println(s"tt = ${tt.show}")
|
||||
tt
|
||||
}
|
||||
'{ InputTask.make($pt) }
|
||||
}
|
||||
|
||||
private[this] def iInitializeMacro[F1[_]: Type, A1: Type](tree: Expr[A1])(
|
||||
f: Expr[A1] => Expr[F1[A1]]
|
||||
)(using qctx: Quotes): Expr[Def.Initialize[F1[A1]]] =
|
||||
import qctx.reflect.*
|
||||
import InputWrapper.*
|
||||
val convert1 = new InputInitConvert(qctx)
|
||||
import convert1.Converted
|
||||
|
||||
def wrapInitTask[A2: Type](tree: Term): Term =
|
||||
val expr = tree.asExprOf[Def.Initialize[Task[A2]]]
|
||||
'{
|
||||
InputWrapper.`wrapTask_\u2603\u2603`[A2](InputWrapper.`wrapInit_\u2603\u2603`[A2]($expr))
|
||||
}.asTerm
|
||||
|
||||
def wrapInitParser[A2: Type](tree: Term): Term =
|
||||
val expr = tree.asExprOf[Def.Initialize[State => Parser[A2]]]
|
||||
'{
|
||||
ParserInput.`parser_\u2603\u2603`[A2](
|
||||
InputWrapper.`wrapInit_\u2603\u2603`[State => Parser[A2]]($expr)
|
||||
)
|
||||
}.asTerm
|
||||
|
||||
def wrapInitInput[A2: Type](tree: Term): Term =
|
||||
val expr = tree.asExprOf[Def.Initialize[InputTask[A2]]]
|
||||
wrapInput[A2]('{
|
||||
InputWrapper.`wrapInit_\u2603\u2603`[InputTask[A2]]($expr)
|
||||
}.asTerm)
|
||||
|
||||
def wrapInput[A2: Type](tree: Term): Term =
|
||||
val expr = tree.asExprOf[InputTask[A1]]
|
||||
'{
|
||||
InputWrapper.`wrapTask_\u2603\u2603`[A2](
|
||||
ParserInput.`parser_\u2603\u2603`[Task[A2]]($expr.parser)
|
||||
)
|
||||
}.asTerm
|
||||
|
||||
def expand(nme: String, tpeRepr: TypeRepr, tree: Term): Converted =
|
||||
tpeRepr.asType match
|
||||
case '[tpe] =>
|
||||
nme match
|
||||
case WrapInitTaskName => Converted.success(wrapInitTask[tpe](tree))
|
||||
case WrapPreviousName => Converted.success(wrapInitTask[tpe](tree))
|
||||
case ParserInput.WrapInitName => Converted.success(wrapInitParser[tpe](tree))
|
||||
case WrapInitInputName => Converted.success(wrapInitInput[tpe](tree))
|
||||
case WrapInputName => Converted.success(wrapInput[tpe](tree))
|
||||
case _ => Converted.NotApplicable()
|
||||
|
||||
def conditionInputTaskTree(t: Term): Term =
|
||||
convert1.transformWrappers(
|
||||
tree = t,
|
||||
subWrapper = (nme, tpe, tree, original) => expand(nme, tpe, tree),
|
||||
owner = Symbol.spliceOwner,
|
||||
)
|
||||
|
||||
val inner: convert1.TermTransform[F1] = (in: Term) => f(in.asExprOf[A1]).asTerm
|
||||
val cond = conditionInputTaskTree(tree.asTerm).asExprOf[A1]
|
||||
convert1.contMapN[A1, Def.Initialize, F1](cond, convert1.appExpr, inner)
|
||||
|
||||
private[this] def iParserMacro[F1[_]: Type, A1: Type](tree: Expr[A1])(
|
||||
f: Expr[A1] => Expr[F1[A1]]
|
||||
)(using qctx: Quotes): Expr[State => Parser[F1[A1]]] =
|
||||
import qctx.reflect.*
|
||||
val convert1 = new ParserConvert(qctx)
|
||||
val inner: convert1.TermTransform[F1] = (in: Term) => f(in.asExprOf[A1]).asTerm
|
||||
convert1.contMapN[A1, ParserInstance.F1, F1](tree, convert1.appExpr, inner)
|
||||
|
||||
private[this] def iTaskMacro[A1: Type](tree: Expr[A1])(using qctx: Quotes): Expr[Task[A1]] =
|
||||
import qctx.reflect.*
|
||||
val convert1 = new TaskConvert(qctx)
|
||||
convert1.contMapN[A1, Task, Id](tree, convert1.appExpr)
|
||||
|
||||
/*
|
||||
private[this] def inputTaskDynMacro0[A1: Type](
|
||||
expr: Expr[Def.Initialize[Task[A1]]]
|
||||
)(using qctx: Quotes): Expr[Def.Initialize[InputTask[A1]]] = {
|
||||
import qctx.reflect.{ Apply => ApplyTree, * }
|
||||
// import internal.decorators._
|
||||
val tag: Type[A1] = summon[Type[A1]]
|
||||
// val util = ContextUtil[c.type](c)
|
||||
val convert1 = new InitParserConvert(qctx)
|
||||
import convert1.Converted
|
||||
|
||||
// val it = Ident(convert1.singleton(InputTask))
|
||||
val isParserWrapper = new InitParserConvert(qctx).asPredicate
|
||||
val isTaskWrapper = new FullConvert(qctx).asPredicate
|
||||
val isAnyWrapper =
|
||||
(n: String, tpe: TypeRepr, tr: Term) =>
|
||||
isParserWrapper(n, tpe, tr) || isTaskWrapper(n, tpe, tr)
|
||||
val ttree = expr.asTerm
|
||||
val defs = convert1.collectDefs(ttree, isAnyWrapper)
|
||||
val checkQual =
|
||||
util.checkReferences(defs, isAnyWrapper, weakTypeOf[Def.Initialize[InputTask[Any]]])
|
||||
|
||||
// the Symbol for the anonymous function passed to the appropriate Instance.map/flatMap/pure method
|
||||
// this Symbol needs to be known up front so that it can be used as the owner of synthetic vals
|
||||
|
||||
// val functionSym = util.functionSymbol(ttree.pos)
|
||||
var result: Option[(Term, TypeRepr, ValDef)] = None
|
||||
|
||||
// original is the Tree being replaced. It is needed for preserving attributes.
|
||||
def subWrapper(tpe: TypeRepr, qual: Term, original: Term): Tree =
|
||||
if result.isDefined then
|
||||
report.errorAndAbort(
|
||||
"implementation restriction: a dynamic InputTask can only have a single input parser.",
|
||||
qual.pos,
|
||||
)
|
||||
Literal(UnitConstant())
|
||||
else {
|
||||
// qual.foreach(checkQual)
|
||||
val vd = util.freshValDef(tpe, qual.symbol.pos, functionSym) // val $x: <tpe>
|
||||
result = Some((qual, tpe, vd))
|
||||
val tree = util.refVal(original, vd) // $x
|
||||
tree.setPos(
|
||||
qual.pos
|
||||
) // position needs to be set so that wrapKey passes the position onto the wrapper
|
||||
assert(tree.tpe != null, "Null type: " + tree)
|
||||
tree.setType(tpe)
|
||||
tree
|
||||
}
|
||||
// Tree for InputTask.<name>[<tpeA>, <tpeB>](arg1)(arg2)
|
||||
def inputTaskCreate(name: String, tpeA: Type, tpeB: Type, arg1: Tree, arg2: Tree) = {
|
||||
val typedApp = TypeApply(util.select(it, name), TypeTree(tpeA) :: TypeTree(tpeB) :: Nil)
|
||||
val app = ApplyTree(ApplyTree(typedApp, arg1 :: Nil), arg2 :: Nil)
|
||||
Expr[Def.Initialize[InputTask[A1]]](app)
|
||||
}
|
||||
// Tree for InputTask.createFree[<tpe>](arg1)
|
||||
def inputTaskCreateFree(tpe: Type, arg: Tree) = {
|
||||
val typedApp = TypeApply(util.select(it, InputTaskCreateFreeName), TypeTree(tpe) :: Nil)
|
||||
val app = ApplyTree(typedApp, arg :: Nil)
|
||||
Expr[Def.Initialize[InputTask[A1]]](app)
|
||||
}
|
||||
def expandTask[I: Type](dyn: Boolean, tx: Tree): c.Expr[Initialize[Task[I]]] =
|
||||
if dyn then taskDynMacroImpl[I](c)(c.Expr[Initialize[Task[I]]](tx))
|
||||
else taskMacroImpl[I](c)(c.Expr[I](tx))
|
||||
def wrapTag[I: Type]: Type[Initialize[Task[I]]] = weakTypeTag
|
||||
|
||||
def sub(name: String, tpe: TypeRepr, qual: Term, oldTree: Term): Converted =
|
||||
convert1.convert[A1](name, qual) transform { (tree: Term) =>
|
||||
subWrapper(tpe, tree, oldTree)
|
||||
}
|
||||
|
||||
val inlined = convert1.inlineExtensionProxy(expr.asTerm)
|
||||
val tx =
|
||||
convert1.transformWrappers(inlined, sub, Symbol.spliceOwner)
|
||||
result match {
|
||||
case Some((p, tpe, param)) =>
|
||||
val fCore = util.createFunction(param :: Nil, tx, functionSym)
|
||||
val bodyTpe = wrapTag(tag).tpe
|
||||
val fTpe = util.functionType(tpe :: Nil, bodyTpe)
|
||||
val fTag = Type[Any](fTpe) // don't know the actual type yet, so use Any
|
||||
val fInit = expandTask(false, fCore)(fTag).tree
|
||||
inputTaskCreate(InputTaskCreateDynName, tpe, tag.tpe, p, fInit)
|
||||
case None =>
|
||||
val init = expandTask[A1](true, tx).tree
|
||||
inputTaskCreateFree(tag.tpe, init)
|
||||
}
|
||||
}
|
||||
*/
|
||||
end InputTaskMacro
|
||||
|
|
@ -64,9 +64,6 @@ object InputWrapper:
|
|||
private[this] def implDetailError =
|
||||
sys.error("This method is an implementation detail and should not be referenced.")
|
||||
|
||||
inline def wrapTask[A](in: Any): A = `wrapTask_\u2603\u2603`[A](in)
|
||||
inline def wrapInit[A](in: Any): A = `wrapInit_\u2603\u2603`[A](in)
|
||||
|
||||
/*
|
||||
private[std] def wrapInitInputTask[T: c.WeakTypeTag](using qctx: Quotes)(
|
||||
ts: c.Expr[Any],
|
||||
|
|
@ -237,9 +234,6 @@ object ParserInput:
|
|||
def `initParser_\u2603\u2603`[T](@deprecated("unused", "") i: Any): T =
|
||||
sys.error("This method is an implementation detail and should not be referenced.")
|
||||
|
||||
inline def wrap[A1](in: Any): A1 = `parser_\u2603\u2603`[A1](in)
|
||||
inline def wrapInit[A1](in: Any): A1 = `initParser_\u2603\u2603`[A1](in)
|
||||
|
||||
/*
|
||||
private[std] def inputParser[T: c.WeakTypeTag](
|
||||
using qctx: Quotes
|
||||
|
|
|
|||
|
|
@ -87,18 +87,23 @@ object FullInstance:
|
|||
(a, data).flatMap { case (a, d) => f(a) evaluate d }
|
||||
}(AList.tuple3[Task[Initialize[Task[A1]]], Task[SS], [a] => Initialize[a] => Initialize[a]])
|
||||
|
||||
/*
|
||||
def flattenFun[S, T](
|
||||
in: Initialize[Task[S => Initialize[Task[A1]]]]
|
||||
): Initialize[S => Task[A1]] = {
|
||||
def flattenFun[A1, A2](
|
||||
in: Initialize[Task[A1 => Initialize[Task[A2]]]]
|
||||
): Initialize[A1 => Task[A2]] =
|
||||
type K[L[x]] =
|
||||
AList.T3K[Task[S => Initialize[Task[A1]]], Task[SS], Initialize ~> Initialize]#l[L]
|
||||
Def.app[K, S => Task[A1]]((in, settingsData, Def.capturedTransformations)) {
|
||||
case (a: Task[S => Initialize[Task[A1]]], data: Task[SS], f) => { (s: S) =>
|
||||
import TaskExtra.multT2Task
|
||||
(a, data) flatMap { case (af, d) => f(af(s)) evaluate d }
|
||||
AList.Tuple3K[Task[A1 => Initialize[Task[A2]]], Task[SS], [a] => Initialize[a] => Initialize[
|
||||
a
|
||||
]][L]
|
||||
Def.app[K, A1 => Task[A2]]((in, settingsData, Def.capturedTransformations)) {
|
||||
case (a: Task[A1 => Initialize[Task[A2]]] @unchecked, data: Task[SS] @unchecked, f) => {
|
||||
(s: A1) =>
|
||||
import TaskExtra.multT2Task
|
||||
(a, data) flatMap { case (af, d) => f(af(s)) evaluate d }
|
||||
}
|
||||
}(AList.tuple3)
|
||||
}
|
||||
*/
|
||||
}(
|
||||
AList.tuple3[Task[A1 => Initialize[Task[A2]]], Task[SS], [a] => Initialize[a] => Initialize[
|
||||
a
|
||||
]]
|
||||
)
|
||||
|
||||
end FullInstance
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import sbt.internal.util.appmacro.{
|
|||
}
|
||||
// import Instance.Transform
|
||||
import sbt.internal.util.{ AList, LinePosition, NoPosition, SourcePosition, ~> }
|
||||
import sbt.internal.util.complete.Parser
|
||||
|
||||
import language.experimental.macros
|
||||
import scala.annotation.tailrec
|
||||
|
|
@ -158,15 +157,6 @@ object TaskMacro:
|
|||
$rec.set0($app, $sourcePosition)
|
||||
}
|
||||
|
||||
/** Implementation of := macro for tasks. */
|
||||
def inputTaskAssignMacroImpl[A1: Type](v: Expr[A1])(using
|
||||
qctx: Quotes
|
||||
): Expr[Setting[InputTask[A1]]] =
|
||||
val init = inputTaskMacroImpl[A1](v)
|
||||
// val assign = transformMacroImpl(init.tree)(AssignInitName)
|
||||
// Expr[Setting[InputTask[A1]]](assign)
|
||||
???
|
||||
|
||||
/** Implementation of += macro for settings. */
|
||||
def settingAppend1Impl[A1: Type, A2: Type](rec: Expr[SettingKey[A1]], v: Expr[A2])(using
|
||||
qctx: Quotes,
|
||||
|
|
@ -238,176 +228,6 @@ object TaskMacro:
|
|||
c.Expr[A1](Literal(Constant(t)))
|
||||
}
|
||||
*/
|
||||
|
||||
def inputTaskMacroImpl[A1: Type](tree: Expr[A1])(using
|
||||
qctx: Quotes
|
||||
): Expr[Initialize[InputTask[A1]]] =
|
||||
inputTaskMacro0[A1](tree)
|
||||
|
||||
// def inputTaskDynMacroImpl[A1: Type](t: c.Expr[Initialize[Task[A1]]])(using qctx: Quotes): c.Expr[Initialize[InputTask[A1]]] =
|
||||
// inputTaskDynMacro0[A1](c)(t)
|
||||
|
||||
private[this] def inputTaskMacro0[A1: Type](tree: Expr[A1])(using
|
||||
qctx: Quotes
|
||||
): Expr[Initialize[InputTask[A1]]] =
|
||||
iInitializeMacro(tree) { et =>
|
||||
val pt = iParserMacro(et) { pt =>
|
||||
iTaskMacro(pt)
|
||||
}
|
||||
'{ InputTask.make($pt) }
|
||||
}
|
||||
|
||||
private[this] def iInitializeMacro[F1[_]: Type, A1: Type](tree: Expr[A1])(
|
||||
f: Expr[A1] => Expr[F1[A1]]
|
||||
)(using qctx: Quotes): Expr[Initialize[F1[A1]]] =
|
||||
import qctx.reflect.*
|
||||
import InputWrapper.*
|
||||
val convert1 = new InputInitConvert(qctx)
|
||||
import convert1.Converted
|
||||
|
||||
def wrapInitTask[A2: Type](tree: Term): Term =
|
||||
val expr = tree.asExprOf[Initialize[Task[A2]]]
|
||||
'{
|
||||
InputWrapper.wrapTask[A2](InputWrapper.wrapInit[A2]($expr))
|
||||
}.asTerm
|
||||
|
||||
def wrapInitParser[A2: Type](tree: Term): Term =
|
||||
val expr = tree.asExprOf[Initialize[State => Parser[A2]]]
|
||||
'{
|
||||
ParserInput.wrap[A2](InputWrapper.wrapInit[State => Parser[A2]]($expr))
|
||||
}.asTerm
|
||||
|
||||
def wrapInitInput[A2: Type](tree: Term): Term =
|
||||
val expr = tree.asExprOf[Initialize[InputTask[A2]]]
|
||||
wrapInput[A2]('{
|
||||
InputWrapper.wrapInit[InputTask[A2]]($expr)
|
||||
}.asTerm)
|
||||
|
||||
def wrapInput[A2: Type](tree: Term): Term =
|
||||
val expr = tree.asExprOf[InputTask[A1]]
|
||||
'{
|
||||
InputWrapper.wrapTask[A2](ParserInput.wrap[Task[A2]]($expr.parser))
|
||||
}.asTerm
|
||||
|
||||
def expand(nme: String, tpeRepr: TypeRepr, tree: Term): Converted =
|
||||
tpeRepr.asType match
|
||||
case '[tpe] =>
|
||||
nme match
|
||||
case WrapInitTaskName => Converted.success(wrapInitTask[tpe](tree))
|
||||
case WrapPreviousName => Converted.success(wrapInitTask[tpe](tree))
|
||||
case ParserInput.WrapInitName => Converted.success(wrapInitParser[tpe](tree))
|
||||
case WrapInitInputName => Converted.success(wrapInitInput[tpe](tree))
|
||||
case WrapInputName => Converted.success(wrapInput[tpe](tree))
|
||||
case _ => Converted.NotApplicable()
|
||||
|
||||
def conditionInputTaskTree(t: Term): Term =
|
||||
convert1.transformWrappers(
|
||||
tree = t,
|
||||
subWrapper = (nme, tpe, tree, original) => expand(nme, tpe, tree),
|
||||
owner = Symbol.spliceOwner,
|
||||
)
|
||||
|
||||
val inner: convert1.TermTransform[F1] = (in: Term) => f(in.asExprOf[A1]).asTerm
|
||||
val cond = conditionInputTaskTree(tree.asTerm).asExprOf[A1]
|
||||
convert1.contMapN[A1, Def.Initialize, F1](cond, convert1.appExpr, inner)
|
||||
|
||||
private[this] def iParserMacro[F1[_]: Type, A1: Type](tree: Expr[A1])(
|
||||
f: Expr[A1] => Expr[F1[A1]]
|
||||
)(using qctx: Quotes): Expr[State => Parser[F1[A1]]] =
|
||||
import qctx.reflect.*
|
||||
val convert1 = new ParserConvert(qctx)
|
||||
val inner: convert1.TermTransform[F1] = (in: Term) => f(in.asExprOf[A1]).asTerm
|
||||
convert1.contMapN[A1, ParserInstance.F1, F1](tree, convert1.appExpr, inner)
|
||||
|
||||
private[this] def iTaskMacro[A1: Type](tree: Expr[A1])(using qctx: Quotes): Expr[Task[A1]] =
|
||||
import qctx.reflect.*
|
||||
val convert1 = new TaskConvert(qctx)
|
||||
convert1.contMapN[A1, Task, Id](tree, convert1.appExpr)
|
||||
|
||||
/*
|
||||
private[this] def inputTaskDynMacro0[A1: Type](
|
||||
t: Expr[Initialize[Task[A1]]]
|
||||
)(using qctx: Quotes): Expr[Initialize[InputTask[A1]]] = {
|
||||
import c.universe.{ Apply => ApplyTree, _ }
|
||||
import internal.decorators._
|
||||
|
||||
val tag = implicitly[Type[A1]]
|
||||
val util = ContextUtil[c.type](c)
|
||||
val it = Ident(util.singleton(InputTask))
|
||||
val isParserWrapper = InitParserConvert.asPredicate(c)
|
||||
val isTaskWrapper = FullConvert.asPredicate(c)
|
||||
val isAnyWrapper = (n: String, tpe: Type, tr: Tree) =>
|
||||
isParserWrapper(n, tpe, tr) || isTaskWrapper(n, tpe, tr)
|
||||
val ttree = t.tree
|
||||
val defs = util.collectDefs(ttree, isAnyWrapper)
|
||||
val checkQual = util.checkReferences(defs, isAnyWrapper, weakTypeOf[Initialize[InputTask[Any]]])
|
||||
|
||||
// the Symbol for the anonymous function passed to the appropriate Instance.map/flatMap/pure method
|
||||
// this Symbol needs to be known up front so that it can be used as the owner of synthetic vals
|
||||
val functionSym = util.functionSymbol(ttree.pos)
|
||||
var result: Option[(Tree, Type, ValDef)] = None
|
||||
|
||||
// original is the Tree being replaced. It is needed for preserving attributes.
|
||||
def subWrapper(tpe: Type, qual: Tree, original: Tree): Tree =
|
||||
if (result.isDefined) {
|
||||
c.error(
|
||||
qual.pos,
|
||||
"Implementation restriction: a dynamic InputTask can only have a single input parser."
|
||||
)
|
||||
EmptyTree
|
||||
} else {
|
||||
qual.foreach(checkQual)
|
||||
val vd = util.freshValDef(tpe, qual.symbol.pos, functionSym) // val $x: <tpe>
|
||||
result = Some((qual, tpe, vd))
|
||||
val tree = util.refVal(original, vd) // $x
|
||||
tree.setPos(
|
||||
qual.pos
|
||||
) // position needs to be set so that wrapKey passes the position onto the wrapper
|
||||
assert(tree.tpe != null, "Null type: " + tree)
|
||||
tree.setType(tpe)
|
||||
tree
|
||||
}
|
||||
// Tree for InputTask.<name>[<tpeA>, <tpeB>](arg1)(arg2)
|
||||
def inputTaskCreate(name: String, tpeA: Type, tpeB: Type, arg1: Tree, arg2: Tree) = {
|
||||
val typedApp = TypeApply(util.select(it, name), TypeTree(tpeA) :: TypeTree(tpeB) :: Nil)
|
||||
val app = ApplyTree(ApplyTree(typedApp, arg1 :: Nil), arg2 :: Nil)
|
||||
c.Expr[Initialize[InputTask[A1]]](app)
|
||||
}
|
||||
// Tree for InputTask.createFree[<tpe>](arg1)
|
||||
def inputTaskCreateFree(tpe: Type, arg: Tree) = {
|
||||
val typedApp = TypeApply(util.select(it, InputTaskCreateFreeName), TypeTree(tpe) :: Nil)
|
||||
val app = ApplyTree(typedApp, arg :: Nil)
|
||||
c.Expr[Initialize[InputTask[A1]]](app)
|
||||
}
|
||||
def expandTask[I: WeakTypeTag](dyn: Boolean, tx: Tree): c.Expr[Initialize[Task[I]]] =
|
||||
if (dyn)
|
||||
taskDynMacroImpl[I](c)(c.Expr[Initialize[Task[I]]](tx))
|
||||
else
|
||||
taskMacroImpl[I](c)(c.Expr[I](tx))
|
||||
def wrapTag[I: WeakTypeTag]: WeakTypeTag[Initialize[Task[I]]] = weakTypeTag
|
||||
|
||||
def sub(name: String, tpe: Type, qual: Tree, selection: Tree): Converted[c.type] = {
|
||||
val tag = Type[A1](tpe)
|
||||
InitParserConvert(c)(name, qual)(tag) transform { tree =>
|
||||
subWrapper(tpe, tree, selection)
|
||||
}
|
||||
}
|
||||
|
||||
val tx = util.transformWrappers(ttree, (n, tpe, tree, replace) => sub(n, tpe, tree, replace))
|
||||
result match {
|
||||
case Some((p, tpe, param)) =>
|
||||
val fCore = util.createFunction(param :: Nil, tx, functionSym)
|
||||
val bodyTpe = wrapTag(tag).tpe
|
||||
val fTpe = util.functionType(tpe :: Nil, bodyTpe)
|
||||
val fTag = Type[Any](fTpe) // don't know the actual type yet, so use Any
|
||||
val fInit = expandTask(false, fCore)(fTag).tree
|
||||
inputTaskCreate(InputTaskCreateDynName, tpe, tag.tpe, p, fInit)
|
||||
case None =>
|
||||
val init = expandTask[A1](true, tx).tree
|
||||
inputTaskCreateFree(tag.tpe, init)
|
||||
}
|
||||
}
|
||||
*/
|
||||
end TaskMacro
|
||||
|
||||
object DefinableTaskMacro:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import sbt.internal.util.complete
|
|||
import sbt.internal.util.complete.DefaultParsers
|
||||
import sbt.{ Def, InputTask, Task }
|
||||
import sbt.Def.parsed
|
||||
import sbt.Def.value
|
||||
|
||||
object UseTask:
|
||||
val set = Def.setting { 23 }
|
||||
|
|
@ -91,30 +92,36 @@ object Assign {
|
|||
//
|
||||
tsk.parsed // "as" //dummy.value.parsed
|
||||
}
|
||||
// val it2 = Def.inputTask {
|
||||
// "lit"
|
||||
// }
|
||||
val it2 = Def.inputTask {
|
||||
"lit"
|
||||
}
|
||||
|
||||
val it3: Initialize[InputTask[String]] = Def.inputTask[String] {
|
||||
itsk.parsed.value.toString
|
||||
}
|
||||
|
||||
val it3b: Initialize[InputTask[String]] = Def.inputTask[String] {
|
||||
tsk.parsed.value + itsk.parsed.value.toString + isk.evaluated
|
||||
}
|
||||
|
||||
// should not compile: cannot use a task to define the parser
|
||||
/* val it4 = Def.inputTask {
|
||||
dummyt.value.parsed
|
||||
}*/
|
||||
// should compile: can use a setting to define the parser
|
||||
val it5 = Def.inputTask {
|
||||
dummys.parsed
|
||||
}
|
||||
|
||||
// val it3: Initialize[InputTask[String]] = Def.inputTask[String] {
|
||||
// tsk.parsed.value + itsk.parsed.value.toString + isk.evaluated
|
||||
// }
|
||||
// // should not compile: cannot use a task to define the parser
|
||||
// /* val it4 = Def.inputTask {
|
||||
// dummyt.value.parsed
|
||||
// }*/
|
||||
// // should compile: can use a setting to define the parser
|
||||
// val it5 = Def.inputTask {
|
||||
// dummys.parsed
|
||||
// }
|
||||
// val it6 = Def.inputTaskDyn {
|
||||
// val d3 = dummy3.parsed
|
||||
// val i = d3._2
|
||||
// Def.task { tk.value + i }
|
||||
// }
|
||||
|
||||
// val it7 = Def.inputTask {
|
||||
// it5.parsed
|
||||
// }
|
||||
val it7 = Def.inputTask {
|
||||
it5.parsed
|
||||
}
|
||||
|
||||
// def bool: Initialize[Boolean] = Def.setting { true }
|
||||
// def enabledOnly[T](key: Initialize[T]): Initialize[Seq[T]] = Def.setting {
|
||||
|
|
|
|||
Loading…
Reference in New Issue