@@ -23,168 +23,193 @@ pub type alias Parser[a, b] = Input[b] -> ParseResult[a, b]
23
23
namespace Parser {
24
24
25
25
///
26
- /// Returns a non-empty `ParseResult` with value `b`
26
+ /// Returns a parser that always succeeds with value `b`
27
27
/// regardless of input.
28
28
///
29
- pub def succeed(a: a, input: Input[b] ): ParseResult [a, b] =
30
- (a, input ) :: Nil
29
+ pub def succeed(a: a): Parser [a, b] =
30
+ inp -> (a, inp ) :: Nil
31
31
32
32
///
33
- /// Returns an empty `ParseResult` regardless of input.
33
+ /// Returns a parser that always fails regardless of input.
34
34
///
35
35
/// Equivalent to the empty string ϵ.
36
36
///
37
37
pub def fail(_: Input[b]): ParseResult[a, b] =
38
38
Nil
39
39
40
40
///
41
- /// Returns a non-empty `ParseResult` if the input is non-empty
42
- /// and the first element satisfies the predicate `p`.
43
- /// Returns an empty `ParseResult` otherwise.
41
+ /// Returns a parser that succeeds with value `x`
42
+ /// if the input is non-empty and the first
43
+ /// element `x` of the input satisfies
44
+ /// the predicate `p(x)`.
44
45
///
45
- pub def satisfy(p: a -> Bool, input: Input[a]): ParseResult[a, a] = match input {
46
- case Nil => fail(input)
47
- case x :: xs if p(x) => succeed(x, xs)
48
- case _ :: xs => fail(xs)
49
- }
46
+ /// The parser fails otherwise.
47
+ ///
48
+ pub def satisfy(p: a -> Bool): Parser[a, a] =
49
+ inp -> match inp {
50
+ case Nil => fail(inp)
51
+ case x :: xs if p(x) => succeed(x, xs)
52
+ case _ :: xs => fail(xs)
53
+ }
50
54
51
55
///
52
- /// Returns a non-empty `ParseResult` if the first element of the input
53
- /// is equal to `a`.
54
- /// Returns an empty ParseReult otherwise.
56
+ /// Returns a parser that succeeds with value `a`
57
+ /// if the first element of the input is equal to `a`.
58
+ ///
59
+ /// The parser fails otherwise.
55
60
///
56
- pub def literal(a: a, input: Input[a] ): ParseResult [a, a] with Eq[a] =
57
- satisfy(Eq.eq(a) , input )
61
+ pub def literal(a: a): Parser [a, a] with Eq[a] =
62
+ satisfy(Eq.eq(a))
58
63
59
64
///
60
- /// Returns the result of parser `p1` applied to `input`
61
- /// followed by the result of parser `p2` applied to `input` .
65
+ /// Returns a parser that recognizes the alternation
66
+ /// of `p1` and `p2` (i.e. it recognizes both `p1` and `p2`) .
62
67
///
63
- pub def otherwise(p1: Parser[a, b], p2: Parser[a, b], input: Input[b]): ParseResult[a, b] =
64
- p1(input) ::: p2(input)
68
+ /// Equivalent to `p1` | `p2`.
69
+ ///
70
+ pub def otherwise(p1: Parser[a, b], p2: Parser[a, b]): Parser[a, b] =
71
+ inp -> p1(inp) ::: p2(inp)
65
72
66
73
///
67
- /// Returns the `ParseResult` of sequencing `p1`, `p2`, i.e.
68
- /// `p1` is applied to the input and `p2` is applied to the
69
- /// input that `p1` did not consume.
74
+ /// Returns a parser that recognizes the concatenation of
75
+ /// `p1` and `p2`.
70
76
///
71
- /// Equivalent to `AB` where `A` and `B` are non-terminals .
77
+ /// Equivalent to `p1p2` .
72
78
///
73
- pub def then(p1: Parser[a, b], p2: Parser[c, b], input: Input[b]): ParseResult[(a, c), b] =
74
- for (
75
- (x1, rest1) <- p1(input);
76
- (x2, rest2) <- p2(rest1)
77
- ) yield ((x1, x2), rest2)
79
+ pub def then(p1: Parser[a, b], p2: Parser[c, b]): Parser[(a, c), b] =
80
+ inp ->
81
+ for (
82
+ (x1, rest1) <- p1(inp);
83
+ (x2, rest2) <- p2(rest1)
84
+ ) yield ((x1, x2), rest2)
78
85
79
86
///
80
- /// Returns a `ParseResult` that recognizes the concatenation of `p1` and `p2`
81
- /// but discards the result of `p1`.
87
+ /// Returns a parser that recognizes the concatenation of
88
+ /// `p1` and `p2` but discards the result of `p1`.
82
89
///
83
- pub def thenIgnoringLeft(p1: Parser[a, b], p2: Parser[c, b], input: Input[b] ): ParseResult [c, b] =
84
- input |> (( p1 `then` p2) `using` snd)
90
+ pub def thenIgnoringLeft(p1: Parser[a, b], p2: Parser[c, b]): Parser [c, b] =
91
+ ( p1 `then` p2) `using` snd
85
92
86
93
///
87
- /// Returns a `ParseResult` that recognizes the concatenation of `p1` and `p2`
88
- /// but discards the result of `p2`.
94
+ /// Returns a parser that recognizes the concatenation of
95
+ /// `p1` and `p2` but discards the result of `p2`.
89
96
///
90
- pub def thenIgnoringRight(p1: Parser[a, b], p2: Parser[c, b], input: Input[b] ): ParseResult [a, b] =
91
- input |> (( p1 `then` p2) `using` fst)
97
+ pub def thenIgnoringRight(p1: Parser[a, b], p2: Parser[c, b]): Parser [a, b] =
98
+ ( p1 `then` p2) `using` fst
92
99
93
100
///
94
- /// Returns the result of applying `f` to every element of
95
- /// the `ParseResult` of `p` on `input`.
101
+ /// Returns a parser that applies `f` to all recognized
102
+ /// values of `p`.
103
+ ///
104
+ /// Useful for producing AST nodes.
96
105
///
97
- pub def using(p: Parser[a, b], f: a -> c, input: Input[b]): ParseResult[c, b] =
98
- for (
99
- (x, rest) <- p(input)
100
- ) yield (f(x), rest)
106
+ pub def using(p: Parser[a, b], f: a -> c): Parser[c, b] =
107
+ inp ->
108
+ for (
109
+ (x, rest) <- p(inp)
110
+ ) yield (f(x), rest)
101
111
102
112
///
103
- /// Returns zero or more results of the parser `p`.
113
+ /// Returns a parser that recognizes zero or more repetitions
114
+ /// of `p`.
104
115
///
105
116
/// Note that it always succeeds, so the result will always
106
- /// be non-empty, but the rest of the input may be `Nil`, along
107
- /// with the result. I.e. both the value of `List[a]` may be `Nil`
108
- /// and `b` may be `Nil`.
117
+ /// be non-empty, but the rest of the inp may be empty as well as
118
+ /// the result.
119
+ /// I.e. both the recognized value of may be empty (but still exist) and
120
+ /// the unconsumed may be empty (but still exist).
109
121
///
110
- /// Equivalent to `A *`.
122
+ /// Equivalent to `p *`.
111
123
///
112
- pub def many(p: Parser[a, b], input: Input[b] ): ParseResult [List[a], b] =
113
- let p1 = (p `then` many(p)) `using` cons;
114
- otherwise(p1, succeed(Nil), input )
124
+ pub def many(p: Parser[a, b]): Parser [List[a], b] =
125
+ inp -> inp // Wrap in lambda so the recursive call does not immediately happen
126
+ |> (((p `then` many(p)) `using` cons) `otherwise` succeed(Nil))
115
127
116
128
///
117
- /// Returns one or more results of the parser `p`.
129
+ /// Returns a parser that recognizes one or more repetitions
130
+ /// of `p`.
118
131
///
119
132
/// Note that unlike `many`, this parser may fail, i.e.
120
- /// return 0 results .
133
+ /// not recognize anything .
121
134
///
122
- /// Equivalent to `A +`.
135
+ /// Equivalent to `p +`.
123
136
///
124
- pub def some(p: Parser[a, b], input: Input[b] ): ParseResult [List[a], b] =
125
- (( p `then` many(p)) `using` cons)(input)
137
+ pub def some(p: Parser[a, b]): Parser [List[a], b] =
138
+ (p `then` many(p)) `using` cons
126
139
127
140
///
128
- /// Returns one or more `ParseResults` recognizing numbers.
141
+ /// Returns a parser that recognizes numbers (consecutive integer characters).
142
+ ///
143
+ /// All possible parses of the number will be recognized.
144
+ ///
145
+ /// E.g. `123` is recognized as `123, 12, 1`.
146
+ ///
129
147
/// The longest match will be the first result.
130
148
///
131
- pub def number(input : Input[Char]): ParseResult[List[Char], Char] =
149
+ pub def number(inp : Input[Char]): ParseResult[List[Char], Char] =
132
150
let digit = c -> '0' <= c and c <= '9';
133
- input |> some(satisfy(digit))
151
+ inp |> some(satisfy(digit))
134
152
135
153
///
136
- /// Returns one or more `ParseResults` recognizing consecutive chars.
154
+ /// Returns a parser that recognizes words
155
+ /// (consectutive non-integer, non-whitespace characters).
156
+ ///
157
+ /// All possible parses of the word will be recognized.
158
+ ///
159
+ /// E.g. `hello` is recognized as `hello, hell, hel, he, h`.
160
+ ///
137
161
/// The longest match will be the first result.
138
162
///
139
- pub def word(input : Input[Char]): ParseResult[List[Char], Char] =
163
+ pub def word(inp : Input[Char]): ParseResult[List[Char], Char] =
140
164
let lowercase = c -> 'a' <= c and c <= 'z';
141
165
let uppercase = c -> 'A' <= c and c <= 'Z';
142
166
let letter = c -> lowercase(c) or uppercase(c);
143
- input |> some(satisfy(letter))
167
+ inp |> some(satisfy(letter))
144
168
145
169
///
146
- /// Returns a `ParseResult` that recognizes the sequence `lit`.
170
+ /// Returns a parser that recognizes the sequence `lit`.
171
+ ///
147
172
/// This is generalization of `literal`.
148
173
///
149
- pub def literalSequence(lit: List[a], input: Input[a] ): ParseResult [List[a], a] with Eq[a] =
150
- let p = match lit {
151
- case Nil => succeed(Nil)
152
- case x :: xs => (literal(x) `then` (literalSequence(xs))) `using` cons
153
- };
154
- p(input )
174
+ pub def literalSequence(lit: List[a]): Parser [List[a], a] with Eq[a] =
175
+ inp -> // Wrap in lambda so the recursive call does not immediately happen
176
+ match lit {
177
+ case Nil => succeed(Nil)
178
+ case x :: xs => (literal(x) `then` (literalSequence(xs))) `using` cons
179
+ }(inp )
155
180
156
181
///
157
- /// Returns a `ParseResult` containing the value `c` if `p` is succesful.
182
+ /// Returns parser that returns the the value `c` if `p` is succesful.
158
183
///
159
- pub def return(p: Parser[a, b], c: c, input: Input[b] ): ParseResult [c, b] =
184
+ pub def return(p: Parser[a, b], c: c): Parser [c, b] =
160
185
let const = (x, _) -> x;
161
- ( p `using` ( const(c)))(input )
186
+ p `using` const(c)
162
187
163
188
///
164
- /// Returns a `ParseResult` that recognizes the string `s`.
189
+ /// Returns a parser that recognizes the string `s`.
165
190
///
166
- pub def string(s: String, input: Input[Char] ): ParseResult [List[Char], Char] =
167
- (String.toList >> literalSequence)(s, input )
191
+ pub def string(s: String): Parser [List[Char], Char] =
192
+ s |> (String.toList >> literalSequence)
168
193
169
194
///
170
- /// Returns a `ParseResult` where white-space
171
- /// has been removed on both sides of `p`.
195
+ /// Returns a parser that ignores whitespace on both
196
+ /// sides of `p`.
172
197
///
173
- pub def nibble(p: Parser[a, Char], input: Input[Char] ): ParseResult [a, Char] =
174
- input |> ( whitespace `thenIgnoringLeft` p `thenIgnoringRight` whitespace)
198
+ pub def nibble(p: Parser[a, Char]): Parser [a, Char] =
199
+ whitespace `thenIgnoringLeft` p `thenIgnoringRight` whitespace
175
200
176
201
///
177
- /// Returns a `ParseResult` that recognizes whitespace.
202
+ /// Returns a parser that recognizes whitespace.
178
203
///
179
- pub def whitespace(input : Input[Char]): ParseResult[List[Char], Char] =
204
+ pub def whitespace(inp : Input[Char]): ParseResult[List[Char], Char] =
180
205
let chars = String.toList(" \t\n");
181
- input |> (many(any(literal, chars)))
206
+ inp |> (many(any(literal, chars)))
182
207
183
208
///
184
- /// Returns a `ParseResult` that recognizes any of the elements in `syms`.
209
+ /// Returns a parser that recognizes any of the elements in `syms`.
185
210
///
186
- pub def any(f: a -> Parser[b, c], syms: List[a], input: Input[c] ): ParseResult [b, c] =
187
- input |> List.foldRight(f >> otherwise, fail, syms)
211
+ pub def any(f: a -> Parser[b, c], syms: List[a]): Parser [b, c] =
212
+ List.foldRight(f >> otherwise, fail, syms)
188
213
189
214
///
190
215
/// Returns the string `s` as an `Input` type.
0 commit comments