lisp.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*bin/echo '#-*- indent-tabs-mode:nil;js-indent-level:2;coding:utf-8 -*-
  2. SectorLISP v2.o (ISC License)
  3. Copyright 2021 Justine Tunney
  4. This file implements SectorLISP as a C / JavaScript polyglot and
  5. includes friendly branch features such as the undefined behavior
  6. exceptions handlers, optimized interning, and global definitions
  7. (aset standard-display-table #x2029 [?¶]) ;; emacs protip '>/dev/null
  8. curl -so bestline.c -z bestline.c https://justine.lol/sectorlisp2/bestline.c
  9. curl -so bestline.h -z bestline.h https://justine.lol/sectorlisp2/bestline.h
  10. [ lisp.js -nt lisp ] && cc -w -xc lisp.js bestline.c -o lisp
  11. exec ./lisp "$@"
  12. exit
  13. */
  14. //
`
  15. #include "bestline.h"
  16. #ifndef __COSMOPOLITAN__
  17. #include <stdio.h>
  18. #include <locale.h>
  19. #include <setjmp.h>
  20. #endif
  21. #define var int
  22. #define function
  23. #define Null 0100000
  24. var M[Null * 2];
  25. jmp_buf undefined;
  26. //`
  27. var cx, dx, kT, kEq, kCar, kCdr, kCond, kAtom, kCons, kQuote, kDefine;
  28. function Set(i, x) {
  29. M[Null + i] = x;
  30. }
  31. function Get(i) {
  32. return M[Null + i];
  33. }
  34. function Car(x) {
  35. if (x < 0) {
  36. return Get(x);
  37. } else {
  38. Throw(x);
  39. }
  40. }
  41. function Cdr(x) {
  42. if (x < 0) {
  43. return Get(x + 1);
  44. } else {
  45. Throw(x);
  46. }
  47. }
  48. function Cons(car, cdr) {
  49. Set(--cx, cdr);
  50. Set(--cx, car);
  51. return cx;
  52. }
  53. function Hash(h, c) {
  54. return h + c * 2;
  55. }
  56. function Intern(x, y, i) {
  57. i &= Null - 1;
  58. if (x == Get(i) && y == Get(i + 1)) return i;
  59. if (Get(i)) return Intern(x, y, i + 2);
  60. Set(i, x);
  61. Set(i + 1, y);
  62. return i;
  63. }
  64. function ReadAtom(h) {
  65. var c = ReadChar();
  66. if (c <= Ord(' ')) return ReadAtom(h);
  67. return Intern(c, c > Ord(')') && dx > Ord(')') ?
  68. ReadAtom(Hash(h, c)) : 0,
  69. Hash(h, c) - Hash(0, Ord('N')));
  70. }
  71. function PrintAtom(x) {
  72. do PrintChar(Get(x));
  73. while ((x = Get(x + 1)));
  74. }
  75. function AddList(x) {
  76. return Cons(x, ReadList());
  77. }
  78. function ReadList() {
  79. var t = ReadAtom(0);
  80. if (Get(t) == Ord(')')) return -0;
  81. return AddList(ReadObject(t));
  82. }
  83. function ReadObject(t) {
  84. if (Get(t) != Ord('(')) return t;
  85. return ReadList();
  86. }
  87. function PrintList(x) {
  88. PrintChar(Ord('('));
  89. if (x < 0) {
  90. PrintObject(Car(x));
  91. while ((x = Cdr(x))) {
  92. if (x < 0) {
  93. PrintChar(Ord(' '));
  94. PrintObject(Car(x));
  95. } else {
  96. PrintChar(0x2219);
  97. PrintObject(x);
  98. break;
  99. }
  100. }
  101. }
  102. PrintChar(Ord(')'));
  103. }
  104. function PrintObject(x) {
  105. if (1./x < 0) {
  106. PrintList(x);
  107. } else {
  108. PrintAtom(x);
  109. }
  110. }
  111. function Print(e) {
  112. PrintObject(e);
  113. PrintChar(Ord('\n'));
  114. }
  115. function Read() {
  116. return ReadObject(ReadAtom(0));
  117. }
  118. function Define(a) {
  119. var x = Read();
  120. return Cons(Cons(x, Read()), a);
  121. }
  122. function Gc(A, x) {
  123. var C, B = cx;
  124. x = Copy(x, A, A - B), C = cx;
  125. while (C < B) Set(--A, Get(--B));
  126. cx = A;
  127. return x;
  128. }
  129. function Copy(x, m, k) {
  130. return x < m ? Cons(Copy(Car(x), m, k),
  131. Copy(Cdr(x), m, k)) + k : x;
  132. }
  133. function Evlis(m, a) {
  134. return m ? Cons(Eval(Car(m), a),
  135. Evlis(Cdr(m), a)) : m;
  136. }
  137. function Pairlis(x, y, a) {
  138. return x ? Cons(Cons(Car(x), Car(y)),
  139. Pairlis(Cdr(x), Cdr(y), a)) : a;
  140. }
  141. function Assoc(x, y) {
  142. if (y >= 0) Throw(x);
  143. if (x == Car(Car(y))) return Cdr(Car(y));
  144. return Assoc(x, Cdr(y));
  145. }
  146. function Evcon(c, a) {
  147. if (Eval(Car(Car(c)), a)) {
  148. return Eval(Car(Cdr(Car(c))), a);
  149. } else if (Cdr(c)) {
  150. return Evcon(Cdr(c), a);
  151. } else {
  152. Throw(c);
  153. }
  154. }
  155. function Apply(f, x, a) {
  156. if (f < 0) return Eval(Car(Cdr(Cdr(f))), Pairlis(Car(Cdr(f)), x, a));
  157. if (f == kEq) return Car(x) == Car(Cdr(x)) ? kT : 0;
  158. if (f == kCons) return Cons(Car(x), Car(Cdr(x)));
  159. if (f == kAtom) return Car(x) < 0 ? 0 : kT;
  160. if (f == kCar) return Car(Car(x));
  161. if (f == kCdr) return Cdr(Car(x));
  162. return Apply(Assoc(f, a), x, a);
  163. }
  164. function Eval(e, a) {
  165. var A = cx;
  166. if (!e) return e;
  167. if (e > 0) return Assoc(e, a);
  168. if (Car(e) == kQuote) return Car(Cdr(e));
  169. if (Car(e) == kCond) {
  170. e = Evcon(Cdr(e), a);
  171. } else {
  172. e = Apply(Car(e), Evlis(Cdr(e), a), a);
  173. }
  174. return Gc(A, e);
  175. }
  176. function LoadBuiltins() {
  177. ReadAtom(0);
  178. kT = ReadAtom(0);
  179. kEq = ReadAtom(0);
  180. kCar = ReadAtom(0);
  181. kCdr = ReadAtom(0);
  182. kAtom = ReadAtom(0);
  183. kCond = ReadAtom(0);
  184. kCons = ReadAtom(0);
  185. kQuote = ReadAtom(0);
  186. kDefine = ReadAtom(0);
  187. }
  188. //
`
  189. ////////////////////////////////////////////////////////////////////////////////
  190. // ANSI POSIX C Specific Code
  191. Ord(c) {
  192. return c;
  193. }
  194. Throw(x) {
  195. longjmp(undefined, ~x);
  196. }
  197. PrintChar(b) {
  198. fputwc(b, stdout);
  199. }
  200. ReadChar() {
  201. int b, c, t;
  202. static char *freeme;
  203. static char *line = "NIL T EQ CAR CDR ATOM COND CONS QUOTE DEFINE ";
  204. if (line || (line = freeme = bestlineWithHistory("* ", "sectorlisp"))) {
  205. if (*line) {
  206. c = *line++ & 0377;
  207. if (c >= 0300) {
  208. for (b = 0200; c & b; b >>= 1) c ^= b;
  209. while ((*line & 0300) == 0200) {
  210. c <<= 6;
  211. c |= *line++ & 0177;
  212. }
  213. }
  214. } else {
  215. free(freeme);
  216. freeme = 0;
  217. line = 0;
  218. c = '\n';
  219. }
  220. t = dx;
  221. dx = c;
  222. return t;
  223. } else {
  224. exit(0);
  225. }
  226. }
  227. main() {
  228. var x, a, A;
  229. setlocale(LC_ALL, "");
  230. bestlineSetXlatCallback(bestlineUppercase);
  231. LoadBuiltins();
  232. for (a = 0;;) {
  233. A = cx;
  234. if (!(x = setjmp(undefined))) {
  235. x = Read();
  236. if (x == kDefine) {
  237. a = Gc(A, Define(a));
  238. continue;
  239. }
  240. x = Eval(x, a);
  241. } else {
  242. x = ~x;
  243. PrintChar('?');
  244. }
  245. Print(x);
  246. Gc(A, 0);
  247. }
  248. }
  249. #if 0
  250. //`
  251. ////////////////////////////////////////////////////////////////////////////////
  252. // JavaScript Specific Code for https://justine.lol/
  253. var a, code, index, M, Null;
  254. var eInput, eOutput, eSubmit, eClear, eLoad, ePrograms;
  255. function Throw(x) {
  256. throw x;
  257. }
  258. function Ord(s) {
  259. return s.charCodeAt(0);
  260. }
  261. function PrintChar(c) {
  262. eOutput.innerText += String.fromCharCode(c);
  263. SaveOutput();
  264. }
  265. function ReadChar() {
  266. var ax;
  267. if (code.length) {
  268. ax = dx;
  269. if (index < code.length) {
  270. dx = code.charCodeAt(index++);
  271. } else {
  272. code = "";
  273. dx = 0;
  274. }
  275. return ax;
  276. } else {
  277. Throw(0);
  278. }
  279. }
  280. function Lisp() {
  281. var x, A;
  282. while (dx) {
  283. if (dx <= Ord(' ')) {
  284. ReadChar();
  285. } else {
  286. A = cx;
  287. try {
  288. x = Read();
  289. if (x == kDefine) {
  290. a = Gc(A, Define(a));
  291. continue;
  292. }
  293. x = Eval(x, a);
  294. } catch (z) {
  295. PrintChar(Ord('?'));
  296. x = z;
  297. }
  298. Print(x);
  299. Gc(A, 0);
  300. }
  301. }
  302. }
  303. function Load(s) {
  304. code = s + "\n";
  305. dx = Ord(s);
  306. index = 1;
  307. }
  308. function OnSubmit() {
  309. Load(eInput.value);
  310. Lisp();
  311. }
  312. function OnClear() {
  313. eOutput.innerText = "";
  314. SaveOutput();
  315. }
  316. function OnLoad() {
  317. ePrograms.classList.toggle("show");
  318. }
  319. function OnWindowClick(event) {
  320. if (!event.target.matches('#load')) {
  321. ePrograms.classList.remove("show");
  322. }
  323. }
  324. function SaveOutput() {
  325. if (typeof localStorage != 'undefined') {
  326. localStorage.setItem('output', eOutput.innerText);
  327. }
  328. }
  329. function SetUp() {
  330. a = 0;
  331. cx = 0;
  332. Null = 0100000;
  333. M = new Array(Null * 2);
  334. Load("NIL T EQ CAR CDR ATOM COND CONS QUOTE DEFINE ");
  335. LoadBuiltins()
  336. eLoad = document.getElementById('load');
  337. eInput = document.getElementById('input');
  338. eClear = document.getElementById('clear');
  339. eOutput = document.getElementById('output');
  340. eSubmit = document.getElementById('submit');
  341. ePrograms = document.getElementById("programs");
  342. window.onclick = OnWindowClick;
  343. eSubmit.onclick = OnSubmit;
  344. eClear.onclick = OnClear;
  345. eLoad.onclick = OnLoad;
  346. }
  347. SetUp();
  348. //
`
  349. #endif
  350. //`