Fix InputTask macro

This commit is contained in:
Eugene Yokota 2022-09-18 19:38:31 -04:00
parent 7e5fbcd92b
commit 66fa46a912
10 changed files with 294 additions and 237 deletions

View File

@ -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

View File

@ -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

View File

@ -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] =
// ???

View File

@ -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(()))

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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 {