blob: b4051eb43124d531e7c7159b3ed52c3f5ac25417 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
(.module:
[library
[lux #*
[abstract
[monad (#+ do)]]
[control
["." try (#+ Try)]]
[data
["." text ("#\." equivalence)
["%" format (#+ format)]]]]]
["." //])
(type: .public (Parser a)
{#.doc "A command-line interface parser."}
(//.Parser (List Text) a))
(def: .public (run parser inputs)
{#.doc (doc "Executes the parser and verifies that all inputs are processed.")}
(All [a] (-> (Parser a) (List Text) (Try a)))
(case (//.run parser inputs)
(#try.Success [remaining output])
(case remaining
#.End
(#try.Success output)
_
(#try.Failure (format "Remaining CLI inputs: " (text.join_with " " remaining))))
(#try.Failure try)
(#try.Failure try)))
(def: .public any
{#.doc "Just returns the next input without applying any logic."}
(Parser Text)
(function (_ inputs)
(case inputs
(#.Item arg inputs')
(#try.Success [inputs' arg])
_
(#try.Failure "Cannot parse empty arguments."))))
(def: .public (parse parser)
{#.doc "Parses the next input with a parsing function."}
(All [a] (-> (-> Text (Try a)) (Parser a)))
(function (_ inputs)
(do try.monad
[[remaining raw] (any inputs)
output (parser raw)]
(in [remaining output]))))
(def: .public (this reference)
{#.doc "Checks that a token is in the inputs."}
(-> Text (Parser Any))
(function (_ inputs)
(do try.monad
[[remaining raw] (any inputs)]
(if (text\= reference raw)
(in [remaining []])
(#try.Failure (format "Missing token: '" reference "'"))))))
(def: .public (somewhere cli)
{#.doc "Given a parser, tries to parse it somewhere in the inputs (i.e. not necessarily parsing the immediate inputs)."}
(All [a] (-> (Parser a) (Parser a)))
(function (_ inputs)
(loop [immediate inputs]
(case (//.run cli immediate)
(#try.Success [remaining output])
(#try.Success [remaining output])
(#try.Failure try)
(case immediate
#.End
(#try.Failure try)
(#.Item to_omit immediate')
(do try.monad
[[remaining output] (recur immediate')]
(in [(#.Item to_omit remaining)
output])))))))
(def: .public end
{#.doc "Ensures there are no more inputs."}
(Parser Any)
(function (_ inputs)
(case inputs
#.End (#try.Success [inputs []])
_ (#try.Failure (format "Unknown parameters: " (text.join_with " " inputs))))))
(def: .public (named name value)
{#.doc (doc "Parses a named parameter and yields its value.")}
(All [a] (-> Text (Parser a) (Parser a)))
(|> value
(//.after (..this name))
..somewhere))
(def: .public (parameter [short long] value)
{#.doc (doc "Parses a parameter that can have either a short or a long name.")}
(All [a] (-> [Text Text] (Parser a) (Parser a)))
(|> value
(//.after (//.either (..this short) (..this long)))
..somewhere))
|