aboutsummaryrefslogtreecommitdiff
path: root/aoc-2020-gleam/src/util/parser.gleam
diff options
context:
space:
mode:
Diffstat (limited to 'aoc-2020-gleam/src/util/parser.gleam')
-rw-r--r--aoc-2020-gleam/src/util/parser.gleam82
1 files changed, 50 insertions, 32 deletions
diff --git a/aoc-2020-gleam/src/util/parser.gleam b/aoc-2020-gleam/src/util/parser.gleam
index c16dc60..321e459 100644
--- a/aoc-2020-gleam/src/util/parser.gleam
+++ b/aoc-2020-gleam/src/util/parser.gleam
@@ -9,7 +9,7 @@ import ext/intx
const eof: String = "end of input"
-fn quoted(grapheme: String) -> String {
+fn quot(grapheme: String) -> String {
"'" <> grapheme <> "'"
}
@@ -59,8 +59,8 @@ pub fn grapheme_literal(expected: String) -> Parser(String) {
Parser(fn(input) {
case run(any_grapheme(), on: input) {
Ok(#(value, _)) as ok if value == expected -> ok
- Ok(#(value, _)) -> Error(InvalidInput(quoted(expected), found: value))
- Error(_) -> Error(InvalidInput(quoted(expected), found: eof))
+ Ok(#(value, _)) -> Error(InvalidInput(quot(expected), found: quot(value)))
+ Error(_) -> Error(InvalidInput(quot(expected), found: eof))
}
})
}
@@ -83,6 +83,15 @@ pub fn then_skip(first: Parser(a), second: Parser(b)) -> Parser(a) {
|> map(with: pair.first)
}
+pub fn then_third(two: Parser(#(a, b)), third: Parser(c)) -> Parser(#(a, b, c)) {
+ two
+ |> then(third)
+ |> map(with: fn(tuple) {
+ let #(#(p0, p1), p2) = tuple
+ #(p0, p1, p2)
+ })
+}
+
pub fn or(first: Parser(a), else second: Parser(a)) -> Parser(a) {
Parser(fn(input) {
first
@@ -94,7 +103,7 @@ pub fn or(first: Parser(a), else second: Parser(a)) -> Parser(a) {
pub fn any(of parsers: List(Parser(a))) -> Parser(a) {
parsers
|> list.reduce(with: or)
- |> result.unwrap(or: failing(InvalidParser))
+ |> result.unwrap(or: failing(with: InvalidParser))
}
pub fn digit() -> Parser(String) {
@@ -113,66 +122,67 @@ pub fn map(parser: Parser(a), with mapper: fn(a) -> b) -> Parser(b) {
})
}
-fn succeeding(value: a) -> Parser(a) {
- Parser(fn(input) { Ok(#(value, input)) })
+pub fn map2(parser: Parser(#(a, b)), with mapper: fn(a, b) -> c) -> Parser(c) {
+ parser
+ |> map(with: fn(args) { mapper(args.0, args.1) })
}
-fn failing(error: ParseError) -> Parser(a) {
- Parser(fn(_) { Error(error) })
+pub fn map3(
+ parser: Parser(#(a, b, c)),
+ with mapper: fn(a, b, c) -> d,
+) -> Parser(d) {
+ parser
+ |> map(with: fn(args) { mapper(args.0, args.1, args.2) })
}
-fn apply(fn_parser: Parser(fn(a) -> b), value_parser: Parser(a)) -> Parser(b) {
- fn_parser
- |> then(value_parser)
- |> map(fn(pair) {
- let #(f, x) = pair
- f(x)
- })
+fn succeeding(with value: a) -> Parser(a) {
+ Parser(fn(input) { Ok(#(value, input)) })
+}
+
+fn failing(with error: ParseError) -> Parser(a) {
+ Parser(fn(_) { Error(error) })
}
-fn lift2(func: fn(a, b) -> c) -> fn(Parser(a), Parser(b)) -> Parser(c) {
+fn lift2(function: fn(a, b) -> c) -> fn(Parser(a), Parser(b)) -> Parser(c) {
fn(x_parser, y_parser) {
- func
- |> function.curry2
+ function
|> succeeding
- |> apply(x_parser)
- |> apply(y_parser)
+ |> then(x_parser)
+ |> then_third(y_parser)
+ |> map3(with: fn(f, x, y) { f(x, y) })
}
}
pub fn sequence(of parsers: List(Parser(a))) -> Parser(List(a)) {
- let prepend_parser = lift2(list.prepend)
+ let prepend_parser = lift2(fn(x, xs) { [x, ..xs] })
case parsers {
- [] -> succeeding([])
+ [] -> succeeding(with: [])
[head, ..tail] ->
tail
|> sequence
- |> prepend_parser(head)
+ |> prepend_parser(head, _)
}
}
-fn parse_zero_or_more(
- input: String,
- with parser: Parser(a),
-) -> #(List(a), String) {
+fn do_zero_or_more(input: String, with parser: Parser(a)) -> #(List(a), String) {
case run(parser, on: input) {
Ok(#(value, rest)) -> {
- let #(previous, rest) = parse_zero_or_more(rest, with: parser)
+ let #(previous, rest) = do_zero_or_more(rest, with: parser)
#([value, ..previous], rest)
}
Error(_) -> #([], input)
}
}
-pub fn many(parser: Parser(a)) -> Parser(List(a)) {
- Parser(fn(input) { Ok(parse_zero_or_more(input, with: parser)) })
+pub fn many(of parser: Parser(a)) -> Parser(List(a)) {
+ Parser(fn(input) { Ok(do_zero_or_more(input, with: parser)) })
}
-pub fn many1(parser: Parser(a)) -> Parser(List(a)) {
+pub fn many1(of parser: Parser(a)) -> Parser(List(a)) {
Parser(fn(input) {
use parsed <- result.then(run(parser, on: input))
let #(value, rest) = parsed
- let #(previous, rest) = parse_zero_or_more(rest, with: parser)
+ let #(previous, rest) = do_zero_or_more(rest, with: parser)
Ok(#([value, ..previous], rest))
})
}
@@ -188,3 +198,11 @@ pub fn any_string() -> Parser(String) {
|> many
|> map(with: string.concat)
}
+
+pub fn string_literal(expected: String) -> Parser(String) {
+ expected
+ |> string.to_graphemes()
+ |> list.map(with: grapheme_literal)
+ |> sequence
+ |> map(with: string.concat)
+}