mirror of https://github.com/sbt/sbt.git
Implement input task helper Def.input
This commit is contained in:
parent
441f56bf6e
commit
61d4fe2d30
|
|
@ -234,6 +234,9 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits:
|
|||
|
||||
// def settingDyn[T](t: Def.Initialize[T]): Def.Initialize[T] = macro settingDynMacroImpl[T]
|
||||
|
||||
inline def input[A1](inline p: State => Parser[A1]): ParserGen[A1] =
|
||||
${ SettingMacro.inputMacroImpl[A1]('p) }
|
||||
|
||||
inline def inputTask[A1](inline a: A1): Def.Initialize[InputTask[A1]] =
|
||||
${ InputTaskMacro.inputTaskMacroImpl[A1]('a) }
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import std.TaskExtra._
|
|||
import sbt.internal.util.{ ~>, AttributeKey, Types }
|
||||
import sbt.internal.util.Types._
|
||||
import sbt.internal.util.Util._
|
||||
import sbt.util.Applicative
|
||||
|
||||
/** Parses input and produces a task to run. Constructed using the companion object. */
|
||||
final class InputTask[A1] private (val parser: State => Parser[Task[A1]]):
|
||||
|
|
@ -86,13 +87,14 @@ object InputTask:
|
|||
)(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))
|
||||
}
|
||||
*/
|
||||
|
||||
def createFreeFromAction[A1](a: () => A1): InputTask[A1] =
|
||||
free(emptyParser)(_ => Task.taskMonad.pure(a))
|
||||
|
||||
/**
|
||||
* Constructs an InputTask from:
|
||||
|
|
@ -104,11 +106,11 @@ object InputTask:
|
|||
)(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(()))
|
||||
|
||||
/*
|
||||
/** Implementation detail that is public because it is used by a macro. */
|
||||
def parserAsInput[T](p: Parser[T]): Initialize[State => Parser[T]] =
|
||||
Def.valueStrict(Types.const(p))
|
||||
|
|
@ -181,4 +183,28 @@ object InputTask:
|
|||
f(task)
|
||||
}
|
||||
*/
|
||||
|
||||
given inputTaskApplicative: Applicative[InputTask] with
|
||||
type F[a] = InputTask[a]
|
||||
override def pure[A1](a: () => A1): InputTask[A1] = InputTask.createFreeFromAction(a)
|
||||
override def ap[A1, A2](ff: InputTask[A1 => A2])(in: InputTask[A1]): InputTask[A2] =
|
||||
InputTask[A2]((s: State) =>
|
||||
(in.parser(s) ~ ff.parser(s)).map { case (ta1, tf) =>
|
||||
Task.taskMonad.ap(tf)(ta1)
|
||||
}
|
||||
)
|
||||
override def map[A1, A2](in: InputTask[A1])(f: A1 => A2): InputTask[A2] =
|
||||
InputTask[A2]((s: State) =>
|
||||
in.parser(s).map { ta1 =>
|
||||
ta1.map(f)
|
||||
}
|
||||
)
|
||||
end InputTask
|
||||
|
||||
class ParserGen[A1](val p: Initialize[State => Parser[A1]]):
|
||||
inline def mapTask[A2](inline action: A1 => A2): Initialize[InputTask[A2]] =
|
||||
${ std.InputTaskMacro.parserGenInputTaskMacroImpl[A1, A2]('this, 'action) }
|
||||
|
||||
inline def flatMapTask[A2](inline action: A1 => Initialize[Task[A2]]): Initialize[InputTask[A2]] =
|
||||
${ std.InputTaskMacro.parserGenFlatMapTaskImpl[A1, A2]('this, 'action) }
|
||||
end ParserGen
|
||||
|
|
|
|||
|
|
@ -195,4 +195,70 @@ object InputTaskMacro:
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
def parserGenInputTaskMacroImpl[A1: Type, A2: Type](
|
||||
parserGen: Expr[ParserGen[A1]],
|
||||
tree: Expr[A1 => A2]
|
||||
)(using
|
||||
qctx: Quotes
|
||||
): Expr[Def.Initialize[InputTask[A2]]] =
|
||||
inputTaskMacro0[A2]('{
|
||||
val `arg$` = $parserGen.p.parsed
|
||||
$tree(`arg$`)
|
||||
})
|
||||
|
||||
def parserGenFlatMapTaskImpl[A1: Type, A2: Type](
|
||||
parserGen: Expr[ParserGen[A1]],
|
||||
tree: Expr[A1 => Def.Initialize[Task[A2]]]
|
||||
)(using
|
||||
qctx: Quotes
|
||||
): Expr[Def.Initialize[InputTask[A2]]] =
|
||||
import qctx.reflect.*
|
||||
val convert1 = new FullConvert(qctx) // 1000
|
||||
import convert1.Converted
|
||||
def mkInputTask(params: List[ValDef], body: Term): Expr[Def.Initialize[InputTask[A2]]] =
|
||||
val lambdaTpe =
|
||||
MethodType(params.map(_.name))(
|
||||
_ => List(TypeRepr.of[A1]),
|
||||
_ => TypeRepr.of[Def.Initialize[Task[A2]]]
|
||||
)
|
||||
val lambda = Lambda(
|
||||
owner = Symbol.spliceOwner,
|
||||
tpe = lambdaTpe,
|
||||
rhsFn = (sym, params) => {
|
||||
val p0 = params.head.asInstanceOf[Ident]
|
||||
val body2 =
|
||||
convert1
|
||||
.contFlatMap[A2, TaskMacro.F, Id](body.asExprOf[TaskMacro.F[A2]], convert1.appExpr)
|
||||
.asTerm
|
||||
object refTransformer extends TreeMap:
|
||||
override def transformTerm(tree: Term)(owner: Symbol): Term =
|
||||
tree match
|
||||
case Ident(name) if name == p0.name => Ref(p0.symbol)
|
||||
case _ => super.transformTerm(tree)(owner)
|
||||
end refTransformer
|
||||
refTransformer.transformTerm(body2.changeOwner(sym))(sym)
|
||||
}
|
||||
)
|
||||
val action = lambda.asExprOf[A1 => Def.Initialize[Task[A2]]]
|
||||
'{
|
||||
InputTask.createDyn[A1, A2](${ parserGen }.p)(
|
||||
Def.valueStrict(TaskExtra.task[A1 => Def.Initialize[Task[A2]]]($action))
|
||||
)
|
||||
}
|
||||
tree.asTerm match
|
||||
case Lambda(params, body) =>
|
||||
mkInputTask(params, body)
|
||||
case Inlined(
|
||||
_,
|
||||
_,
|
||||
Lambda(params, body),
|
||||
) =>
|
||||
mkInputTask(params, body)
|
||||
case Inlined(
|
||||
_,
|
||||
_,
|
||||
Block(List(), Lambda(params, body)),
|
||||
) =>
|
||||
mkInputTask(params, body)
|
||||
end InputTaskMacro
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import sbt.internal.util.appmacro.{
|
|||
}
|
||||
import sbt.util.Applicative
|
||||
import scala.quoted.*
|
||||
import sbt.internal.util.complete.Parser
|
||||
|
||||
class InitializeConvert[C <: Quotes & scala.Singleton](override val qctx: C)
|
||||
extends Convert[C](qctx)
|
||||
|
|
@ -48,14 +49,14 @@ object SettingMacro:
|
|||
val convert1 = InitializeConvert(qctx)
|
||||
convert1.contMapN[A1, F, Id](in, convert1.appExpr)
|
||||
|
||||
/*
|
||||
def settingDynMacroImpl[T: c.WeakTypeTag](
|
||||
c: blackbox.Context
|
||||
)(t: c.Expr[Initialize[T]]): c.Expr[Initialize[T]] =
|
||||
Instance.contImpl[T, Id](c, InitializeInstance, InitializeConvert, MixedBuilder, EmptyLinter)(
|
||||
Right(t),
|
||||
Instance.idTransform[c.type]
|
||||
)
|
||||
*/
|
||||
def settingDynImpl[A1: Type](in: Expr[Initialize[A1]])(using qctx: Quotes): Expr[Initialize[A1]] =
|
||||
val convert1 = InitializeConvert(qctx)
|
||||
convert1.contFlatMap[A1, F, Id](in, convert1.appExpr)
|
||||
|
||||
def inputMacroImpl[A1: Type](in: Expr[State => Parser[A1]])(using
|
||||
qctx: Quotes
|
||||
): Expr[ParserGen[A1]] =
|
||||
val convert1 = InitializeConvert(qctx)
|
||||
val init1 = convert1.contMapN[State => Parser[A1], F, Id](in, convert1.appExpr)
|
||||
'{ ParserGen[A1]($init1) }
|
||||
end SettingMacro
|
||||
|
|
|
|||
|
|
@ -1439,8 +1439,7 @@ object Defaults extends BuildCommon {
|
|||
|
||||
private[this] lazy val inputTests0: Initialize[InputTask[Unit]] = {
|
||||
val parser = loadForParser(definedTestNames)((s, i) => testOnlyParser(s, i getOrElse Nil))
|
||||
Def.inputTaskDyn {
|
||||
val (selected, frameworkOptions) = parser.parsed
|
||||
ParserGen(parser).flatMapTask { case ((selected, frameworkOptions)) =>
|
||||
val s = streams.value
|
||||
val filter = testFilter.value
|
||||
val config = testExecution.value
|
||||
|
|
|
|||
Loading…
Reference in New Issue