mes_macro.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /* -*-comment-start: "//";comment-end:""-*-
  2. * GNU Mes --- Maxwell Equations of Software
  3. * Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  4. * Copyright © 2019 Jeremiah Orians
  5. *
  6. * This file is part of GNU Mes.
  7. *
  8. * GNU Mes is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 3 of the License, or (at
  11. * your option) any later version.
  12. *
  13. * GNU Mes is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include "mes.h"
  22. /* Imported functions */
  23. struct cell* macro_progn(struct cell* exps, struct cell* env);
  24. struct cell* make_macro(struct cell* a, struct cell* b, struct cell* env);
  25. struct cell* make_proc(struct cell* a, struct cell* b, struct cell* env);
  26. struct cell* pop_cell();
  27. struct cell* reverse_list(struct cell* head);
  28. void push_cell(struct cell* a);
  29. struct cell* cell_invoke_function(struct cell* cell, struct cell* vals);
  30. void apply(struct cell* proc, struct cell* vals);
  31. struct cell* macro_extend_env(struct cell* sym, struct cell* val, struct cell* env)
  32. {
  33. env->cdr = make_cons(env->car, env->cdr);
  34. env->car = make_cons(sym, val);
  35. return nil;
  36. }
  37. struct cell* define_macro(struct cell* exp, struct cell* env)
  38. {
  39. require(nil != exp->cdr, "source expression failed to match any pattern in form (define-macro)\n");
  40. if(CONS == exp->cdr->car->type)
  41. {
  42. struct cell* fun = exp->cdr->cdr;
  43. struct cell* arguments = exp->cdr->car->cdr;
  44. struct cell* name = exp->cdr->car->car;
  45. exp->cdr = make_cons(name, make_cons(make_cons(s_macro, make_cons(arguments, fun)), nil));
  46. }
  47. return(macro_extend_env(exp->cdr->car, exp->cdr->cdr->car, env));
  48. }
  49. struct cell* macro_apply(struct cell* exps, struct cell* vals);
  50. struct cell* macro_eval(struct cell* exps, struct cell* env);
  51. struct cell* expand_quasiquote(struct cell* exp, struct cell* env)
  52. {
  53. push_cell(R0);
  54. push_cell(R1);
  55. R0 = exp;
  56. R1 = env;
  57. /* Protect the s-expression during the entire evaluation */
  58. push_cell(R0);
  59. /* R2 is the s-expression we are quasiquoting */
  60. push_cell(R2);
  61. /* R3 is the resulting s-expression, built backwards and reversed at the end */
  62. push_cell(R3);
  63. /* R4 is just a temp holder of each unquote */
  64. push_cell(R4);
  65. /* (quasiquote (...)) */
  66. require (NULL != R0, "quasiquote R0 is NULL\n");
  67. require(NULL != R0->cdr, "quasiquote R0->cdr is NULL\n");
  68. R2 = R0->cdr->car;
  69. R3 = NULL;
  70. while(nil != R2)
  71. {
  72. require(NULL != R2, "Null in quasiquote expression reached\n");
  73. require(CONS == R2->type, "Not a cons list in quasiquote reached\n");
  74. R4 = R2->car;
  75. if(CONS == R2->car->type)
  76. {
  77. if(unquote == R2->car->car)
  78. {
  79. R0 = R2->car->cdr->car;
  80. R4 = NULL; /* So that assoc doesn't mistake this for a lambda */
  81. push_cell(R3);
  82. push_cell(R2);
  83. macro_eval(R0, R1);
  84. R2 = pop_cell();
  85. R3 = pop_cell();
  86. R4 = R1;
  87. }
  88. if(unquote_splicing == R2->car->car)
  89. {
  90. R0 = R2->car->cdr->car;
  91. push_cell(R4);
  92. push_cell(R3);
  93. push_cell(R2);
  94. R4 = NULL; /* So that assoc doesn't mistake this for a lambda */
  95. macro_eval(R0, R1);
  96. R2 = pop_cell();
  97. R3 = pop_cell();
  98. R4 = pop_cell();
  99. while((NULL != R1) && (nil != R1))
  100. {
  101. /* Unsure if correct behavior is to revert to unquote behavior (what guile does) */
  102. /* Or restrict to just proper lists as the spec (r7rs) requires */
  103. /* eg. `(foo bar ,@(+ 4 5)) */
  104. require(CONS == R1->type, "unquote-splicing requires argument of type <proper list>\n");
  105. R3 = make_cons(R1->car, R3);
  106. /* Simply convert require to if and the above */
  107. /* else R3 = make_cons(R1, R3); */
  108. R1 = R1->cdr;
  109. }
  110. /* we really don't want to add that cons after what we just did */
  111. goto macro_restart_quasiquote;
  112. }
  113. }
  114. R3 = make_cons(R4, R3);
  115. macro_restart_quasiquote:
  116. /* keep walking down the list of s-expressions */
  117. R2 = R2->cdr;
  118. }
  119. /* We created the list backwards because it was simpler, now we have to put it into correct order */
  120. R2 = R3;
  121. R3 = reverse_list(R3);
  122. require(NULL != R2, "Impossible quasiquote processed?\n");
  123. R2->cdr = nil;
  124. R1 = R3;
  125. /* We are finally done with the s-expression, we don't need it back */
  126. R4 = pop_cell();
  127. R3 = pop_cell();
  128. R2 = pop_cell();
  129. pop_cell();
  130. exp = R0;
  131. R1 = pop_cell();
  132. R0 = pop_cell();
  133. return exp;
  134. }
  135. struct cell* macro_list(struct cell* exps, struct cell* env)
  136. {
  137. if(exps == nil) return nil;
  138. struct cell* i = macro_eval(exps->car, env);
  139. struct cell* j = macro_list(exps->cdr, env);
  140. return make_cons(i, j);
  141. }
  142. struct cell* expand_if(struct cell* exp, struct cell* env)
  143. {
  144. R0 = macro_eval(exp->cdr->car, env);
  145. if(R0 != cell_f)
  146. {
  147. R0 = macro_eval(exp->cdr->cdr->car, env);
  148. return R0;
  149. }
  150. if(nil == exp->cdr->cdr->cdr) return cell_unspecified;
  151. R0 = macro_eval(exp->cdr->cdr->cdr->car, env);
  152. return R0;
  153. }
  154. struct cell* expand_cond(struct cell* exp, struct cell* env)
  155. {
  156. push_cell(R0);
  157. push_cell(R1);
  158. /* Get past the COND */
  159. R0 = exp->cdr;
  160. /* Provide a way to flag no fields in cond */
  161. R1 = NULL;
  162. /* Loop until end of list of s-expressions */
  163. while(nil != R0)
  164. {
  165. /* Protect remaining list of s-expressions from garbage collection */
  166. push_cell(R0);
  167. /* Evaluate the conditional */
  168. R0 = R0->car->car;
  169. macro_eval(R0, env);
  170. R0 = pop_cell();
  171. /* Execute if not false because that is what guile does (believe everything not #f is true) */
  172. if(cell_f != R1)
  173. {
  174. R0 = make_cons(s_begin, R0->car->cdr);
  175. macro_eval(R0, env);
  176. return R0;
  177. }
  178. /* Iterate to the next in the list of s-expressions */
  179. R0 = R0->cdr;
  180. /* The default return in guile if it hits nil */
  181. R1 = cell_unspecified;
  182. }
  183. require(NULL != R1, "a naked cond is not supported\n");
  184. exp = R0;
  185. R1 = pop_cell();
  186. R0 = pop_cell();
  187. return exp;
  188. }
  189. struct cell* expand_let(struct cell* exp, struct cell* env)
  190. {
  191. /* Clean up locals after let completes */
  192. push_cell(env);
  193. push_cell(R0);
  194. R0 = exp;
  195. require(NULL != R0->cdr, "expand_let R0->cdr is NULL\n");
  196. /* Protect the s-expression from garbage collection */
  197. push_cell(R0->cdr->cdr);
  198. /* Deal with the (let ((pieces)) ..) */
  199. for(R0 = R0->cdr->car; R0 != nil; R0 = R0->cdr)
  200. {
  201. push_cell(R0);
  202. require (NULL != R0->car, "expand_let R0->car is NULL in loop\n");
  203. R0 = R0->car->cdr->car;
  204. macro_eval(R0, R1);
  205. R0 = pop_cell();
  206. if(NULL != R4) R4 = make_cons(make_cons(R0->car->car, R1), R4);
  207. else g_env = make_cons(make_cons(R0->car->car, R1), g_env);
  208. }
  209. /* Lets execute the pieces of the of (let ((..)) pieces) */
  210. R0 = pop_cell();
  211. R0 = make_cons(s_begin, R0);
  212. macro_eval(R0, R1);
  213. /* Actual clean up */
  214. exp = R0;
  215. R0 = pop_cell();
  216. g_env = pop_cell();
  217. return exp;
  218. }
  219. struct cell* expand_define(struct cell* exp, struct cell* env)
  220. {
  221. push_cell(R0);
  222. push_cell(R1);
  223. R0 = exp;
  224. R1 = env;
  225. require(nil != R0->cdr, "naked (define) not supported\n");
  226. /* To support (define (foo a b .. N) (s-expression)) form */
  227. if(CONS == R0->cdr->car->type)
  228. {
  229. /* R2 is to get the actual function*/
  230. push_cell(R2);
  231. /* R3 is to get the function arguments */
  232. push_cell(R3);
  233. /* R4 is to get the function's name */
  234. push_cell(R4);
  235. R2 = R0->cdr->cdr;
  236. R3 = R0->cdr->car->cdr;
  237. R4 = R0->cdr->car->car;
  238. /* by converting it into (define foo (lambda (a b .. N) (s-expression))) form */
  239. R0->cdr = make_cons(R4, make_cons(make_cons(s_lambda, make_cons(R3, R2)), nil));
  240. R4 = pop_cell();
  241. R3 = pop_cell();
  242. R2 = pop_cell();
  243. }
  244. /* Protect the name from garbage collection */
  245. push_cell(R0->cdr->car);
  246. /* Evaluate the s-expression which the name is supposed to equal */
  247. require(nil != R0->cdr->cdr, "naked (define foo) not supported\n");
  248. R0 = R0->cdr->cdr->car;
  249. push_cell(R4);
  250. push_cell(R3);
  251. push_cell(R2);
  252. macro_eval(R0, R1);
  253. R2 = pop_cell();
  254. R3 = pop_cell();
  255. R4 = pop_cell();
  256. R0 = pop_cell();
  257. /* If we define a LAMBDA/MACRO, we need to extend its environment otherwise it can not call itself recursively */
  258. if((LAMBDA == R1->type) || (MACRO == R1->type))
  259. {
  260. R1->env = make_cons(make_cons(R0, R1), R1->env);
  261. }
  262. /* We now need to extend the environment with our new name */
  263. g_env = make_cons(make_cons(R0, R1), g_env);
  264. R1 = cell_unspecified;
  265. exp = R0;
  266. R1 = pop_cell();
  267. R0 = pop_cell();
  268. return R0;
  269. }
  270. struct cell* expand_cons(struct cell* exp, struct cell* env)
  271. {
  272. if(exp->car == s_if) return expand_if(exp, env);
  273. if(exp->car == s_cond) return expand_cond(exp->cdr, env);
  274. if(exp->car == s_lambda) return make_proc(exp->cdr->car, exp->cdr->cdr, env);
  275. if(exp->car == quote) return exp->cdr->car;
  276. if(exp->car == s_macro) return make_macro(exp->cdr->car, exp->cdr->cdr, env);
  277. if(exp->car == s_define) return expand_define(exp, env);
  278. if(exp->car == s_let) return expand_let(exp, env);
  279. if(exp->car == quasiquote) return expand_quasiquote(exp->cdr->car, env);
  280. R0 = macro_eval(exp->car, env);
  281. push_cell(R0);
  282. R1 = macro_list(exp->cdr, env);
  283. R0 = pop_cell();
  284. return macro_apply(R0, R1);
  285. }
  286. struct cell* macro_assoc(struct cell* key, struct cell* alist)
  287. {
  288. if(nil == alist) return nil;
  289. struct cell* i;
  290. for(i = alist; nil != i; i = i->cdr)
  291. {
  292. if(i->car->car->string == key->string) return i->car;
  293. }
  294. return nil;
  295. }
  296. struct cell* macro_eval(struct cell* exps, struct cell* env)
  297. {
  298. if(CONS == exps->type) return expand_cons(exps, env);
  299. if(SYM == exps->type)
  300. {
  301. struct cell* tmp = macro_assoc(exps, env);
  302. if(nil == tmp) return exps;
  303. return tmp->cdr;
  304. }
  305. return exps;
  306. }
  307. struct cell* macro_progn(struct cell* exps, struct cell* env)
  308. {
  309. if(CONS != exps->type) return exps;
  310. R0 = exps;
  311. macro_progn_reset:
  312. if(R0 == nil) return R1;
  313. push_cell(R0->cdr);
  314. R1 = macro_eval(R0->car, env);
  315. R0 = pop_cell();
  316. goto macro_progn_reset;
  317. }
  318. struct cell* macro_extend(struct cell* env, struct cell* syms, struct cell* vals)
  319. {
  320. require(NULL != vals, "lambda: bad lambda in form\n");
  321. if(nil == syms)
  322. {
  323. return env;
  324. }
  325. if(cell_dot == syms->car)
  326. {
  327. return make_cons(make_cons(syms->cdr->car, vals), env);
  328. }
  329. return macro_extend(make_cons(make_cons(syms->car, vals->car), env), syms->cdr, vals->cdr);
  330. }
  331. struct cell* macro_apply(struct cell* proc, struct cell* vals)
  332. {
  333. struct cell* temp;
  334. if(proc->type == PRIMOP)
  335. {
  336. temp = cell_invoke_function(proc, vals);
  337. }
  338. else if(proc->type == LAMBDA)
  339. {
  340. push_cell(R0);
  341. push_cell(R1);
  342. apply(proc, vals);
  343. temp = R1;
  344. R1 = pop_cell();
  345. R0 = pop_cell();
  346. }
  347. else if(proc->type == MACRO)
  348. {
  349. struct cell* env = make_cons(proc->env->car, proc->env->cdr);
  350. temp = macro_progn(proc->cdr, macro_extend(env, proc->car, vals));
  351. }
  352. else
  353. {
  354. temp = macro_eval(proc, g_env);
  355. }
  356. return temp;
  357. }
  358. struct cell* expand_macros(struct cell* exp)
  359. {
  360. R0 = exp;
  361. struct cell* hold;
  362. if(NULL == R0) return nil;
  363. if(CONS != R0->type) return exp;
  364. else if(R0->car == s_define_macro)
  365. {
  366. define_macro(R0, g_env);
  367. return cell_unspecified;
  368. }
  369. push_cell(R0);
  370. hold = expand_macros(R0->car);
  371. R0 = pop_cell(R0);
  372. R0->car = hold;
  373. hold = macro_assoc(R0->car, g_env);
  374. if(CONS == hold->type)
  375. {
  376. if(s_macro == hold->cdr->car)
  377. {
  378. R0 = macro_apply(make_macro(hold->cdr->cdr->car, hold->cdr->cdr->cdr, g_env), R0->cdr);
  379. return expand_macros(R0);
  380. }
  381. }
  382. push_cell(R0);
  383. hold = expand_macros(R0->cdr);
  384. R0 = pop_cell(R0);
  385. R0->cdr = hold;
  386. return R0;
  387. }