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.

185 lines
5.4 KiB

  1. open import "prelude.ml"
  2. module Src = import "../lang.ml"
  3. open Src
  4. module Map = import "data/map.ml"
  5. module Set = import "data/set.ml"
  6. module Stg = import "./stg.ml"
  7. let spine f =
  8. let rec spine = function
  9. | App (f, x) ->
  10. let (f, args) = spine f
  11. (f, x :: args)
  12. | e -> (e, [])
  13. let (f, args) = spine f
  14. (f, reverse args)
  15. let rec napp f = function
  16. | [] -> f
  17. | Cons (x, xs) -> napp (App (f, x)) xs
  18. let get_con_arities prog =
  19. let go_con m (Constr (name, tys)) = M.insert name (length tys) m
  20. let go m = function
  21. | Data (_, _, cons) -> foldl go_con m cons
  22. | _ -> m
  23. foldl go M.empty prog
  24. let gensym =
  25. let counter = ref 0
  26. fun () ->
  27. counter := !counter + 1
  28. "_s" ^ show !counter
  29. let rec add_n_args da exp =
  30. if da <= 0 then
  31. exp
  32. else
  33. let var = gensym ()
  34. Lam (var, App (add_n_args (da - 1) exp, Ref var))
  35. let rec eta_expand_cons arities =
  36. let rec go = function
  37. | Case (exp, alts) -> Case (go exp, map (second (second go)) alts)
  38. | Lam (var, alts) -> Lam (var, go alts)
  39. | If (a, b, c) -> If (go a, go b, go c)
  40. | Let (decs, body) -> Let (map (second go) decs, go body)
  41. | exp ->
  42. match spine exp with
  43. | Ref func, args ->
  44. let arg_len = length args
  45. match Map.lookup func arities with
  46. | Some arity when arity > arg_len -> add_n_args (arity - arg_len) (napp (Ref func) args)
  47. | _ -> exp
  48. | _, _ -> error @@ "What?"
  49. go
  50. let build_stg_app func = function
  51. | [] -> Stg.Atom func
  52. | args -> Stg.(App (func, args))
  53. let mk_lambda_form name exp =
  54. let free_vars = Stg.stg_fv exp
  55. { name, free_vars, update = Stg.Updatable, args = [], body = exp }
  56. let mk_function name args exp =
  57. let free_vars = foldl (flip Set.delete) (Stg.stg_fv exp) args
  58. { name, free_vars, update = Stg.Function, args, body = exp }
  59. let rec unlambda = function
  60. | Lam (var, body) ->
  61. let (args, body) = unlambda body
  62. (var :: args, body)
  63. | e -> ([], e)
  64. let rec lower_spine (func, args) kont =
  65. lower_atom func @@ fun func ->
  66. let rec go kont lowered = function
  67. | [] -> kont (build_stg_app func (reverse lowered))
  68. | Cons (Ref e, args) ->
  69. go kont (Stg.Var e :: lowered) args
  70. | Cons (Lit i, args) ->
  71. go kont (Stg.Int i :: lowered) args
  72. | Cons (arg, args) ->
  73. lower_atom arg @@ fun arg ->
  74. go kont (arg :: lowered) args
  75. go kont [] args
  76. and lower exp kont =
  77. match spine exp with
  78. | exp, [] ->
  79. match exp with
  80. | App _ -> error @@ "Impossible lower App with empty spine"
  81. (* STG atoms *)
  82. | Ref e -> kont Stg.(Atom (Var e))
  83. | Lit e -> kont Stg.(Con (0, 1, [Int e]))
  84. (* Lambdas need to be bound as lambda-forms *)
  85. | Lam _ as lam ->
  86. let name = gensym ()
  87. let (args, body) = unlambda lam
  88. let body = lower_body body
  89. Stg.Let ([mk_function name args body], kont Stg.(Atom (Var name)))
  90. | If (cond, th, el) ->
  91. lower cond @@ fun cond ->
  92. lower th @@ fun th ->
  93. lower el @@ fun el ->
  94. Stg.( Case (cond, "binder" ^ gensym(), [(Con_pat (0, []), th), (Default, el)]) )
  95. |> kont
  96. | Let (bindings, body) ->
  97. lower_binds bindings @@ fun lambda_forms ->
  98. Stg.Let (lambda_forms, lower body kont)
  99. | Case (scrut, arms) ->
  100. lower scrut @@ fun scrut ->
  101. lower_arms arms @@ fun arms ->
  102. Stg.Case (scrut, "binder" ^ gensym(), arms) |> kont
  103. | e -> lower_spine e kont
  104. and lower_atom exp kont =
  105. lower exp @@ function
  106. | Stg.Atom at -> kont at
  107. | e ->
  108. let name = gensym ()
  109. Stg.(Let ([mk_lambda_form name e], kont (Var name)))
  110. and lower_binds bindings kont =
  111. let rec go acc = function
  112. | [] -> kont (reverse acc)
  113. | Cons ((name, bind), rest) ->
  114. go (lower_rhs name bind :: acc) rest
  115. go [] bindings
  116. and lower_arms arms kont =
  117. let rec go i acc = function
  118. | [] -> kont (reverse acc)
  119. | Cons ((_, args, exp), rest) ->
  120. let body = lower_body exp
  121. go (i + 1) ((Stg.(Con_pat (i, args)), body) :: acc) rest
  122. go 0 [] arms
  123. and lower_rhs name exp =
  124. match exp with
  125. | Lam _ as lam ->
  126. let (args, body) = unlambda lam
  127. let body = lower_body body
  128. mk_function name args body
  129. | _ ->
  130. let body = lower_body exp
  131. mk_lambda_form name body
  132. and lower_body exp = lower exp (fun x -> x)
  133. let mk_stg_prim name prim =
  134. let binary_prim x =
  135. let open Stg
  136. let body =
  137. Case (Atom (Var "x"), "x",
  138. [( Default, Case (Atom (Var "y"), "y",
  139. [(Default, Prim (x, [Var "x", Var "y"]))]))])
  140. Fun { name, args = ["x", "y"], body, is_con = None }
  141. match prim with
  142. | "add" -> binary_prim Stg.Add
  143. | "sub" -> binary_prim Stg.Sub
  144. | "mul" -> binary_prim Stg.Mul
  145. | "div" -> binary_prim Stg.Div
  146. | "equ" -> binary_prim Stg.Equ
  147. | e -> error @@ "No such primitive " ^ e
  148. let lower_dec = function
  149. | Decl (name, manifest_args, expr) ->
  150. let (args, body) = unlambda expr
  151. let args = manifest_args ++ args
  152. let body = lower_body body
  153. [ Stg.Fun { name, args, body, is_con = None } ]
  154. | Data (_, _, cons) ->
  155. let mk_stg_con (Constr (name, args), i) =
  156. let args = [ gensym () | with _ <- args ]
  157. Stg.Fun { name, args, body = build_stg_app (Stg.Var name) (Stg.Var <$> args), is_con = Some i }
  158. [ mk_stg_con c | with c <- zip cons [0 .. length cons - 1] ]
  159. | Foreign (Fimport { cc = Prim, fent = prim, var = name }) ->
  160. [ mk_stg_prim name prim ]
  161. | Foreign (Fimport { cc = Lua, fent, var, ftype }) ->
  162. [ Stg.Ffi_def { name = var, fent, arity = arity ftype }]