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.

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