Skip to content

Commit 21aa4cc

Browse files
committed
refactor: streamline parser function calls and update result handling
1 parent 366c131 commit 21aa4cc

20 files changed

+207
-262
lines changed

README.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ Success example:
9393
9494
// Pipe operator |>
9595
96-
P.anyDigit |> P.runParser("1") // Belt.Result.Ok("1")
96+
P.anyDigit |> P.runParser("1") // Result.Ok("1")
9797
9898
// Or normal function application
9999
@@ -103,7 +103,7 @@ P.runParser("1", P.anyDigit)
103103
Failure example:
104104

105105
```reason
106-
P.anyDigit |> P.runParser("!") // Belt.Result.Error(ParseError("Expected a digit"))
106+
P.anyDigit |> P.runParser("!") // Result.Error(ParseError("Expected a digit"))
107107
```
108108

109109
In the event of a failed parse, parsers will (in most cases) back-track so that an alternative
@@ -119,7 +119,7 @@ A `RelueParse.Parser` is a `functor`, so we can map a pure function over the par
119119

120120
```reason
121121
// Warning: int_of_string is unsafe (can throw) - this is just an example
122-
P.anyDigit |> P.map(int_of_string) |> P.runParser("1") // Belt.Result.Ok(1)
122+
P.anyDigit |> P.map(int_of_string) |> P.runParser("1") // Result.Ok(1)
123123
124124
// <$> map operator version. <$> is traditionally "function on the left"
125125
int_of_string <$> P.anyDigit |> P.runParser("1");
@@ -154,31 +154,31 @@ together using a variety of techniques.
154154

155155
```reason
156156
// Combine two parsers into a tuple of the results (assuming all succeed)
157-
P.tuple2(P.anyDigit, P.anyDigit) |> P.runParser("12") // Belt.Result.Ok(("1", "2"))
157+
P.tuple2(P.anyDigit, P.anyDigit) |> P.runParser("12") // Result.Ok(("1", "2"))
158158
159159
// <^> operator (operator version of tuple2)
160-
P.anyDigit <^> P.anyDigit |> P.runParser("12") // Belt.Result.Ok(("1", "2"))
160+
P.anyDigit <^> P.anyDigit |> P.runParser("12") // Result.Ok(("1", "2"))
161161
162162
// Combine more parsers using tuple3 up to tuple5
163163
P.tuple3(P.anyDigit, P.anyDigit, P.anyDigit)
164-
|> P.runParser("123") // Belt.Result.Ok(("1", "2", "3"))
164+
|> P.runParser("123") // Result.Ok(("1", "2", "3"))
165165
166166
// Combine parse results using a function via map2 through map5
167167
P.map2((a, b) => a + b, P.anyDigitAsInt, P.anyDigitAsInt)
168-
|> P.runParser("12") // Belt.Result.Ok(3)
168+
|> P.runParser("12") // Result.Ok(3)
169169
170170
// Combine results from a tuple of parsers using mapTuple2 through mapTuple5
171171
(P.anyDigitAsInt, P.anyDigitAsInt)
172172
|> P.mapTuple2((a, b) => a + b)
173-
|> P.runParser("12"); // Belt.Result.Ok(3)
173+
|> P.runParser("12"); // Result.Ok(3)
174174
175175
// Use the *> operator to run two parsers, and only keep the result from the right side
176176
// This is useful if you don't care what the left side parser produces (e.g. whitespace)
177177
// but you need to consume that input.
178178
// `ws` consumes all the whitespace it encounters and throws it away
179179
P.ws
180180
*> P.anyDigit
181-
|> P.runParser(" 3") // Belt.Result.Ok("3")
181+
|> P.runParser(" 3") // Result.Ok("3")
182182
183183
// Use the <* operator to run two parsers, and only keep the result from the left side
184184
// This is useful if you don't care what the right side parser produces (e.g. whitespace)
@@ -190,7 +190,7 @@ P.ws
190190
*> P.anyDigit
191191
<* P.ws
192192
<* P.eof
193-
|> P.runParser(" 3 ") // Belt.Result.Ok("3")
193+
|> P.runParser(" 3 ") // Result.Ok("3")
194194
195195
// ADVANCED: Incrementally collect parse results using a function and chained <$> map and <*> apply
196196
// operators.
@@ -199,7 +199,7 @@ add3
199199
<$> P.anyDigitAsInt
200200
<*> P.anyDigitAsInt
201201
<*> P.anyDigitAsInt
202-
|> P.runParser("123"); // Belt.Result.Ok(6)
202+
|> P.runParser("123"); // Result.Ok(6)
203203
```
204204

205205
Many of these functions and operators come for free for any Applicative via [Relude Apply Extensions](https://github.com/reazen/relude/blob/master/src/extensions/Relude_Extensions_Apply.re)
@@ -225,7 +225,7 @@ if a parser fails at some point in a chain, the rest of the parsers will not run
225225
// Lift a pure value into a parser.
226226
// As you can see the parser just produces the given value regardless of the string.
227227
P.pure(3)
228-
|> runParser("abcdef") // Belt.Result.Ok(3)
228+
|> runParser("abcdef") // Result.Ok(3)
229229
230230
// Sequence parse operations using flatMap.
231231
// In this example we read a single digit as an int, then use that value
@@ -235,7 +235,7 @@ P.pure(3)
235235
P.anyDigitAsInt
236236
|> P.flatMap(count => P.anyAlpha |> P.times(count) <* P.eof)
237237
|> P.map(chars => Relude.List.String.join(chars))
238-
|> P.runParser("3abc"); // Belt.Result.Ok("abc")
238+
|> P.runParser("3abc"); // Result.Ok("abc")
239239
240240
// Sequence using >>= (flatMap/bind) and <#> (map) operators.
241241
// If you are coming from JS -
@@ -245,7 +245,7 @@ P.anyDigitAsInt
245245
P.anyDigitAsInt
246246
>>= (count => P.times(count, P.anyAlpha) <* P.eof)
247247
<#> Relude.List.String.join
248-
|> P.runParser("3abc"); // Belt.Result.Ok("abc")
248+
|> P.runParser("3abc"); // Result.Ok("abc")
249249
```
250250

251251
Many of these functions come for free for any Monad via [Relude Monad Extensions](https://github.com/reazen/relude/blob/master/src/extensions/Relude_Extensions_Monad.re)
@@ -273,7 +273,7 @@ P.anyDigitAsInt
273273
}
274274
)
275275
<#> Relude.List.String.join
276-
|> runParser("9abc") // Belt.Result.Error(ParseError("The count cannot be >= 5"))
276+
|> runParser("9abc") // Result.Error(ParseError("The count cannot be >= 5"))
277277
```
278278

279279
The `filter` function in `ReludeParse` is basically for this purpose. Filter produces its
@@ -293,9 +293,9 @@ if it fails, try another, as many times as you want.
293293
The `<|>` operator is used for this - think of the `<|>` operator as an `orElse` function.
294294

295295
```reason
296-
P.anyDigit <|> P.anyAlpha |> P.runParser("9") // Belt.Result.Ok("9")
297-
P.anyDigit <|> P.anyAlpha |> P.runParser("a") // Belt.Result.Ok("a")
298-
P.anyDigit <|> P.anyAlpha |> P.runParser("!") // Belt.Result.Error(...)
296+
P.anyDigit <|> P.anyAlpha |> P.runParser("9") // Result.Ok("9")
297+
P.anyDigit <|> P.anyAlpha |> P.runParser("a") // Result.Ok("a")
298+
P.anyDigit <|> P.anyAlpha |> P.runParser("!") // Result.Error(...)
299299
```
300300

301301
`<|>` can be chained as many times as you want - it attempts each parser left-to-right.
@@ -321,7 +321,7 @@ function to force a parser to back-track all the way to it's original position i
321321
// parser fully back-track on failure if it had consumed any input.
322322
P.tries(P.anyDigit *> P.anyDigit) // parse a digit, throw it away, then parse another digit
323323
<|> (P.anyDigit *> P.anyAlpha) // parse a digit,throw it away, then parse a letter
324-
|> P.runParser("9a") // Belt.Result.Ok("a")
324+
|> P.runParser("9a") // Result.Ok("a")
325325
```
326326

327327
# Customizing the error message
@@ -333,7 +333,7 @@ message if the parser fails.
333333
```reason
334334
P.many1(P.anyDigit)
335335
<?> "Expected one or more digits"
336-
|> P.runParser("abc") // Belt.Result.Error(ParseError("Expected one or more digits"))
336+
|> P.runParser("abc") // Result.Error(ParseError("Expected one or more digits"))
337337
```
338338

339339
# Checking that all input is consumed
@@ -472,8 +472,8 @@ list of parser functions that come with `ReludeParse`.
472472

473473
|Function|Description|Example|
474474
|--------|-----------|-------|
475-
|`runParser`|runs a parser with an input string to produce a `Belt.Result` with either the value or a `ParseError.t`
476-
|`unParser`|runs a parser with an input string to produce a `Belt.Result` with either the value or a `ParseError.t` (with some additional metadata compared to `runParser`)
475+
|`runParser`|runs a parser with an input string to produce a `Result` with either the value or a `ParseError.t`
476+
|`unParser`|runs a parser with an input string to produce a `Result` with either the value or a `ParseError.t` (with some additional metadata compared to `runParser`)
477477

478478
## Core FP functions and operators
479479

__tests__/ReludeParse_Parser_test.res

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,17 @@ open P.Infix
77
let int_of_string = s => s->Int.fromString->Option.getUnsafe
88

99
describe("ReludeParse_Parser", () => {
10-
test("runParser success", () =>
11-
expect(P.runParser("9", P.anyDigit))->toEqual(Belt.Result.Ok("9"))
12-
)
10+
test("runParser success", () => P.runParser("9", P.anyDigit)->expect->toEqual(Result.Ok("9")))
1311

1412
test("runParser failure", () => {
1513
let expectedError: P.ParseError.t = ParseError("Expected a digit, but found character 'a'")
16-
expect(P.runParser("a", P.anyDigit))->toEqual(Belt.Result.Error(expectedError))
14+
P.runParser("a", P.anyDigit)->expect->toEqual(Result.Error(expectedError))
1715
})
1816

1917
test("pure", () => {
20-
let actual: Belt.Result.t<P.success<int>, P.error> =
18+
let actual: Result.t<P.success<int>, P.error> =
2119
P.pure(42)->P.unParser({pos: 0, str: "whatever"}, _)
22-
let expected: Belt.Result.t<P.success<int>, P.error> = Ok({
20+
let expected: Result.t<P.success<int>, P.error> = Ok({
2321
result: 42,
2422
suffix: {
2523
pos: 0,
@@ -29,43 +27,43 @@ describe("ReludeParse_Parser", () => {
2927
expect(actual)->toEqual(expected)
3028
})
3129

32-
test("unit", () => testParse(P.unit, "whatever", (), {pos: 0, str: "whatever"}))
30+
test("unit", () => P.unit->testParse("whatever", (), {pos: 0, str: "whatever"}))
3331

3432
test("fail", () => {
3533
let actual = P.fail("Fail!")->P.unParser({pos: 0, str: "whatever"}, _)
36-
let expected: Belt.Result.t<P.success<_>, P.error> = Belt.Result.Error({
34+
let expected: Result.t<P.success<_>, P.error> = Result.Error({
3735
error: ParseError("Fail!"),
3836
pos: 0,
3937
})
4038
expect(actual)->toEqual(expected)
4139
})
4240

4341
test("tries success", () =>
44-
testParse(P.tries(P.times(3, P.anyDigit)), "012", list{"0", "1", "2"}, {pos: 3, str: "012"})
42+
P.tries(P.times(3, P.anyDigit))->testParse("012", list{"0", "1", "2"}, {pos: 3, str: "012"})
4543
)
4644

4745
test("without tries, error position is position of error", () =>
48-
testParseFail(P.times(3, P.anyDigit), "01a", 2)
46+
P.times(3, P.anyDigit)->testParseFail("01a", 2)
4947
)
5048

5149
test("with tries, error position is the starting position", () =>
52-
testParseFail(P.tries(P.times(3, P.anyDigit)), "01a", 0)
50+
P.tries(P.times(3, P.anyDigit))->testParseFail("01a", 0)
5351
)
5452

5553
test("withError", () =>
56-
testParseFailWithMessage(P.withError("Fail!", P.anyDigit), "a", 0, "Fail!")
54+
P.withError("Fail!", P.anyDigit)->testParseFailWithMessage("a", 0, "Fail!")
5755
)
5856

5957
test("flipWithError", () =>
60-
testParseFailWithMessage(P.flipWithError(P.anyDigit, "Fail!"), "a", 0, "Fail!")
58+
P.flipWithError(P.anyDigit, "Fail!")->testParseFailWithMessage("a", 0, "Fail!")
6159
)
6260

6361
test("<?> (withError operator)", () =>
64-
testParseFailWithMessage(\"<?>"(P.anyDigit, "Fail!"), "a", 0, "Fail!")
62+
\"<?>"(P.anyDigit, "Fail!")->testParseFailWithMessage("a", 0, "Fail!")
6563
)
6664

6765
test("map/<$>/<#>", () =>
68-
testParse(\"<$$>"(P.anyDigit, int_of_string), "9", 9, {pos: 1, str: "9"})
66+
P.anyDigit->\"<$$>"(int_of_string)->testParse("9", 9, {pos: 1, str: "9"})
6967
)
7068

7169
test("tap", () => {
@@ -75,67 +73,63 @@ describe("ReludeParse_Parser", () => {
7573

7674
let result =
7775
P.anyDigit
78-
->(P.tap(
76+
->P.tap(
7977
(result, posStringBefore, posStringAfter) => {
8078
resultRef := result
8179
posStringBeforeRef := posStringBefore
8280
posStringAfterRef := posStringAfter
8381
},
8482
_,
85-
))
83+
)
8684
->P.runParser("1", _)
8785

8886
expect((
8987
resultRef.contents,
9088
posStringBeforeRef.contents,
9189
posStringAfterRef.contents,
9290
result,
93-
))->toEqual(("1", P.PosString.make(0, "1"), P.PosString.make(1, "1"), Belt.Result.Ok("1")))
91+
))->toEqual(("1", P.PosString.make(0, "1"), P.PosString.make(1, "1"), Result.Ok("1")))
9492
})
9593

96-
test("tapLog", () => expect(P.anyDigit->P.tapLog->(P.runParser("1", _))->ignore)->toEqual())
94+
test("tapLog", () => expect(P.anyDigit->P.tapLog->P.runParser("1", _)->ignore)->toEqual())
9795

9896
test("apply/<*>", () =>
99-
testParse(\"<*>"(P.pure(int_of_string), P.anyDigit), "9", 9, {pos: 1, str: "9"})
97+
P.pure(int_of_string)->\"<*>"(P.anyDigit)->testParse("9", 9, {pos: 1, str: "9"})
10098
)
10199

102100
test("<^> (tuple2 operator)", () =>
103-
testParse(\"<^>"(P.anyDigit, P.anyDigit), "01", ("0", "1"), {pos: 2, str: "01"})
101+
P.anyDigit->\"<^>"(P.anyDigit)->testParse("01", ("0", "1"), {pos: 2, str: "01"})
104102
)
105103

106104
test("mapN (applicative extensions)", () =>
107-
testParse(
108-
P.map3((a, b, c) => (a, b, c), P.anyDigit, P.anyDigit, P.anyDigit),
105+
P.map3((a, b, c) => (a, b, c), P.anyDigit, P.anyDigit, P.anyDigit)->testParse(
109106
"012",
110107
("0", "1", "2"),
111108
{pos: 3, str: "012"},
112109
)
113110
)
114111

115112
test("tupleN (applicative extensions)", () =>
116-
testParse(
117-
P.tuple3(P.anyDigit, P.anyDigit, P.anyDigit),
113+
P.tuple3(P.anyDigit, P.anyDigit, P.anyDigit)->testParse(
118114
"012",
119115
("0", "1", "2"),
120116
{pos: 3, str: "012"},
121117
)
122118
)
123119

124120
test("mapTupleN (applicative extensions)", () =>
125-
testParse(
126-
(P.anyDigit, P.anyDigit, P.anyDigit)->P.mapTuple3((a, b, c) => (a, b, c), _),
127-
"012",
128-
("0", "1", "2"),
129-
{pos: 3, str: "012"},
130-
)
121+
(P.anyDigit, P.anyDigit, P.anyDigit)
122+
->P.mapTuple3((a, b, c) => (a, b, c), _)
123+
->testParse("012", ("0", "1", "2"), {pos: 3, str: "012"})
131124
)
132125

133126
test("*>", () =>
134-
testParse(\"<*"(\"*>"(P.anyDigit, P.anyDigit), P.eof), "12", "2", {pos: 2, str: "12"})
127+
P.anyDigit->\"*>"(P.anyDigit)->\"<*"(P.eof)
128+
->testParse("12", "2", {pos: 2, str: "12"})
135129
)
136130

137131
test("<*", () =>
138-
testParse(\"<*"(\"<*"(P.anyDigit, P.anyDigit), P.eof), "12", "1", {pos: 2, str: "12"})
132+
P.anyDigit->\"<*"(P.anyDigit)->\"<*"(P.eof)->testParse("12", "1", {pos: 2, str: "12"})
139133
)
140134

141135
test("bind/flatMap/>>=", () => {
@@ -158,7 +152,7 @@ describe("ReludeParse_Parser", () => {
158152

159153
test("throwError", () => {
160154
let actual = P.throwError(P.ParseError.make("hi"))->P.unParser({pos: 0, str: "whatever"}, _)
161-
let expected: Belt.Result.t<P.success<_>, P.error> = Belt.Result.Error({
155+
let expected: Result.t<P.success<_>, P.error> = Result.Error({
162156
error: ParseError("hi"),
163157
pos: 0,
164158
})
@@ -1194,7 +1188,7 @@ describe("ReludeParse_Parser", () => {
11941188
->\"<$>"(P.ws->\"*>"(P.anyDigitAsInt))
11951189
->\"<*>"(P.anyDigitAsInt)
11961190
->P.runParser(" 34", _)
1197-
expect(x)->toEqual(Belt.Result.Ok(7))
1191+
expect(x)->toEqual(Result.Ok(7))
11981192
})
11991193

12001194
test("anyCharNotIn success", () =>

0 commit comments

Comments
 (0)