import gleam/option.{None, Some} import gleam/string import nibble.{type Parser, do, return} import node.{type Node, EndOfLine} pub fn exact_string( expected: String, node: Node, ) -> Parser(Node, String, String) { nibble.in( { use _ <- do(string.to_graphemes(expected) |> match_chars(expected)) return(node) }, "exact_string('" <> expected <> "')", ) } pub fn consume_exact_string(expected: String) -> Parser(Nil, String, String) { nibble.in( { use _ <- nibble.do(exact_string(expected, node.Let)) // NOTE: doesn't matter which constructor return(Nil) }, "consume_exact_string('" <> expected <> "')", ) } fn match_chars( chars: List(String), context: String, ) -> Parser(Nil, String, String) { nibble.in( { case chars { [] -> return(Nil) [first, ..rest] -> { use _ <- do( nibble.take_map( "expected '" <> first <> "' in keyword '" <> context <> "'", fn(tok) { case tok == first { True -> Some(Nil) False -> None } }, ), ) match_chars(rest, context) } } }, "match_chars(" <> context <> ")", ) } pub fn let_keyword() -> Parser(Node, String, String) { nibble.in(exact_string("let", node.Let), "let_keyword") } pub fn end_of_line() -> Parser(Node, String, String) { nibble.in( { use _ <- nibble.do( nibble.one_of([ nibble.in(nibble.token("\n"), "unix_line_ending"), consume_exact_string("\r\n"), ]), ) return(EndOfLine) }, "end_of_line", ) }