PageRenderTime 42ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/ellc.h

http://github.com/manuel/ell
C Header | 354 lines | 179 code | 52 blank | 123 comment | 0 complexity | 63f029362675e932862b36ed70f48d63 MD5 | raw file
  1. /***** Executable and Linkable Lisp Compiler *****/
  2. /* Passes:
  3. Lisp text
  4. |
  5. | Parsing
  6. V
  7. Syntax object (including macro calls)
  8. |
  9. | Macroexpansion
  10. V
  11. Syntax object (only core forms)
  12. |
  13. | Normalization (`ellc_norm_stx()')
  14. V
  15. Normal form AST
  16. |
  17. | (Closure) Conversion (`ellc_conv_ast()')
  18. V
  19. Explicit form AST
  20. |
  21. | Emission (`ellc_emit_ast')
  22. V
  23. C text
  24. */
  25. #ifndef ELLC_H
  26. #define ELLC_H
  27. #include "ellrt.h"
  28. struct ellc_id;
  29. struct ellc_ast;
  30. struct ellc_params;
  31. struct ellc_args;
  32. /**** Normal Form ****/
  33. /* After macroexpansion, the S-expression input gets converted to AST
  34. objects in this form. Further passes destructively modify or
  35. augment this information. */
  36. /* Variable reference. */
  37. struct ellc_ast_ref {
  38. struct ellc_id *id;
  39. };
  40. /* Variable update. */
  41. struct ellc_ast_set {
  42. struct ellc_id *id;
  43. struct ellc_ast *val;
  44. };
  45. /* Global variable definition or update. */
  46. struct ellc_ast_def {
  47. struct ellc_id *id;
  48. struct ellc_ast *val;
  49. };
  50. /* Conditional. */
  51. struct ellc_ast_cond {
  52. struct ellc_ast *test;
  53. struct ellc_ast *consequent;
  54. struct ellc_ast *alternative;
  55. };
  56. /* Sequential. */
  57. struct ellc_ast_seq {
  58. list_t *exprs; // ast
  59. };
  60. /* Function application. */
  61. struct ellc_ast_app {
  62. struct ellc_ast *op;
  63. struct ellc_args *args;
  64. };
  65. /* Lambda.
  66. .env: Free variables, populated during closure conversion.
  67. Initially consists of ast_refs, which then get converted to
  68. argument or environment references.
  69. .code_id: Sequence number of lambda in compilation unit, for
  70. linking the closure to its generated C function. Corresponds to
  71. offset of lambda in compilation state's list of lambdas from the
  72. current compilation unit. */
  73. struct ellc_ast_lam {
  74. struct ellc_params *params;
  75. struct ellc_ast *body;
  76. dict_t *env;
  77. unsigned code_id;
  78. };
  79. /* Checks whether identifier names a defined global variable.
  80. Unlike Common Lisp's BOUNDP, does not evaluate its argument. */
  81. struct ellc_ast_defp {
  82. struct ellc_id *id;
  83. };
  84. /* Infinite loop. */
  85. struct ellc_ast_loop {
  86. struct ellc_ast *body;
  87. };
  88. /* Literal symbol, produced by QUOTE. */
  89. struct ellc_ast_lit_sym {
  90. struct ell_obj *sym;
  91. };
  92. /* Literal string. */
  93. struct ellc_ast_lit_str {
  94. struct ell_obj *str;
  95. };
  96. /* Literal number. */
  97. struct ellc_ast_lit_num {
  98. struct ell_obj *num;
  99. };
  100. /* Literal syntax object, produced by QUASISYNTAX. */
  101. struct ellc_ast_lit_stx {
  102. struct ell_obj *stx;
  103. };
  104. /* Context node for maintenance of SRFI 72's improved hygiene
  105. condition. This binds the `__ell_cur_cx' (`ellrt.h') variable for
  106. the body of code. It is introduced for every quasisyntax that is
  107. not considered enclosed in another quasisyntax. */
  108. struct ellc_ast_cx {
  109. struct ellc_ast *body;
  110. };
  111. /* Inline C expressions. */
  112. struct ellc_ast_snip {
  113. struct ellc_ast *body; // seq of strings and other expressions
  114. };
  115. /* Inline C statement. */
  116. struct ellc_ast_stmt {
  117. struct ellc_ast *body; // seq of strings and other expressions
  118. };
  119. /**** Explicit Form ****/
  120. /* During closure conversion, the normal form AST gets destructively
  121. refined to distinguish between references and updates to global
  122. variables, arguments of the current function, or closed-over
  123. environment variables of superordinate functions. Every reference
  124. or update gets transformed to one of the following AST nodes: */
  125. struct ellc_ast_glo_ref {
  126. struct ellc_id *id;
  127. };
  128. struct ellc_ast_glo_set {
  129. struct ellc_id *id;
  130. struct ellc_ast *val;
  131. };
  132. struct ellc_ast_arg_ref {
  133. struct ellc_param *param;
  134. };
  135. struct ellc_ast_arg_set {
  136. struct ellc_param *param;
  137. struct ellc_ast *val;
  138. };
  139. struct ellc_ast_env_ref {
  140. struct ellc_param *param;
  141. };
  142. struct ellc_ast_env_set {
  143. struct ellc_param *param;
  144. struct ellc_ast *val;
  145. };
  146. /**** AST Representation ****/
  147. enum ellc_ast_type {
  148. ELLC_AST_REF = 1, // -> glo_ref | arg_ref | env_ref
  149. ELLC_AST_DEF = 2,
  150. ELLC_AST_SET = 3, // -> glo_set | arg_set | env_set
  151. ELLC_AST_COND = 4,
  152. ELLC_AST_SEQ = 5,
  153. ELLC_AST_APP = 6,
  154. ELLC_AST_LAM = 7,
  155. ELLC_AST_DEFP = 8,
  156. ELLC_AST_LOOP = 9,
  157. ELLC_AST_CX = 10,
  158. ELLC_AST_SNIP = 11,
  159. ELLC_AST_STMT = 12,
  160. ELLC_AST_GLO_REF = 101,
  161. ELLC_AST_GLO_SET = 102,
  162. ELLC_AST_ARG_REF = 103,
  163. ELLC_AST_ARG_SET = 104,
  164. ELLC_AST_ENV_REF = 105,
  165. ELLC_AST_ENV_SET = 106,
  166. ELLC_AST_LIT_SYM = 201,
  167. ELLC_AST_LIT_STR = 202,
  168. ELLC_AST_LIT_STX = 203,
  169. ELLC_AST_LIT_NUM = 204,
  170. };
  171. struct ellc_ast {
  172. enum ellc_ast_type type;
  173. __extension__ union {
  174. struct ellc_ast_ref ref;
  175. struct ellc_ast_def def;
  176. struct ellc_ast_set set;
  177. struct ellc_ast_cond cond;
  178. struct ellc_ast_seq seq;
  179. struct ellc_ast_app app;
  180. struct ellc_ast_lam lam;
  181. struct ellc_ast_defp defp;
  182. struct ellc_ast_loop loop;
  183. struct ellc_ast_cx cx;
  184. struct ellc_ast_snip snip;
  185. struct ellc_ast_stmt stmt;
  186. struct ellc_ast_glo_ref glo_ref;
  187. struct ellc_ast_glo_set glo_set;
  188. struct ellc_ast_arg_ref arg_ref;
  189. struct ellc_ast_arg_set arg_set;
  190. struct ellc_ast_env_ref env_ref;
  191. struct ellc_ast_env_set env_set;
  192. struct ellc_ast_lit_sym lit_sym;
  193. struct ellc_ast_lit_str lit_str;
  194. struct ellc_ast_lit_num lit_num;
  195. struct ellc_ast_lit_stx lit_stx;
  196. };
  197. };
  198. /* A note on namespaces, i.e. Lisp-N. The language is a Lisp-2 on the
  199. surface, but internally, all the compiler cares about is
  200. identifiers (`struct ellc_id'). Identifiers carry a namespace
  201. number (`enum ellc_ns'), which means that in the future we'll be
  202. able to add an unbounded number of additional namespaces. Just
  203. kidding.
  204. Note that (syntax) symbols themselves do *not* carry a namespace.
  205. That's because the namespace of a symbol is determined by its
  206. position in the syntax. For example, the first element of a
  207. compound form is always put into the function namespace (Nr. 2).
  208. Syntax symbols are converted to identifiers during normalization. */
  209. enum ellc_ns {
  210. ELLC_NS_VAR = 1,
  211. ELLC_NS_FUN = 2,
  212. };
  213. /* Variable identifier. */
  214. struct ellc_id {
  215. struct ell_obj *sym; // name symbol
  216. enum ellc_ns ns; // namespace
  217. struct ell_cx *cx; // hygiene context
  218. };
  219. /* Parameters of a function. */
  220. struct ellc_params {
  221. list_t *req; // param
  222. list_t *opt; // param
  223. list_t *key; // param
  224. struct ellc_param *rest; // maybe NULL
  225. struct ellc_param *all_keys; // maybe NULL
  226. };
  227. /* A single parameter. Optional and keyword parameters may have an
  228. initialization form that's used when the parameter is not supplied.
  229. During closure conversion, it is determined whether the parameter
  230. is potentially updated (mutable), and whether it is referenced or
  231. updated in subordinate lambdas (closed). Parameters that are both
  232. mutable and closed are put into heap allocated boxes. */
  233. struct ellc_param {
  234. struct ellc_id *id;
  235. struct ellc_ast *init; // maybe NULL
  236. bool mutable;
  237. bool closed;
  238. };
  239. /* The arguments to a function call. */
  240. struct ellc_args {
  241. list_t pos; // ast
  242. dict_t key; // sym -> ast
  243. };
  244. /**** Compiler State ****/
  245. /* Compiler state, as opposed to compilation state, is maintained
  246. across unit compilations. Compiler state comprises the following
  247. variables: */
  248. /* Table of macros. Maps macro symbols to expander functions, that
  249. take a syntax object, and return a syntax object. To have macro
  250. definitions available across REPL uses, this table is maintained in
  251. the compiler process across compilation units. In the ordinary,
  252. file compilation use case of the compiler, this makes no difference
  253. as the compiler process is torn down after every unit. In
  254. interactive REPL mode however, this design is crucial: the REPL
  255. process spawns a new process for the compiler. Every user input is
  256. sent interactively to the compiler process, and the resulting
  257. shared object is again loaded in the REPL process. But! - macro
  258. expanders are not evaluated in the REPL process, they only live in
  259. the compiler process. */
  260. static dict_t ellc_mac_tab; // sym -> clo
  261. /**** Compilation State ****/
  262. /* Compilation state, as opposed to compiler state, is reset between
  263. unit compilations. */
  264. /* Lexical contour, helper object used during closure conversion to
  265. mirror the runtime lexical environment of lambdas. */
  266. struct ellc_contour {
  267. struct ellc_ast_lam *lam;
  268. struct ellc_contour *up; // maybe NULL
  269. };
  270. /* Compilation state, maintained during the compilation of a unit. */
  271. struct ellc_st {
  272. /*** Static data extracted from unit by passes. ***/
  273. /* Global variables defined in the compilation unit. Populated
  274. during normalization. */
  275. list_t *defined_globals; // id
  276. /* Globals variables referenced or updated in the compilation
  277. unit. Populated during closure conversion. */
  278. list_t *globals; // id
  279. /* Macro definitions in the compilation unit. Populated during
  280. normalization. */
  281. dict_t *defined_macros; // sym -> stx
  282. /* Lambdas in the compilation unit. Populated during closure
  283. conversion. */
  284. list_t *lambdas; // lam
  285. /* Top-level C statements. */
  286. list_t *stmts; // ast
  287. /*** Dynamic data used during passes. ***/
  288. /* Lexical contour during normalization and closure conversion. */
  289. struct ellc_contour *bottom_contour; // maybe NULL
  290. /* Whether we are inside a quasisyntax (during emission), for
  291. hygiene condition. */
  292. bool in_quasisyntax;
  293. /* The output file for C code during emission. */
  294. FILE *f;
  295. };
  296. /**** API ****/
  297. int
  298. ellc_compile_file(char *infile, char *faslfile, char *cfaslfile);
  299. #endif