srvargs.bend

cswap-bend-cli@0.1.0.0 · 104 lines · 17 definitions

1import Base
2import cswap-bend-cli@0.1.0.0/fmt/out.bend as O
3
4# The command line of `cswap rpc [--format json|toon|yaml]` and
5# `cswap serve --socket PATH [--format json|toon|yaml]`. Pure.
6
7type Plan is Data:
8  PRpc{fmt: O.Fmt}
9  PServe{path: String, fmt: O.Fmt}
10  PBad{msg: String}
11
12type A is Data:
13  A{fmt: Maybe<&2, String>, socket: Maybe<&2, String>, err: String, want: String}
14
15def err(+a: A, msg: String) -> A:
16  match a:
17    case A{fmt, socket, e, w}:
18      A{fmt, socket, Bool.pick(String, String.is_empty(e), msg, e), ""}
19
20def got(+a: A, +v: String) -> A:
21  match a:
22    case A{fmt, socket, e, w}:
23      Bool.pick(A, String.eq(w, "--format"), A{Some{v}, socket, e, ""}, A{fmt, Some{v}, e, ""})
24
25def want(+a: A, +flag: String) -> A:
26  match a:
27    case A{fmt, socket, e, w}:
28      A{fmt, socket, e, flag}
29
30def pending(+a: A) -> Bool:
31  match a:
32    case A{fmt, socket, e, w}:
33      Bool.not(String.is_empty(w))
34
35def sel.a(c: Bool, +x: A, +y: A) -> A:
36  match c:
37    case True{}:
38      x
39    case False{}:
40      y
41
42def free(+h: String, +a: A) -> A:
43  sel.a(String.eq(h, "--format") || String.eq(h, "--socket"), want(a, h),
44  sel.a(String.starts_with(h, "--format="), got(want(a, "--format"), String.drop(h, 9n)),
45  sel.a(String.starts_with(h, "--socket="), got(want(a, "--socket"), String.drop(h, 9n)),
46  err(a, "unrecognized arguments: " ++ h))))
47
48def step(+h: String, +a: A) -> A:
49  sel.a(pending(a), got(a, h), free(h, a))
50
51def go(args: List<&2, String>, +a: A) -> A:
52  match args:
53    case Nil{}:
54      a
55    case Con{h, t}:
56      go(t, step(h, a))
57
58def end(+a: A) -> A:
59  match a:
60    case A{fmt, socket, e, w}:
61      Bool.pick(A, String.is_empty(w), a, err(a, "argument " ++ w ++ ": expected one argument"))
62
63def fmt_of2(m: Maybe<&2, O.Fmt>, +name: String) -> Result<&2, &2, String, O.Fmt>:
64  match m:
65    case Some{O.FText{}}:
66      Fail{"argument --format: invalid choice: '" ++ name ++ "' (choose from 'json', 'toon', 'yaml')"}
67    case Some{O.FCsv{}}:
68      Fail{"argument --format: invalid choice: '" ++ name ++ "' (choose from 'json', 'toon', 'yaml')"}
69    case Some{f}:
70      Done{f}
71    case None{}:
72      Fail{"argument --format: invalid choice: '" ++ name ++ "' (choose from 'json', 'toon', 'yaml')"}
73
74def fmt_of(m: Maybe<&2, String>) -> Result<&2, &2, String, O.Fmt>:
75  match m:
76    case None{}:
77      Done{O.FJson{}}
78    case Some{+n}:
79      fmt_of2(O.of_name(n), n)
80
81def plan4(serve: Bool, +f: O.Fmt, socket: Maybe<&2, String>) -> Plan:
82  match serve socket:
83    case True{} Some{p}:
84      PServe{p, f}
85    case True{} None{}:
86      PBad{"the following arguments are required: --socket"}
87    case False{} _:
88      PRpc{f}
89
90def plan3(+verb: String, r: Result<&2, &2, String, O.Fmt>, socket: Maybe<&2, String>) -> Plan:
91  match r:
92    case Fail{m}:
93      PBad{m}
94    case Done{f}:
95      plan4(String.eq(verb, "serve"), f, socket)
96
97def plan2(+verb: String, +a: A) -> Plan:
98  match a:
99    case A{fmt, socket, e, w}:
100      Bool.pick(Plan, String.is_empty(e), plan3(verb, fmt_of(fmt), socket), PBad{e})
101
102# `verb` is rpc or serve; `args` the words after it.
103def plan(+verb: String, args: List<&2, String>) -> Plan:
104  plan2(verb, end(go(args, A{None{}, None{}, "", ""})))