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, ctx) { use _ <- do(string.to_graphemes(expected) |> match_chars(expected)) return(node) } pub fn consume_exact_string(expected: String) -> Parser(Nil, String, ctx) { use _ <- nibble.do(exact_string(expected, node.Let)) // NOTE: doesn't matter which constructor return(Nil) } fn match_chars(chars: List(String), context: String) -> Parser(Nil, String, ctx) { 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) } } } pub fn let_keyword() -> Parser(Node, String, ctx) { exact_string("let", node.Let) } pub fn end_of_line() -> Parser(Node, String, ctx) { use _ <- nibble.do( nibble.one_of([nibble.token("\n"), consume_exact_string("\r\n")]), ) return(EndOfLine) }