Skip to content

Commit 677a135

Browse files
authored
refactor: drop last parameter input
refactor: drop last parameter `input`
2 parents 11ed71e + 819f8a7 commit 677a135

File tree

1 file changed

+111
-86
lines changed

1 file changed

+111
-86
lines changed

src/Parser.flix

Lines changed: 111 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -23,168 +23,193 @@ pub type alias Parser[a, b] = Input[b] -> ParseResult[a, b]
2323
namespace Parser {
2424

2525
///
26-
/// Returns a non-empty `ParseResult` with value `b`
26+
/// Returns a parser that always succeeds with value `b`
2727
/// regardless of input.
2828
///
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
3131

3232
///
33-
/// Returns an empty `ParseResult` regardless of input.
33+
/// Returns a parser that always fails regardless of input.
3434
///
3535
/// Equivalent to the empty string ϵ.
3636
///
3737
pub def fail(_: Input[b]): ParseResult[a, b] =
3838
Nil
3939

4040
///
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)`.
4445
///
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+
}
5054

5155
///
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.
5560
///
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))
5863

5964
///
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`).
6267
///
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)
6572

6673
///
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`.
7076
///
71-
/// Equivalent to `AB` where `A` and `B` are non-terminals.
77+
/// Equivalent to `p1p2`.
7278
///
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)
7885

7986
///
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`.
8289
///
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
8592

8693
///
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`.
8996
///
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
9299

93100
///
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.
96105
///
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)
101111

102112
///
103-
/// Returns zero or more results of the parser `p`.
113+
/// Returns a parser that recognizes zero or more repetitions
114+
/// of `p`.
104115
///
105116
/// 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).
109121
///
110-
/// Equivalent to `A*`.
122+
/// Equivalent to `p*`.
111123
///
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))
115127

116128
///
117-
/// Returns one or more results of the parser `p`.
129+
/// Returns a parser that recognizes one or more repetitions
130+
/// of `p`.
118131
///
119132
/// Note that unlike `many`, this parser may fail, i.e.
120-
/// return 0 results.
133+
/// not recognize anything.
121134
///
122-
/// Equivalent to `A+`.
135+
/// Equivalent to `p+`.
123136
///
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
126139

127140
///
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+
///
129147
/// The longest match will be the first result.
130148
///
131-
pub def number(input: Input[Char]): ParseResult[List[Char], Char] =
149+
pub def number(inp: Input[Char]): ParseResult[List[Char], Char] =
132150
let digit = c -> '0' <= c and c <= '9';
133-
input |> some(satisfy(digit))
151+
inp |> some(satisfy(digit))
134152

135153
///
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+
///
137161
/// The longest match will be the first result.
138162
///
139-
pub def word(input: Input[Char]): ParseResult[List[Char], Char] =
163+
pub def word(inp: Input[Char]): ParseResult[List[Char], Char] =
140164
let lowercase = c -> 'a' <= c and c <= 'z';
141165
let uppercase = c -> 'A' <= c and c <= 'Z';
142166
let letter = c -> lowercase(c) or uppercase(c);
143-
input |> some(satisfy(letter))
167+
inp |> some(satisfy(letter))
144168

145169
///
146-
/// Returns a `ParseResult` that recognizes the sequence `lit`.
170+
/// Returns a parser that recognizes the sequence `lit`.
171+
///
147172
/// This is generalization of `literal`.
148173
///
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)
155180

156181
///
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.
158183
///
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] =
160185
let const = (x, _) -> x;
161-
(p `using` (const(c)))(input)
186+
p `using` const(c)
162187

163188
///
164-
/// Returns a `ParseResult` that recognizes the string `s`.
189+
/// Returns a parser that recognizes the string `s`.
165190
///
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)
168193

169194
///
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`.
172197
///
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
175200

176201
///
177-
/// Returns a `ParseResult` that recognizes whitespace.
202+
/// Returns a parser that recognizes whitespace.
178203
///
179-
pub def whitespace(input: Input[Char]): ParseResult[List[Char], Char] =
204+
pub def whitespace(inp: Input[Char]): ParseResult[List[Char], Char] =
180205
let chars = String.toList(" \t\n");
181-
input |> (many(any(literal, chars)))
206+
inp |> (many(any(literal, chars)))
182207

183208
///
184-
/// Returns a `ParseResult` that recognizes any of the elements in `syms`.
209+
/// Returns a parser that recognizes any of the elements in `syms`.
185210
///
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)
188213

189214
///
190215
/// Returns the string `s` as an `Input` type.

0 commit comments

Comments
 (0)