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.

105 lines
2.7 KiB

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. | Arg of int
  9. type gm_code =
  10. | Push of addr
  11. | Update of int
  12. | Pop of int
  13. | Unwind
  14. | Mkap
  15. instance show gm_code begin
  16. let show = function
  17. | Mkap -> "Mkap"
  18. | Unwind -> "Unwind"
  19. | Push (Combinator k) -> "Push " ^ k
  20. | Push (Arg i) -> "Arg " ^ show i
  21. | Update n -> "Update " ^ show n
  22. | Pop n -> "Pop " ^ show n
  23. end
  24. let rec lambda_lift = function
  25. | Ref v -> pure (Ref v)
  26. | App (f, x) -> (| app (lambda_lift f) (lambda_lift x) |)
  27. | Lam (v, x) ->
  28. let! body = lambda_lift x
  29. let! (i, defs, known_sc) = get
  30. let vars =
  31. x |> free_vars
  32. |> S.delete v
  33. |> flip S.difference known_sc
  34. |> S.members
  35. let def = ("Lam" ^ show i, vars ++ [v], body)
  36. let app = foldl (fun f -> app f # Ref) (Ref ("Lam" ^ show i)) vars
  37. put (i + 1, Decl def :: defs, known_sc)
  38. |> map (const app)
  39. | Case (sc, alts) ->
  40. alts
  41. |> map (fun (_, x) -> x)
  42. |> foldl app sc
  43. |> lambda_lift
  44. let rec eta_contract = function
  45. | Decl (n, a, e) as dec ->
  46. match a, e with
  47. | [], _ -> dec
  48. | xs, App (f, Ref v) ->
  49. if v == last xs && not (S.member v (free_vars f)) then
  50. eta_contract (Decl (n, init a, f))
  51. else
  52. dec
  53. | _, _ -> dec
  54. | Data c -> Data c
  55. let rec lambda_lift_sc = function
  56. | Decl (n, a, e) ->
  57. match e with
  58. | Lam (v, e) -> lambda_lift_sc (Decl (n, a ++ [v], e))
  59. | _ ->
  60. let! e = lambda_lift e
  61. let! _ = modify (fun (a, b, s) -> (a, b, S.insert n s))
  62. pure (Decl (n, a, e))
  63. | Data c -> Data c |> pure
  64. type dlist 'a <- list 'a -> list 'a
  65. let rec compile (env : M.t string int) = function
  66. | Ref v ->
  67. match M.lookup v env with
  68. | Some i -> (Push (Arg i) ::)
  69. | None -> (Push (Combinator v) ::)
  70. | App (f, x) ->
  71. let f = compile env f
  72. let x = compile (map (1 +) env) x
  73. f # x # (Mkap ::)
  74. | Lam _ -> error "Can not compile lambda expression, did you forget to lift?"
  75. | Case _ -> error "Can not compile case expression, did you forget to lift?"
  76. let supercomb (_, args, exp) =
  77. let env = M.from_list (zip args [0..length args])
  78. let k = compile (M.from_list (zip args [0..length args])) exp
  79. k [Update (length env), Pop (length env), Unwind]
  80. let known_scs = S.from_list [ "getchar", "putchar" ]
  81. let program decs =
  82. let (decs, (_, lams, _)) =
  83. run_state (traverse (lambda_lift_sc # eta_contract) decs) (0, [], known_scs)
  84. flip map (lams ++ decs) @@ function
  85. | Decl ((nm, args, _) as sc) ->
  86. let code = supercomb sc
  87. (nm, length args, code)
  88. | Data _ -> error "data declaration in compiler"