You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

232 lines
5.5 KiB

open import "prelude.ml"
open import "./monads.ml"
private type consumed = C | E
private type error = Unexpected of string * list string
instance show error begin
let show = function
| Unexpected (s, []) -> s
| Unexpected (s, ms) ->
"Unexpected " ^ s ^ "\n"
^ "Expecting one of " ^ foldl (^) "" ms
end
private type result 'a =
| Ok of consumed * 'a * string
| Err of consumed * error * string
let join_consumed x y =
match x with
| C -> C
| E -> y
type parser_t 'm 'a = private P of string -> 'm (result 'a)
type parser <- parser_t identity
instance functor 'm => functor (parser_t 'm) begin
let f <$> P x = P @@ fun i ->
flip map (x i) @@ fun p ->
match p with
| Ok (c, x, i) -> Ok (c, f x, i)
| Err e -> Err e
end
instance monad 'm => applicative (parser_t 'm) begin
let pure x = P (fun s -> pure (Ok (E, x, s)))
let P f <*> P x = P @@ fun s ->
let! f = f s
match f with
| Ok (c, f, s) ->
let! x = x s
match x with
| Ok (c', x, s) -> pure @@ Ok (join_consumed c c', f x, s)
| Err (c', p) -> pure @@ Err (join_consumed c c', p)
| Err e -> pure @@ Err e
end
let x *> y = (fun _ x -> x) <$> x <*> y
let x <* y = (| const x y |)
instance monad 'm => monad (parser_t 'm) begin
let P x >>= f = P @@ fun s ->
let! x = x s
match x with
| Ok (c, x, s) ->
let P kont = f x
let! x = kont s
match x with
| Ok (c', x, s) -> pure @@ Ok (join_consumed c c', x, s)
| Err (c', p) -> pure @@ Err (join_consumed c c', p)
| Err e -> pure @@ Err e
end
let private fail e = P (fun s -> pure (Err (E, e, s)))
let empty : forall 'm 'a. monad 'm => parser_t 'm 'a =
fail (Unexpected ("empty parse", []))
let unexpected e =
fail (Unexpected (e, []))
let alt_err (Unexpected (u, xs)) (Unexpected (_, ys)) =
Unexpected (u, xs ++ ys)
let P x <|> P y = P @@ fun s ->
let! x = x s
match x with
| Ok x -> pure (Ok x)
| Err (c, m, s) ->
let! y = y s
match y with
| Ok (c', x, s) -> pure (Ok (join_consumed c c', x, s))
| Err (c', m', s) -> pure (Err (join_consumed c c', alt_err m m', s))
let P x <+> y = P @@ fun s ->
let! x = x s
match x with
| Ok x -> pure (Ok x)
| Err (c, m, s) ->
let P y = force y
let! y = y s
match y with
| Ok (c', x, s) -> pure (Ok (join_consumed c c', x, s))
| Err (c', m', s) -> pure (Err (join_consumed c c', alt_err m m', s))
private module S = import "lua/string.ml"
let char : forall 'm. applicative 'm => parser_t 'm string =
P @@ fun s ->
let x = S.substring s 1 1
if x <> "" then
let r = S.substring s 2 (S.length s)
pure @@ Ok (C, x, r)
else
pure @@ Err (E, Unexpected ("end-of-file", ["character"]), s)
let eof : forall 'm. applicative 'm => parser_t 'm () =
P @@ fun s ->
if s == "" then
pure @@ Ok (E, (), s)
else
pure @@ Err (E, Unexpected (S.substring s 1 1, ["end-of-file"]), s)
let satisfy p = P @@ fun s ->
let x = S.substring s 1 1
if x <> "" && p x then
pure @@ Ok (C, x, S.substring s 2 (S.length s))
else
let m =
if x == "" then
"end of file"
else x
pure @@ Err (E, Unexpected (m, ["character"]), s)
let P k <?> m = P @@ fun s ->
let! x = k s
match x with
| Ok e -> pure (Ok e)
| Err (c, Unexpected (u, _), s) -> pure (Err (c, Unexpected (u, [m]), s))
let many_fold k z (P x) =
let rec go consumed kont s =
let! x = x s
match x with
| Err ((c, _, s) as p) ->
match c with
| C -> pure (Err p)
| E -> kont consumed z s
| Ok (c, x, s) ->
match c with
| E -> error @@ "many: got parser that accepts the empty string"
| C -> go C (fun c -> kont c # k x) s
P (go E (fun c z s -> pure (Ok (c, z, s))))
let many p = many_fold (::) [] p
let some p =
let! x = p
(x ::) <$> many p
let sep_by_1 sep p =
let! x = p
let! xs = many (sep *> p)
pure (x :: xs)
let sep_by sep p = sep_by_1 sep p <|> pure []
external private val is_infix_of : string -> string -> bool =
"function(s, s2) return s2:find(s) ~= nil end"
external private val is_prefix_of : string -> string -> bool =
"function(s, s2) return (s2:find(s)) == 1 end"
let one_of chs =
let len = S.length chs
let rec loop ch i =
if i > len then
fail @@ Unexpected (ch, ["one of \"" ^ chs ^ "\""])
else if ch == S.substring chs i i then
pure ch
else
loop ch (i + 1)
let! ch = char
loop ch 1
let symbol str =
let len = S.length str
let rec loop acc i =
if i > len then
pure acc
else
let! c = char <?> S.substring str i i
if c == S.substring str i i then
loop (acc ^ c) (i + 1)
else
fail @@ Unexpected (acc ^ c, [S.substring str 1 i])
loop "" 1
let between o c p =
let! _ = o
let! x = p
let! _ = c
pure x
let try (P x) = P @@ fun s ->
let! x = x s
match x with
| Ok c -> pure (Ok c)
| Err (_, p, _) -> pure (Err (E, p, s))
let optionally p = map Some (try p) <|> pure None
let rec sep_end_by_1 sep p =
let! x = p
( let! _ = sep
let! xs = sep_end_by sep p
pure (x :: xs)
) <|> pure [x]
and sep_end_by sep p =
sep_end_by_1 sep p <|> pure []
let parse (P x) s =
let! x = x s
match x with
| Ok (_, x, r) -> pure @@ Right (x, r)
| Err (_, m, _) -> pure @@ Left m
let run_parser p s =
let Id x = parse p s
x
let run_parser' (P x) s =
let Id x = x s
x
let lift m = P @@ fun s ->
let! x = m
pure @@ Ok (E, x, s)
let morph (k : forall 'a. 'm 'a -> 'n 'a) (P x) = P @@ fun s -> k (x s)
let void x = map (const ()) x