@ -0,0 +1,52 @@ | |||||
include import "./compile.ml" | |||||
open import "prelude.ml" | |||||
open import "lua/io.ml" | |||||
let resolve_addr = function | |||||
| Combinator n -> n ^ "_combinator" | |||||
| Arg i -> "stack[sp - " ^ show (i + 1) ^ "][3]" | |||||
let gm2lua = function | |||||
| Push addr -> " stack[sp + 1] = " ^ resolve_addr addr ^ "; sp = sp + 1" | |||||
| Pop n -> " sp = sp - " ^ show n | |||||
| Update n -> " stack[sp - " ^ show (n + 1) ^ "] = { I, stack[sp] }; sp = sp - 1" | |||||
| Mkap -> " stack[sp - 1] = { A, stack[sp - 1], stack[sp] }; sp = sp - 1" | |||||
| Unwind -> " return unwind()" | |||||
let compute_local_set xs = | |||||
let rec go i (s : S.t string) = function | |||||
| Cons ((name, _, _), xs) -> | |||||
if i >= 100 then | |||||
s | |||||
else | |||||
go (i + 2) (S.insert name (S.insert (name ^ "_combinator") s)) xs | |||||
| Nil -> s | |||||
go 1 S.empty xs | |||||
let sc2lua (name, arity, body) = | |||||
let body = | |||||
body | |||||
|> foldl (fun x s -> x ^ gm2lua s ^ ";\n") (name ^ " = function()\n") | |||||
|> (^ "end") | |||||
let dec = | |||||
name ^ "_combinator = { F, " ^ name ^ ", " ^ show arity ^ ", " ^ show name ^ " };" | |||||
body ^ "\n" ^ dec | |||||
let preamble = | |||||
let f = open_for_reading "preamble.lua" | |||||
let x = read_all f | |||||
close_file f | |||||
match x with | |||||
| Some s -> s | |||||
| None -> error "no preamble.lua" | |||||
let assm_program decs = | |||||
match decs with | |||||
| [] -> error "empty program" | |||||
| _ -> | |||||
let Cons (local1, locals) = | |||||
compute_local_set decs |> S.members | |||||
let local_decs = | |||||
foldl (fun x v -> x ^ ", " ^ v) ("local " ^ local1) locals | |||||
let body = foldl (fun x s -> x ^ sc2lua s ^ "\n") "" decs | |||||
preamble ^ local_decs ^ "\n" ^ body ^ "stack[sp] = { A, main_combinator, 0 }; unwind()" |
@ -0,0 +1,105 @@ | |||||
module M = import "data/map.ml" | |||||
module S = import "data/set.ml" | |||||
open import "prelude.ml" | |||||
open import "./lang.ml" | |||||
open import "./lib/monads.ml" | |||||
type addr = | |||||
| Combinator of string | |||||
| Arg of int | |||||
type gm_code = | |||||
| Push of addr | |||||
| Update of int | |||||
| Pop of int | |||||
| Unwind | |||||
| Mkap | |||||
instance show gm_code begin | |||||
let show = function | |||||
| Mkap -> "Mkap" | |||||
| Unwind -> "Unwind" | |||||
| Push (Combinator k) -> "Push " ^ k | |||||
| Push (Arg i) -> "Arg " ^ show i | |||||
| Update n -> "Update " ^ show n | |||||
| Pop n -> "Pop " ^ show n | |||||
end | |||||
let rec lambda_lift = function | |||||
| Ref v -> pure (Ref v) | |||||
| App (f, x) -> (| app (lambda_lift f) (lambda_lift x) |) | |||||
| Lam (v, x) -> | |||||
let! body = lambda_lift x | |||||
let! (i, defs, known_sc) = get | |||||
let vars = | |||||
x |> free_vars | |||||
|> S.delete v | |||||
|> flip S.difference known_sc | |||||
|> S.members | |||||
let def = ("Lam" ^ show i, vars ++ [v], body) | |||||
let app = foldl (fun f -> app f # Ref) (Ref ("Lam" ^ show i)) vars | |||||
put (i + 1, Decl def :: defs, known_sc) | |||||
|> map (const app) | |||||
| Case (sc, alts) -> | |||||
alts | |||||
|> map (fun (_, x) -> x) | |||||
|> foldl app sc | |||||
|> lambda_lift | |||||
let rec eta_contract = function | |||||
| Decl (n, a, e) as dec -> | |||||
match a, e with | |||||
| [], _ -> dec | |||||
| xs, App (f, Ref v) -> | |||||
if v == last xs && not (S.member v (free_vars f)) then | |||||
eta_contract (Decl (n, init a, f)) | |||||
else | |||||
dec | |||||
| _, _ -> dec | |||||
| Data c -> Data c | |||||
let rec lambda_lift_sc = function | |||||
| Decl (n, a, e) -> | |||||
match e with | |||||
| Lam (v, e) -> lambda_lift_sc (Decl (n, a ++ [v], e)) | |||||
| _ -> | |||||
let! e = lambda_lift e | |||||
let! _ = modify (fun (a, b, s) -> (a, b, S.insert n s)) | |||||
pure (Decl (n, a, e)) | |||||
| Data c -> Data c |> pure | |||||
type dlist 'a <- list 'a -> list 'a | |||||
let rec compile (env : M.t string int) = function | |||||
| Ref v -> | |||||
match M.lookup v env with | |||||
| Some i -> (Push (Arg i) ::) | |||||
| None -> (Push (Combinator v) ::) | |||||
| App (f, x) -> | |||||
let f = compile env f | |||||
let x = compile (map (1 +) env) x | |||||
f # x # (Mkap ::) | |||||
| Lam _ -> error "Can not compile lambda expression, did you forget to lift?" | |||||
| Case _ -> error "Can not compile case expression, did you forget to lift?" | |||||
let supercomb (_, args, exp) = | |||||
let env = M.from_list (zip args [0..length args]) | |||||
let k = compile (M.from_list (zip args [0..length args])) exp | |||||
k [Update (length env), Pop (length env), Unwind] | |||||
let known_scs = S.from_list [ "getchar", "putchar" ] | |||||
let program decs = | |||||
let (decs, (_, lams, _)) = | |||||
run_state (traverse (lambda_lift_sc # eta_contract) decs) (0, [], known_scs) | |||||
flip map (lams ++ decs) @@ function | |||||
| Decl ((nm, args, _) as sc) -> | |||||
let code = supercomb sc | |||||
(nm, length args, code) | |||||
| Data _ -> error "data declaration in compiler" |
@ -0,0 +1,50 @@ | |||||
module C = import "./compile.ml" | |||||
module A = import "./assemble.ml" | |||||
open import "./parser.ml" | |||||
open import "prelude.ml" | |||||
open import "lua/io.ml" | |||||
let go infile outfile = | |||||
let infile = open_for_reading infile | |||||
let outfile = open_file outfile Write_m | |||||
match read_all infile with | |||||
| Some str -> | |||||
match lex prog str with | |||||
| Right (ds, _) -> | |||||
ds | |||||
|> ds_prog | |||||
|> C.program | |||||
|> A.assm_program | |||||
|> write_bytes outfile | |||||
| Left e -> print e | |||||
| _ -> () | |||||
close_file infile | |||||
close_file outfile | |||||
let test str = | |||||
match lex prog str with | |||||
| Right (ds, _) -> | |||||
ds | |||||
|> ds_prog | |||||
|> C.program | |||||
|> A.assm_program | |||||
|> put_line | |||||
| Left e -> print e | |||||
let test_file infile = | |||||
let infile = open_for_reading infile | |||||
match read_all infile with | |||||
| Some str -> test str | |||||
| None -> () | |||||
close_file infile | |||||
external val args : string * string = | |||||
"{ _1 = select(1, ...), _2 = select(2, ...) }" | |||||
external val has_args : bool = "select('#', ...) ~= 0" | |||||
let () = | |||||
if has_args then | |||||
let (from, into) = args | |||||
go from into | |||||
else () |
@ -0,0 +1,69 @@ | |||||
open import "prelude.ml" | |||||
module S = import "data/set.ml" | |||||
module M = import "data/map.ml" | |||||
type expr = | |||||
| Ref of string | |||||
| App of expr * expr | |||||
| Lam of string * expr | |||||
| Case of expr * list (string * expr) | |||||
let app = curry App | |||||
let lam = curry Lam | |||||
let rec free_vars = function | |||||
| Ref v -> S.singleton v | |||||
| App (f, x) -> S.union (free_vars f) (free_vars x) | |||||
| Lam (v, x) -> v `S.delete` free_vars x | |||||
| Case (e, bs) -> | |||||
bs | |||||
|> map (fun (_, e) -> free_vars e) | |||||
|> foldl S.union S.empty | |||||
|> S.union (free_vars e) | |||||
let rec subst m = function | |||||
| Ref v -> | |||||
match M.lookup v m with | |||||
| Some s -> s | |||||
| None -> Ref v | |||||
| App (f, x) -> App (subst m f, subst m x) | |||||
| Lam (v, x) -> Lam (v, subst (M.delete v m) x) | |||||
| Case (e, xs) -> Case (subst m e, map (second (subst m)) xs) | |||||
type hstype = | |||||
| Tycon of string | |||||
| Tyvar of string | |||||
| Tyapp of hstype * hstype | |||||
type constr = Constr of string * list hstype | |||||
type decl = | |||||
| Decl of string * list string * expr | |||||
| Data of string * list string * list constr | |||||
type prog <- list decl | |||||
let rec xs !! i = | |||||
match xs, i with | |||||
| Cons (x, _), 0 -> x | |||||
| Cons (_, xs), i when i > 0 -> xs !! (i - 1) | |||||
| _, _ -> error "empty list and/or negative index" | |||||
let ds_data (_, _, cs) = | |||||
let ncons = length cs | |||||
let alts = map (("c" ^) # show) [1..ncons] | |||||
let ds_con i (Constr (n, args)) = | |||||
let arity = length args | |||||
let alt = alts !! i | |||||
let args = map (("x" ^) # show) [1..arity] | |||||
Decl (n, args, foldr lam (foldl app (Ref alt) (map Ref args)) alts) | |||||
let rec go i = function | |||||
| [] -> [] | |||||
| Cons (x, xs) -> ds_con i x :: go (i + 1) xs | |||||
go 0 cs | |||||
let ds_prog prog = | |||||
let! c = prog | |||||
match c with | |||||
| Data c -> ds_data c | |||||
| Decl (n, args, e) -> [Decl (n, args, e)] |
@ -0,0 +1,133 @@ | |||||
include import "./lib/parsers.ml" | |||||
open import "prelude.ml" | |||||
let lex = run_parser | |||||
let line_comment () = | |||||
let! _ = symbol "--" | |||||
let rec go = | |||||
let! x = map (const "\n") eof <|> char | |||||
if x == "\n" then | |||||
pure () | |||||
else | |||||
go | |||||
go | |||||
let whitepiece : forall 'm. monad 'm => parser_t 'm () = | |||||
(try (void @@ one_of " \n\v\t\r") <|> try (line_comment ())) | |||||
<?> "white space" | |||||
let whitespace : forall 'm. monad 'm => parser_t 'm () = | |||||
void (many whitepiece) | |||||
let lexeme p = | |||||
let! _ = whitespace | |||||
p | |||||
let oparen : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol "(") | |||||
let cparen : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol ")") | |||||
let comma : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol ",") | |||||
let semi : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol ";") | |||||
let osquare : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol "[") | |||||
let csquare : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol "]") | |||||
let obrace : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol "{") | |||||
let cbrace : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol "}") | |||||
let back : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol "\\") | |||||
let arrow : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol "->") | |||||
let darrow : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol "=>") | |||||
let equals : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol "=") | |||||
let pipe : forall 'm. monad 'm => parser_t 'm () = try @@ void @@ lexeme (symbol "|") | |||||
let small : forall 'm. monad 'm => parser_t 'm string = | |||||
try (satisfy (fun c -> "a" <= c && c <= "z") <|> symbol "_") <?> "small letter" | |||||
let big : forall 'm. monad 'm => parser_t 'm string = | |||||
try (satisfy (fun c -> "A" <= c && c <= "Z")) <?> "big letter" | |||||
let iskw = function | |||||
| "case" | |||||
| "class" | |||||
| "data" | |||||
| "default" | |||||
| "deriving" | |||||
| "do" | |||||
| "else" | |||||
| "if" | |||||
| "import" | |||||
| "in" | |||||
| "infix" | |||||
| "infixl" | |||||
| "infixr" | |||||
| "instance" | |||||
| "let" | |||||
| "module" | |||||
| "newtype" | |||||
| "of" | |||||
| "then" | |||||
| "type" | |||||
| "where" | |||||
| "_" -> true | |||||
| _ -> false | |||||
let isreserved = function | |||||
| "=" | "=>" | "->" | "|" -> true | |||||
| _ -> false | |||||
let varid : forall 'm. monad 'm => parser_t 'm string = | |||||
flip (<?>) "variable name" # lexeme @@ | |||||
let! c = small | |||||
let! cs = | |||||
many_fold (^) "" (small <|> big <|> try (symbol "'")) | |||||
<|> pure "" | |||||
let id = c ^ cs | |||||
if iskw id then | |||||
unexpected id | |||||
else | |||||
pure id | |||||
let conid : forall 'm. monad 'm => parser_t 'm string = | |||||
flip (<?>) "constructor name" # lexeme @@ | |||||
let! c = big | |||||
let! cs = | |||||
many_fold (^) "" (small <|> big <|> try (symbol "'")) | |||||
<|> pure "" | |||||
pure (c ^ cs) | |||||
let tyvar = varid | |||||
let tycon = conid | |||||
let tycls = conid | |||||
let keyword c = lexeme (symbol c) <?> "``" ^ c ^ "''" | |||||
let operator : forall 'm. monad 'm => parser_t 'm string = | |||||
flip (<?>) "operator" # lexeme @@ | |||||
let! c = one_of "!#$%&*+./<=>?@\\^|-~" | |||||
let! cs = many_fold (^) "" (one_of ":!#$%&*+./<=>?@\\^|-~") | |||||
let op = c ^ cs | |||||
if isreserved op then | |||||
unexpected op | |||||
else | |||||
pure op | |||||
let digit : forall 'm. monad 'm => parser_t 'm string = | |||||
satisfy (fun c -> "0" <= c && c <= "9") <?> "digit" | |||||
let hexit : forall 'm. monad 'm => parser_t 'm string = | |||||
digit | |||||
<|> satisfy (fun c -> "a" <= c && c <= "f") | |||||
<|> satisfy (fun c -> "A" <= c && c <= "F") | |||||
let integer : forall 'm. monad 'm => parser_t 'm int = | |||||
let decimal = | |||||
let! c = digit | |||||
let! cs = many_fold (^) "" digit | |||||
pure (c ^ cs) | |||||
let hexadecimal = | |||||
let! _ = symbol "0x" | |||||
let! c = hexit | |||||
let! cs = many_fold (^) "" hexit | |||||
pure ("0x" ^ c ^ cs) | |||||
let! c = (try hexadecimal <|> decimal) <?> "hex or decimal integer" | |||||
match parse_int c with | |||||
| None -> error "no parse" | |||||
| Some x -> pure x |
@ -0,0 +1,42 @@ | |||||
open import "prelude.ml" | |||||
type identity 'a = Id of 'a | |||||
instance functor identity begin | |||||
let f <$> Id x = Id (f x) | |||||
end | |||||
instance applicative identity begin | |||||
let pure = Id | |||||
let Id f <*> Id x = Id (f x) | |||||
end | |||||
instance monad identity begin | |||||
let Id x >>= f = f x | |||||
end | |||||
type state 's 'a = State of 's -> 'a * 's | |||||
let run_state (State k) = k | |||||
instance functor (state 's) begin | |||||
let f <$> State x = State (first f # x) | |||||
end | |||||
instance applicative (state 's) begin | |||||
let pure x = State (x,) | |||||
let State f <*> State x = State @@ fun s -> | |||||
let (f, s) = f s | |||||
let (x, s) = x s | |||||
(f x, s) | |||||
end | |||||
instance monad (state 's) begin | |||||
let State x >>= f = State @@ fun s -> | |||||
let (x, s) = x s | |||||
run_state (f x) s | |||||
end | |||||
let get = State (fun s -> (s, s)) | |||||
let put x = State (fun _ -> ((), x)) | |||||
let modify f = State (fun s -> ((), f s)) |
@ -0,0 +1,232 @@ | |||||
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 |
@ -0,0 +1,69 @@ | |||||
include import "./lang.ml" | |||||
include import "./lexer.ml" | |||||
open import "prelude.ml" | |||||
let parse = lex | |||||
let laid_out_block p = between obrace cbrace (sep_end_by_1 semi p) | |||||
let rec atom : forall 'm. monad 'm => parser_t 'm expr = | |||||
map Ref (try varid) | |||||
<+> map Ref (try conid) | |||||
<+> between (try oparen) cparen expr | |||||
and fexp : forall 'm. monad 'm => parser_t 'm expr = | |||||
let! a = atom | |||||
let! ats = many atom | |||||
pure (foldl (curry App) a ats) | |||||
and expr : forall 'm. monad 'm => parser_t 'm expr = | |||||
let lam = | |||||
let! _ = back | |||||
let! vs = many (try varid) | |||||
let! _ = arrow | |||||
let! b = expr | |||||
pure (foldr ((Lam #) # curry id) b vs) | |||||
let case = | |||||
let! _ = keyword "case" | |||||
let! e = fexp | |||||
let! _ = keyword "of" | |||||
let! arms = | |||||
laid_out_block ( | |||||
let! c = conid | |||||
let! vs = many (try varid) | |||||
let! _ = arrow | |||||
let! e = expr | |||||
pure (c, foldr ((Lam #) # curry id) e vs) | |||||
) | |||||
pure (Case (e, arms)) | |||||
try lam <|> try case <+> fexp | |||||
let rec ty_atom : forall 'm. monad 'm => parser_t 'm hstype = | |||||
map Tyvar (try varid) | |||||
<|> map Tycon (try conid) | |||||
<+> between (try oparen) cparen ty_exp | |||||
and ty_exp : forall 'm. monad 'm => parser_t 'm hstype = | |||||
let! a = ty_atom | |||||
let! ats = many ty_atom | |||||
pure (foldl (curry Tyapp) a ats) | |||||
let datadec : forall 'm. monad 'm => parser_t 'm decl = | |||||
let! _ = keyword "data" | |||||
let datacon = | |||||
let! nm = conid | |||||
let! args = many ty_atom | |||||
pure (Constr (nm, args)) | |||||
let! nm = conid | |||||
let! args = many (try varid) | |||||
let! _ = equals | |||||
let! c = sep_by_1 pipe (try datacon) | |||||
pure (Data (nm, args, c)) | |||||
let dec : forall 'm. monad 'm => parser_t 'm decl = | |||||
let func = | |||||
let! nm = varid | |||||
let! args = many (try varid) | |||||
let! _ = equals | |||||
map (fun e -> Decl (nm, args, e)) expr | |||||
try datadec <|> func | |||||
let prog : forall 'm. monad 'm => parser_t 'm prog = | |||||
sep_end_by_1 semi dec <* eof |
@ -0,0 +1,68 @@ | |||||
local A, F, I = {}, {}, {} | |||||
local stack = {} | |||||
local sp = 1 | |||||
local function repr(x) | |||||
if type(x) == 'table' then | |||||
if x[1] == F then | |||||
return x[4] | |||||
elseif x[1] == A then | |||||
return repr(x[2]) .. '(' .. repr(x[3]) .. ')' | |||||
elseif x[1] == I then | |||||
return '&' .. repr(x[2]) | |||||
end | |||||
else | |||||
return tostring(x) | |||||
end | |||||
end | |||||
local function unwind() | |||||
local x = stack[sp] | |||||
if type(x) == 'table' then | |||||
if x[1] == A then | |||||
stack[sp + 1] = x[2]; sp = sp + 1 | |||||
return unwind() | |||||
elseif x[1] == I then | |||||
stack[sp] = x[2] | |||||
return unwind() | |||||
elseif x[1] == F then | |||||
if sp - 1 >= x[3] then | |||||
return x[2]() | |||||
else | |||||
print("insufficient arguments for supercombinator " .. x[4]) | |||||
print 'stack dump:' | |||||
for k, v in pairs(stack) do | |||||
print(sp - k, repr(v)) | |||||
end | |||||
error() | |||||
end | |||||
end | |||||
else | |||||
os.exit(x) | |||||
end | |||||
end | |||||
local function getchar() | |||||
local k = stack[sp - 1][3]; sp = sp - 1 | |||||
local knil = stack[sp - 1][3]; sp = sp - 1 | |||||
local ch = io.read(1) | |||||
if ch then | |||||
stack[sp] = { A, k, ch:byte() } | |||||
else | |||||
stack[sp] = { A, knil, 0 } | |||||
end | |||||
return unwind() | |||||
end | |||||
local getchar_combinator = { F, getchar, 2 } | |||||
local function putchar() | |||||
local ch = stack[sp - 1][3]; | |||||
local k = stack[sp - 2][3]; sp = sp - 1 | |||||
io.write(string.char(ch)) | |||||
stack[sp] = { A, k, ch } | |||||
return unwind() | |||||
end | |||||
local putchar_combinator = { F, putchar, 2 } |
@ -0,0 +1,6 @@ | |||||
data List a = Nil | Cons a (List a); | |||||
map f xs = case xs of { Nil -> Nil; Cons x xs -> Cons (f x) (map f xs) }; | |||||
readall k = getchar (\ch -> readall (\xs -> k (Cons ch xs))) (\ch -> k Nil); | |||||
putall x xs = case xs of { Nil -> x; Cons x xs -> putchar x (\ch -> putall x xs) }; | |||||
id x = x; | |||||
main x = readall (putall x); |