src/argv.bend source
src/argv.bend on the hub · documented module
# src/argv: what `run`, `exec` and `start` do with an argv. `run.plan` decides# whether it can reach its program whole, and hands the effect `wire(argv)`# only then; `run.with` and `start.with` perform the plan with an effect given# as a parameter, so a refused plan can be seen to call none. `cmd` is the# newline wire ez's `pass` effect reads.import Base# the arguments joined on newlines, which is the wire ez's `pass` effect# reads. snap's own effects are handed `wire` and `par.plan`, since an# argument may hold a newline.def cmd(argv: List<&2, String>) -> String: String.join(argv, "\n")# the arguments joined on newlines; the same as `cmd`def line(argv: List<&2, String>) -> String: cmd(argv)# whether a string holds no copy of a chardef free_of(text: String, +sep: Char) -> Bool: match text: case SNil{}: True{} case SCon{ch, tail}: rest = free_of(tail, sep) Bool.and(Bool.not(Char.is_eq(ch, sep)), rest)# whether no string of a list holds a copy of a chardef free_of.all(ps: List<&2, String>, +sep: Char) -> Bool: match ps: case []: True{} case pc <> pt: rest = free_of.all(pt, sep) Bool.and(free_of(pc, sep), rest)# whether an argv can reach its program whole: it names a program, and no# argument holds NUL, which separates them on the wire and which no program# could be handed inside an argument anywaydef accepts(argv: List<&2, String>) -> Bool: match argv: case []: False{} case +prog <> +args: Bool.and(Bool.not(String.is_empty(prog)), free_of.all(prog <> args, '\0'))# the arguments as the effects want them: joined on NUL, the one char no# argument can hold, so each is split back out wholedef wire(argv: List<&2, String>) -> String: String.join(argv, "\0")# what a call does with its argv: refuse it, or hand the effect this wiretype Step is Data: Refused{} Run{wire: String}# an argv accepted is run; any other is refuseddef run.plan.of(ok: Bool, argv: List<&2, String>) -> Step: match ok: case True{}: Run{wire(argv)} case False{}: Refused{}# what `run`, `exec` and `start` do with an argv. It decides everything: the# effect is called only with the wire of an argv this accepts.def run.plan(+argv: List<&2, String>) -> Step: run.plan.of(accepts(argv), argv)# a step performed by an effect that waits: a refused argv answers as a# program that could not be started, and the effect is never calleddef run.with(eff: String -> IO(String), step: Step) -> IO(String): match step: case Refused{}: IO.pure(String, "127\n") case Run{w}: eff(w)# a step performed by an effect that does not wait: a refused argv answers# as a program that could not be started, and the effect is never calleddef start.with(eff: String -> IO(String), step: Step) -> IO(String): match step: case Refused{}: IO.pure(String, "0") case Run{w}: eff(w)