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.

116 lines
3.7 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
  1. include import "./compile.ml"
  2. module Strings = import "./lib/strings.ml"
  3. open import "prelude.ml"
  4. open import "lua/io.ml"
  5. open import "./lang.ml"
  6. let resolve_addr = function
  7. | Combinator n -> n ^ "_combinator"
  8. | Arg i -> "stack[sp - " ^ show (i + 1) ^ "][3]"
  9. | Int i -> show i
  10. let rec gm2lua = function
  11. | Push addr ->
  12. " stack[sp + 1] = " ^ resolve_addr addr ^ "; sp = sp + 1"
  13. | Pop n ->
  14. " sp = sp - " ^ show n
  15. | Update n ->
  16. " stack[sp - " ^ show (n + 1) ^ "] = { I, stack[sp] }; sp = sp - 1"
  17. | Mkap ->
  18. " stack[sp - 1] = { A, stack[sp - 1], stack[sp] }; sp = sp - 1"
  19. | Unwind ->
  20. " return unwind(stack, sp)"
  21. | Eval -> " stack[sp] = eval(stack[sp])"
  22. | Add -> " stack[sp - 1] = stack[sp - 1] + stack[sp]; sp = sp - 1"
  23. | Sub -> " stack[sp - 1] = stack[sp - 1] - stack[sp]; sp = sp - 1"
  24. | Div -> " stack[sp - 1] = stack[sp - 1] / stack[sp]; sp = sp - 1"
  25. | Mul -> " stack[sp - 1] = stack[sp - 1] * stack[sp]; sp = sp - 1"
  26. | Iszero (yes, no) ->
  27. " if stack[sp] == 0 then\n"
  28. ^ foldl (fun x i -> x ^ " " ^ gm2lua i) "" yes ^ "\n"
  29. ^ " else\n"
  30. ^ foldl (fun x i -> x ^ " " ^ gm2lua i) "" no ^ "\n"
  31. ^ " end"
  32. let compute_local_set xs =
  33. let rec go i (s : S.t string) = function
  34. | Cons (Fd (Fimport {var}), xs) ->
  35. if i >= 100 then
  36. s
  37. else
  38. go (i + 2) (S.insert (var ^ "_wrapper") (S.insert (var ^ "_combinator") s)) xs
  39. | Cons (Sc (name, _), xs) ->
  40. if i >= 100 then
  41. s
  42. else
  43. go (i + 2) (S.insert name (S.insert (name ^ "_combinator") s)) xs
  44. | Nil -> s
  45. go 1 S.empty xs
  46. let sc2lua (name, arity, body) =
  47. let body =
  48. body
  49. |> foldl (fun x s -> x ^ gm2lua s ^ ";\n") (name ^ " = function(stack, sp)\n")
  50. |> (^ "end")
  51. let dec =
  52. name ^ "_combinator = { F, " ^ name ^ ", " ^ show arity ^ ", " ^ show name ^ " };"
  53. body ^ "\n" ^ dec
  54. let foreign2lua (Fimport { cc, fent = fspec, var, ftype }) =
  55. let (file, fspec) =
  56. match Strings.split_on " " fspec with
  57. | [file, func] -> (Some file, func)
  58. | [func] -> (None, func)
  59. | _ -> error @@ "Foreign spec too big: " ^ fspec
  60. match cc with
  61. | Prim -> error "primitive definitions are in Gmcode"
  62. | Lua ->
  63. let arity = arity ftype
  64. let args = map (fun i -> ("a" ^ show i, i)) [1..arity]
  65. let fcall =
  66. if arity == 0 then
  67. fspec
  68. else
  69. let Cons ((a, _), args) = args
  70. fspec ^ "(" ^ foldl (fun a (i, _) -> a ^ ", " ^ i) a args ^ ")"
  71. let wrapper =
  72. "local function " ^ var ^ "_wrapper(stack, sp)\n"
  73. ^ foldl (fun x (a, i) -> x ^ " local " ^ a ^ " = stack[sp - " ^ show i ^ "][3];\n") "" args
  74. ^ " stack[sp - " ^ show arity ^ "] = " ^ fcall ^ "\n"
  75. ^ " return unwind(stack, sp - " ^ show arity ^ ")\nend"
  76. let dec =
  77. var ^ "_combinator = { F, " ^ var ^ "_wrapper, " ^ show arity ^ ", '" ^ fspec ^ "' };"
  78. let contents =
  79. match file with
  80. | Some path ->
  81. let f = open_for_reading path
  82. let x = read_all f
  83. close_file f
  84. match x with
  85. | Some s -> "--- " ^ path ^ "\n" ^ s ^ "\n"
  86. | None -> ""
  87. | None -> ""
  88. contents ^ wrapper ^ "\n" ^ dec
  89. let codegen = function
  90. | Sc t -> sc2lua t
  91. | Fd i -> foreign2lua i
  92. let preamble =
  93. let f = open_for_reading "preamble.lua"
  94. let x = read_all f
  95. close_file f
  96. match x with
  97. | Some s -> s
  98. | None -> error "no preamble.lua"
  99. let assm_program decs =
  100. match decs with
  101. | [] -> error "empty program"
  102. | _ ->
  103. let Cons (local1, locals) =
  104. compute_local_set decs |> S.members
  105. let local_decs =
  106. foldl (fun x v -> x ^ ", " ^ v) ("local " ^ local1) locals
  107. let body = foldl (fun x s -> x ^ codegen s ^ "\n") "" decs
  108. preamble ^ local_decs ^ "\n" ^ body ^ "unwind({{ A, main_combinator, 123 }}, 1)"