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.

286 lines
8.3 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. module M = import "data/map.ml"
  2. module S = import "data/set.ml"
  3. module Str = import "data/set.ml"
  4. open import "prelude.ml"
  5. open import "./lang.ml"
  6. open import "./lib/monads.ml"
  7. type addr =
  8. | Combinator of string
  9. | Local of int
  10. | Arg of int
  11. | Int of int
  12. type gm_code =
  13. | Push of addr
  14. | Update of int
  15. | Pop of int
  16. | Slide of int
  17. | Alloc of int
  18. | Unwind
  19. | Mkap
  20. | Add | Sub | Mul | Div | Eval
  21. | Iszero of list gm_code * list gm_code
  22. | Pack of int * int
  23. | Casejump of list (int * list gm_code)
  24. instance show gm_code begin
  25. let show = function
  26. | Mkap -> "Mkap"
  27. | Unwind -> "Unwind"
  28. | Push (Combinator k) -> "Push " ^ k
  29. | Push (Arg i) -> "Pusharg " ^ show i
  30. | Push (Local i) -> "Pushlocal " ^ show i
  31. | Push (Int i) -> "Pushint " ^ show i
  32. | Update n -> "Update " ^ show n
  33. | Pop n -> "Pop " ^ show n
  34. | Slide n -> "Slide " ^ show n
  35. | Alloc n -> "Alloc " ^ show n
  36. | Add -> "Add"
  37. | Mul -> "Mul"
  38. | Sub -> "Sub"
  39. | Div -> "Div"
  40. | Eval -> "Eval"
  41. | Pack (arity, tag) -> "Pack{" ^ show arity ^ "," ^ show tag ^ "}"
  42. | Casejump xs -> "Casejump " ^ show xs
  43. | Iszero xs -> "Iszero " ^ show xs
  44. end
  45. type program_item =
  46. | Sc of string * int * list gm_code
  47. | Fd of fdecl
  48. instance show program_item begin
  49. let show = function
  50. | Sc p -> show p
  51. | Fd _ -> "<foreign item>"
  52. end
  53. let rec lambda_lift strict = function
  54. | Ref v -> pure (Ref v)
  55. | Lit v -> pure (Lit v)
  56. | App (f, x) -> (| app (lambda_lift false f) (lambda_lift false x) |)
  57. | Lam (v, x) ->
  58. let! body = lambda_lift true x
  59. let! (i, defs, known_sc) = get
  60. let vars =
  61. x |> free_vars
  62. |> S.delete v
  63. |> flip S.difference known_sc
  64. |> S.members
  65. let def = ("Lam" ^ show i, vars ++ [v], body)
  66. let app = foldl (fun f -> app f # Ref) (Ref ("Lam" ^ show i)) vars
  67. put (i + 1, Decl def :: defs, known_sc)
  68. |> map (const app)
  69. | Case (sc, alts) ->
  70. let! sc = lambda_lift true sc
  71. let! alts = traverse (fun (c, args, e) -> (c,args,) <$> lambda_lift true e) alts
  72. let case = Case (sc, alts)
  73. if strict then
  74. pure case
  75. else
  76. let! (i, defs, known_sc) = get
  77. let vars =
  78. case
  79. |> free_vars
  80. |> flip S.difference known_sc
  81. |> S.members
  82. let def = ("Lam" ^ show i, vars, case)
  83. let app = foldl (fun f -> app f # Ref) (Ref ("Lam" ^ show i)) vars
  84. put (i + 1, Decl def :: defs, known_sc)
  85. |> map (const app)
  86. | Let (vs, e) ->
  87. let! vs = flip traverse vs @@ fun (v, e) ->
  88. (v,) <$> lambda_lift false e
  89. let! e = lambda_lift true e
  90. pure (Let (vs, e))
  91. let rec eta_contract = function
  92. | Decl (n, a, e) as dec ->
  93. match a, e with
  94. | [], _ -> dec
  95. | xs, App (f, Ref v) ->
  96. if v == last xs && not (S.member v (free_vars f)) then
  97. eta_contract (Decl (n, init a, f))
  98. else
  99. dec
  100. | _, _ -> dec
  101. | Data c -> Data c
  102. | Foreign i -> Foreign i
  103. let rec lambda_lift_sc = function
  104. | Decl (n, a, e) ->
  105. match e with
  106. | Lam (v, e) -> lambda_lift_sc (Decl (n, a ++ [v], e))
  107. | _ ->
  108. let! e = lambda_lift true e
  109. let! _ = modify (fun (a, b, s) -> (a, b, S.insert n s))
  110. pure (Decl (n, a, e))
  111. | Data c -> Data c |> pure
  112. | Foreign (Fimport { var } as i) ->
  113. let! _ = modify (second (second (S.insert var)))
  114. Foreign i |> pure
  115. type dlist 'a <- list 'a -> list 'a
  116. let cg_prim (Fimport { var, fent }) =
  117. let prim_math_op x =
  118. [ Push (Arg 0), Eval, Push (Arg 2), Eval, x, Update 2, Pop 2, Unwind ]
  119. let prim_equality =
  120. [ Push (Arg 0), Eval (* x, arg0, arg1, arg2, arg3 *)
  121. , Push (Arg 2), Eval (* y, x, arg0, arg1, arg2, arg3 *)
  122. , Sub (* y - x, arg0, arg1, arg2, arg3 *)
  123. , Iszero ([ Pack (0, 0) ], [ Pack (0, 1) ])
  124. , Update 2, Pop 2, Unwind ]
  125. match fent with
  126. | "add" -> (Sc (var, 2, prim_math_op Add), Add)
  127. | "sub" -> (Sc (var, 2, prim_math_op Sub), Sub)
  128. | "mul" -> (Sc (var, 2, prim_math_op Mul), Mul)
  129. | "div" -> (Sc (var, 2, prim_math_op Div), Div)
  130. | "equ" -> (Sc (var, 2, prim_equality), Unwind)
  131. | "seq" -> (Sc (var, 2, [ Push (Arg 0), Eval, Update 0, Push (Arg 2), Update 2, Pop 2, Unwind]), Eval)
  132. | e -> error @@ "No such primitive " ^ e
  133. type slot = As of int | Ls of int
  134. let offs n = function
  135. | As x -> As (x + n)
  136. | Ls x -> Ls (x + n)
  137. let incr = offs 1
  138. let private prim_scs : ref (M.t string gm_code) = ref M.empty
  139. let private is_arith_op = function
  140. | Add | Sub | Mul | Div | Iszero _ -> true
  141. | _ -> false
  142. let rec compile_lazy (env : M.t string slot) = function
  143. | Ref v ->
  144. match M.lookup v env with
  145. | Some (As i) -> (Push (Arg i) ::)
  146. | Some (Ls i) -> (Push (Local i) ::)
  147. | None -> (Push (Combinator v) ::)
  148. | App (f, x) ->
  149. let f = compile_lazy env f
  150. let x = compile_lazy (map incr env) x
  151. f # x # (Mkap ::)
  152. | Lam _ ->
  153. error "Can not compile lambda expression, did you forget to lift?"
  154. | Case _ ->
  155. error "Case expression in lazy context"
  156. | Lit i -> (Push (Int i) ::)
  157. | Let (vs, e) ->
  158. compile_let compile_lazy env vs e
  159. and compile_strict (env : M.t string slot) = function
  160. | Case (sc, alts) ->
  161. let rec go_alts = function
  162. | [] -> []
  163. | Cons ((_, args, exp), rest) ->
  164. let c_arity = length args
  165. let env =
  166. args
  167. |> flip zip [Ls k | with k <- [c_arity - 1, c_arity - 2 .. 0]]
  168. |> M.from_list
  169. |> M.union (offs (c_arity + 1) <$> env)
  170. (c_arity, compile_strict env exp [Slide (c_arity + 1)]) :: go_alts rest
  171. compile_strict env sc # (Casejump (go_alts alts) ::)
  172. | App (App (Ref f, x), y) as e ->
  173. match M.lookup f !prim_scs with
  174. | Some op when is_arith_op op ->
  175. compile_strict env x
  176. # compile_strict (incr <$> env) y
  177. # (op ::)
  178. | _ -> compile_lazy env e # (Eval ::)
  179. | e -> compile_lazy env e # (Eval ::)
  180. and compile_tail (env : M.t string slot) = function
  181. | Ref v ->
  182. match M.lookup v env with
  183. | Some (As i) -> (Push (Arg i) ::)
  184. | Some (Ls i) -> (Push (Local i) ::)
  185. | None -> (Push (Combinator v) ::)
  186. | App (f, x) ->
  187. let f = compile_tail env f
  188. let x = compile_lazy (map incr env) x
  189. f # x # (Mkap ::)
  190. | e -> compile_strict env e
  191. and compile_let cont env vs e =
  192. let n = length vs
  193. let env =
  194. vs
  195. |> map (fun (x, _) -> x)
  196. |> flip zip [Ls x | with x <- [n - 1, n - 2 .. 0]]
  197. |> M.from_list
  198. |> M.union (offs n <$> env)
  199. let defs = zip [1..n] vs
  200. let rec go : list (int * string * expr) -> dlist gm_code = function
  201. | [] -> id
  202. | Cons ((k, (_, exp)), rest) ->
  203. compile_lazy env exp # (Update (n - k) ::) # go rest
  204. (Alloc n ::) # go defs # cont env e # (Slide n ::)
  205. let supercomb (_, args, exp) =
  206. let env = M.from_list (zip args [0..length args])
  207. let k = compile_tail (M.from_list (zip args (As <$> [0..length args]))) exp
  208. k [Update (length env), Pop (length env), Unwind]
  209. let compile_cons =
  210. let rec go i = function
  211. | [] -> []
  212. | Cons (Constr (n, args), rest) ->
  213. let arity = length args
  214. let rec pushargs i =
  215. if i < arity then
  216. Push (Arg (2 * i)) :: pushargs (i + 1)
  217. else
  218. []
  219. Sc (n, arity, pushargs 0 ++ [ Pack (arity, i), Update (2 * arity), Pop (2 * arity), Unwind ])
  220. :: go (i + 1) rest
  221. go 0
  222. let program decs =
  223. let rec globals s = function
  224. | [] -> s
  225. | Cons (Decl (n, _, _), r) -> globals (S.insert n s) r
  226. | Cons (Data (_, _, c), r) ->
  227. globals (foldl (fun s (Constr (n, _)) -> S.insert n s) s c) r
  228. | Cons (Foreign (Fimport {var=n}), r) ->
  229. globals (S.insert n s) r
  230. let (decs, (_, lams, _)) =
  231. run_state (traverse (map eta_contract # lambda_lift_sc) decs)
  232. (0, [], globals S.empty decs)
  233. let define nm k =
  234. let! x = get
  235. if nm `S.member` x then
  236. pure []
  237. else
  238. let! _ = modify (S.insert nm)
  239. k
  240. let go =
  241. flip traverse (lams ++ decs) @@ function
  242. | Decl ((nm, args, _) as sc) ->
  243. define nm (
  244. let code = supercomb sc
  245. [Sc (nm, length args, code)] |> pure
  246. )
  247. | Data (_, _, cs) -> pure (compile_cons cs)
  248. | Foreign (Fimport { cc = Prim, var } as fi) ->
  249. define var (
  250. let (code, h) = cg_prim fi
  251. prim_scs := M.insert var h !prim_scs
  252. pure [code]
  253. )
  254. | Foreign f -> pure [Fd f]
  255. let (out, _) = run_state go S.empty
  256. join out