parser.gleam

 1import gleam/option.{None, Some}
 2import gleam/string
 3import nibble.{type Parser, do, return}
 4import node.{type Node, EndOfLine}
 5
 6pub fn exact_string(expected: String, node: Node) -> Parser(Node, String, ctx) {
 7  use _ <- do(string.to_graphemes(expected) |> match_chars(expected))
 8  return(node)
 9}
10
11pub fn consume_exact_string(expected: String) -> Parser(Nil, String, ctx) {
12  use _ <- nibble.do(exact_string(expected, node.Let))
13  // NOTE: doesn't matter which constructor 
14
15  return(Nil)
16}
17
18fn match_chars(chars: List(String), context: String) -> Parser(Nil, String, ctx) {
19  case chars {
20    [] -> return(Nil)
21
22    [first, ..rest] -> {
23      use _ <- do(
24        nibble.take_map(
25          "expected '" <> first <> "' in keyword '" <> context <> "'",
26          fn(tok) {
27            case tok == first {
28              True -> Some(Nil)
29              False -> None
30            }
31          },
32        ),
33      )
34      match_chars(rest, context)
35    }
36  }
37}
38
39pub fn let_keyword() -> Parser(Node, String, ctx) {
40  exact_string("let", node.Let)
41}
42
43pub fn end_of_line() -> Parser(Node, String, ctx) {
44  use _ <- nibble.do(
45    nibble.one_of([nibble.token("\n"), consume_exact_string("\r\n")]),
46  )
47
48  return(EndOfLine)
49}