Monad/Parser.bruijn
# MIT License, Copyright (c) 2024 Marvin Borner
# see samples/fun/minibruijn for example usage
# TODO: also support line/char offset
:import std/List .
:import std/Combinator .
:import std/Char C
:import std/Result R
# TODO: don't just use strings for errors
error-unexpected ["unexpected symbol " ++ 0] ⧗ Error
error-end-of-input "end of input" ⧗ Error
error-expected-end "expected end of input" ⧗ Error
error-custom [0] ⧗ Error
error-compose [[C.?eq? 1 0 0 (1 ++ " or " ++ 0)]] ⧗ Error → Error → Error
satisfy [[0 [[[go]]] end]] ⧗ (a → Boolean) → (Parser a)
go 4 2 (R.ok (2 : 1)) (R.err (error-unexpected {}2))
end R.err error-end-of-input
char [satisfy (C.eq? 0)] ⧗ Char → (Parser a)
:test (char 'a' "abc") (R.ok ('a' : "bc"))
:test (char 'b' "abc") (R.err (error-unexpected "a"))
:test (char 'a' [[0]]) (R.err error-end-of-input)
map [[[R.map ok (1 0)]]] ⧗ (a → b) → (Parser a) → (Parser b)
ok &[[(4 1) : 0]]
…<$>… map
fail [[R.err 1]] ⧗ a → (Parser a)
pure [[R.ok (1 : 0)]] ⧗ a → (Parser a)
ap [[[R.bind (2 0) ok]]] ⧗ (Parser (a → b)) → (Parser a) → (Parser b)
ok &[[R.map ok (3 0)]]
ok &[[(3 1) : 0]]
…<*>… ap
string y [[0 [[[go]]] (pure [[0]])]] ⧗ String → (Parser a)
go cons <$> (char 2) <*> (4 1)
:test (string "ac" "abc") (R.err (error-unexpected "b"))
:test (string "ab" "abcd") (R.ok ("ab" : "cd"))
return pure ⧗ a → (Parser a)
bind [[[R.bind (2 0) ok]]] ⧗ (Parser a) → (a → (Parser b)) → (Parser a)
ok &[[3 1 0]]
…>>=… bind
alt [[[2 0 R.ok err]]] ⧗ (Parser a) → (Parser a) → (Parser a)
err [2 1 R.ok err]
err R.err ∘ (error-compose 0)
…<|>… alt
:test ((string "ab") <|> (string "cd") "abc") (R.ok ("ab" : "c"))
:test ((string "ab") <|> (string "cd") "cde") (R.ok ("cd" : "e"))
:test ((string "ab") <|> (string "cd") "acd") (R.err (error-compose (error-unexpected "c") (error-unexpected "a")))
:test ((string "ab") <|> (string "cd") "cbe") (R.err (error-compose (error-unexpected "c") (error-unexpected "b")))
eof [0 [[[go]]] end] ⧗ (Parser a)
go R.err error-expected-end
end R.ok ([[0]] : [[0]])
lift-result [0 pure fail] ⧗ (Result a) → (Parser a)
:test (lift-result (R.ok "ok") "rst") (R.ok ("ok" : "rst"))
:test (lift-result (R.err "oh") "rst") (R.err "oh")
# =========================================================================== #
# most relevant functions are defined - we can now derive from Generic/Monad! #
# =========================================================================== #
:input std/Generic/Monad
:test (k <$ (string "ab") "abc") (R.ok (k : "c"))
:test ((char '{') *> (string "wow") <* (char '}') "{wow}{owo}") (R.ok ("wow" : "{owo}"))