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]
|
// 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]] =
|
inline def inputTask[A1](inline a: A1): Def.Initialize[InputTask[A1]] =
|
||||||
${ InputTaskMacro.inputTaskMacroImpl[A1]('a) }
|
${ InputTaskMacro.inputTaskMacroImpl[A1]('a) }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import std.TaskExtra._
|
||||||
import sbt.internal.util.{ ~>, AttributeKey, Types }
|
import sbt.internal.util.{ ~>, AttributeKey, Types }
|
||||||
import sbt.internal.util.Types._
|
import sbt.internal.util.Types._
|
||||||
import sbt.internal.util.Util._
|
import sbt.internal.util.Util._
|
||||||
|
import sbt.util.Applicative
|
||||||
|
|
||||||
/** Parses input and produces a task to run. Constructed using the companion object. */
|
/** Parses input and produces a task to run. Constructed using the companion object. */
|
||||||
final class InputTask[A1] private (val parser: State => Parser[Task[A1]]):
|
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]] =
|
)(action: Initialize[A1 => Task[A2]]): Initialize[InputTask[A2]] =
|
||||||
p.zipWith(action)((parser, act) => free(parser)(act))
|
p.zipWith(action)((parser, act) => free(parser)(act))
|
||||||
|
|
||||||
/*
|
|
||||||
/** Constructs an InputTask that accepts no user input. */
|
/** Constructs an InputTask that accepts no user input. */
|
||||||
def createFree[T](action: Initialize[Task[T]]): Initialize[InputTask[T]] =
|
def createFree[T](action: Initialize[Task[T]]): Initialize[InputTask[T]] =
|
||||||
action { tsk =>
|
action { tsk =>
|
||||||
free(emptyParser)(const(tsk))
|
free(emptyParser)(const(tsk))
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
def createFreeFromAction[A1](a: () => A1): InputTask[A1] =
|
||||||
|
free(emptyParser)(_ => Task.taskMonad.pure(a))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an InputTask from:
|
* Constructs an InputTask from:
|
||||||
|
|
@ -104,11 +106,11 @@ object InputTask:
|
||||||
)(action: Initialize[Task[A1 => Initialize[Task[A2]]]]): Initialize[InputTask[A2]] =
|
)(action: Initialize[Task[A1 => Initialize[Task[A2]]]]): Initialize[InputTask[A2]] =
|
||||||
separate(p)(std.FullInstance.flattenFun[A1, A2](action))
|
separate(p)(std.FullInstance.flattenFun[A1, A2](action))
|
||||||
|
|
||||||
/*
|
|
||||||
/** A dummy parser that consumes no input and produces nothing useful (unit). */
|
/** A dummy parser that consumes no input and produces nothing useful (unit). */
|
||||||
def emptyParser: State => Parser[Unit] =
|
def emptyParser: State => Parser[Unit] =
|
||||||
Types.const(sbt.internal.util.complete.DefaultParsers.success(()))
|
Types.const(sbt.internal.util.complete.DefaultParsers.success(()))
|
||||||
|
|
||||||
|
/*
|
||||||
/** Implementation detail that is public because it is used by a macro. */
|
/** Implementation detail that is public because it is used by a macro. */
|
||||||
def parserAsInput[T](p: Parser[T]): Initialize[State => Parser[T]] =
|
def parserAsInput[T](p: Parser[T]): Initialize[State => Parser[T]] =
|
||||||
Def.valueStrict(Types.const(p))
|
Def.valueStrict(Types.const(p))
|
||||||
|
|
@ -181,4 +183,28 @@ object InputTask:
|
||||||
f(task)
|
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
|
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
|
end InputTaskMacro
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import sbt.internal.util.appmacro.{
|
||||||
}
|
}
|
||||||
import sbt.util.Applicative
|
import sbt.util.Applicative
|
||||||
import scala.quoted.*
|
import scala.quoted.*
|
||||||
|
import sbt.internal.util.complete.Parser
|
||||||
|
|
||||||
class InitializeConvert[C <: Quotes & scala.Singleton](override val qctx: C)
|
class InitializeConvert[C <: Quotes & scala.Singleton](override val qctx: C)
|
||||||
extends Convert[C](qctx)
|
extends Convert[C](qctx)
|
||||||
|
|
@ -48,14 +49,14 @@ object SettingMacro:
|
||||||
val convert1 = InitializeConvert(qctx)
|
val convert1 = InitializeConvert(qctx)
|
||||||
convert1.contMapN[A1, F, Id](in, convert1.appExpr)
|
convert1.contMapN[A1, F, Id](in, convert1.appExpr)
|
||||||
|
|
||||||
/*
|
def settingDynImpl[A1: Type](in: Expr[Initialize[A1]])(using qctx: Quotes): Expr[Initialize[A1]] =
|
||||||
def settingDynMacroImpl[T: c.WeakTypeTag](
|
val convert1 = InitializeConvert(qctx)
|
||||||
c: blackbox.Context
|
convert1.contFlatMap[A1, F, Id](in, convert1.appExpr)
|
||||||
)(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 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
|
end SettingMacro
|
||||||
|
|
|
||||||
|
|
@ -1439,8 +1439,7 @@ object Defaults extends BuildCommon {
|
||||||
|
|
||||||
private[this] lazy val inputTests0: Initialize[InputTask[Unit]] = {
|
private[this] lazy val inputTests0: Initialize[InputTask[Unit]] = {
|
||||||
val parser = loadForParser(definedTestNames)((s, i) => testOnlyParser(s, i getOrElse Nil))
|
val parser = loadForParser(definedTestNames)((s, i) => testOnlyParser(s, i getOrElse Nil))
|
||||||
Def.inputTaskDyn {
|
ParserGen(parser).flatMapTask { case ((selected, frameworkOptions)) =>
|
||||||
val (selected, frameworkOptions) = parser.parsed
|
|
||||||
val s = streams.value
|
val s = streams.value
|
||||||
val filter = testFilter.value
|
val filter = testFilter.value
|
||||||
val config = testExecution.value
|
val config = testExecution.value
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue