123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771 |
- /*bin/echo '#-*- indent-tabs-mode:nil;js-indent-level:2;coding:utf-8 -*-
- SectorLISP v2.o (ISC License)
- Copyright 2021 Justine Tunney
- This file implements SectorLISP as a C / JavaScript polyglot and
- includes friendly branch features such as the undefined behavior
- exceptions handlers, optimized interning, and global definitions
- (aset standard-display-table #x2029 [?¶]) ;; emacs protip '>/dev/null
- curl -so bestline.c -z bestline.c https://justine.lol/sectorlisp2/bestline.c
- curl -so bestline.h -z bestline.h https://justine.lol/sectorlisp2/bestline.h
- [ lisp.js -nt lisp ] && cc -w -xc lisp.js bestline.c -o lisp
- exec ./lisp "$@"
- exit
- */
- //
`
- #include "bestline.h"
- #ifndef __COSMOPOLITAN__
- #include <assert.h>
- #include <stdio.h>
- #include <locale.h>
- #include <setjmp.h>
- #endif
- #define var int
- #define function
- #define Null 16384
- var M[Null * 2];
- var (*funcall)();
- jmp_buf undefined;
- //`
- var ax, cx, dx, depth, panic, fail;
- var cHeap, cGets, cSets, cReads, cPrints;
- var kEq, kCar, kCdr, kCond, kAtom, kCons, kQuote, kDefine;
- function Get(i) {
- ++cGets;
- return M[Null + i];
- }
- function Set(i, x) {
- ++cSets;
- M[Null + i] = x;
- }
- function Car(x) {
- if (x > 0) Throw(List(kCar, x));
- return x ? Get(x) : +0;
- }
- function Cdr(x) {
- if (x > 0) Throw(List(kCdr, x));
- return x ? Get(x + 1) : -0;
- }
- function Cons(car, cdr) {
- Set(--cx, cdr);
- Set(--cx, car);
- if (cx < cHeap) cHeap = cx;
- return cx;
- }
- function Probe(h, p) {
- return (h + p * p) & (Null / 2 - 1);
- }
- function Hash(h, x) {
- return (((h + x) * 3083 + 3191) >> 4) & (Null / 2 - 1);
- }
- function Intern(x, y, h, p) {
- if (x == Get(h) && y == Get(h + Null / 2)) return h;
- if (Get(h)) return Intern(x, y, Probe(h, p), p + 1);
- Set(h, x);
- Set(h + Null/2, y);
- return h;
- }
- function ReadAtom() {
- var x, y;
- ax = y = 0;
- do x = ReadChar();
- while (x <= Ord(' '));
- if (x > Ord(')') && dx > Ord(')')) y = ReadAtom();
- return Intern(x, y, (ax = Hash(x, ax)), 1);
- }
- function ReadList() {
- var x, y;
- if ((x = Read()) > 0) {
- if (Get(x) == Ord(')')) return -0;
- if (Get(x) == Ord('.') && !Get(x + 1)) {
- x = Read();
- y = ReadList();
- if (!y) {
- return x;
- } else {
- Throw(y);
- }
- }
- }
- return Cons(x, ReadList());
- }
- function Read() {
- var t;
- ++cReads;
- t = ReadAtom();
- if (Get(t) != Ord('(')) return t;
- return ReadList();
- }
- function PrintAtom(x) {
- do PrintChar(Get(x));
- while ((x = Get(x + Null / 2)));
- }
- function PrintList(x) {
- PrintChar(Ord('('));
- if (x < 0) {
- Print(Car(x));
- while ((x = Cdr(x))) {
- if (panic && cPrints > panic) {
- PrintChar(Ord(' '));
- PrintChar(0x2026);
- break;
- }
- if (x < 0) {
- PrintChar(Ord(' '));
- Print(Car(x));
- } else {
- PrintChar(Ord(' '));
- PrintChar(Ord('.'));
- PrintChar(Ord(' '));
- Print(x);
- break;
- }
- }
- }
- PrintChar(Ord(')'));
- }
- function Print(x) {
- ++cPrints;
- if (1./x < 0) {
- PrintList(x);
- } else {
- PrintAtom(x);
- }
- }
- function List(x, y) {
- return Cons(x, Cons(y, -0));
- }
- function Gc(A, x) {
- var C, B = cx;
- x = Copy(x, A, A - B), C = cx;
- while (C < B) Set(--A, Get(--B));
- return cx = A, x;
- }
- function Evcon(c, a) {
- if (c >= 0) Throw(kCond);
- if (Eval(Car(Car(c)), a)) {
- return Eval(Car(Cdr(Car(c))), a);
- } else {
- return Evcon(Cdr(c), a);
- }
- }
- function Peel(x, a) {
- return a && x == Car(Car(a)) ? Cdr(a) : a;
- }
- function Copy(x, m, k) {
- return x < m ? Cons(Copy(Car(x), m, k),
- Copy(Cdr(x), m, k)) + k : x;
- }
- function Evlis(m, a) {
- return m ? Cons(Eval(Car(m), a),
- Evlis(Cdr(m), a)) : m;
- }
- function Pairlis(x, y, a) {
- return x ? Cons(Cons(Car(x), Car(y)),
- Pairlis(Cdr(x), Cdr(y),
- Peel(Car(x), a))) : a;
- }
- function Assoc(x, y) {
- if (!y) Throw(x);
- return x == Car(Car(y)) ? Cdr(Car(y)) : Assoc(x, Cdr(y));
- }
- function Apply(f, x, a) {
- if (f < 0) return Eval(Car(Cdr(Cdr(f))), Pairlis(Car(Cdr(f)), x, a));
- if (f == kCons) return Cons(Car(x), Car(Cdr(x)));
- if (f == kEq) return Car(x) == Car(Cdr(x));
- if (f == kAtom) return Car(x) >= 0;
- if (f == kCar) return Car(Car(x));
- if (f == kCdr) return Cdr(Car(x));
- return funcall(cx, f, Assoc(f, a), x, a);
- }
- function Eval(e, a) {
- if (!e) return e;
- if (e > 0) return Assoc(e, a);
- if (Car(e) == kQuote) return Car(Cdr(e));
- if (Car(e) == kCond) return Evcon(Cdr(e), a);
- return Apply(Car(e), Evlis(Cdr(e), a), a);
- }
- function Funcall(A, f, l, x, a) {
- return Gc(A, Apply(l, x, a));
- }
- function Funtrace(A, f, l, x, a) {
- var y;
- Indent(depth);
- Print(f);
- Print(x);
- PrintChar(Ord('\n'));
- depth += 2;
- y = Funcall(cx, f, l, x, a);
- depth -= 2;
- Indent(depth);
- Print(f);
- Print(x);
- PrintChar(Ord(' '));
- PrintChar(0x2192);
- PrintChar(Ord(' '));
- Print(y);
- PrintChar(Ord('\n'));
- return y;
- }
- function Indent(i) {
- if (i) {
- PrintChar(Ord(' '));
- Indent(i - 1);
- }
- }
- function DumpAlist(a) {
- PrintChar(Ord('('));
- PrintChar(Ord('\n'));
- for (;a ;a = Cdr(a)) {
- PrintChar(Ord('('));
- Print(Car(Car(a)));
- PrintChar(Ord(' '));
- PrintChar(Ord('.'));
- PrintChar(Ord(' '));
- Print(Cdr(Car(a)));
- PrintChar(Ord(')'));
- PrintChar(Ord('\n'));
- }
- PrintChar(Ord(')'));
- }
- function DumpDefines(a) {
- if (a) {
- DumpDefines(Cdr(a));
- PrintChar(Ord('('));
- Print(kDefine);
- PrintChar(Ord(' '));
- Print(Car(Car(a)));
- PrintChar(Ord(' '));
- PrintChar(Ord('.'));
- PrintChar(Ord(' '));
- Print(Cdr(Car(a)));
- PrintChar(Ord(')'));
- PrintChar(Ord('\n'));
- }
- }
- function LoadBuiltins() {
- Read();
- Read();
- kEq = Read();
- kCar = Read();
- kCdr = Read();
- kAtom = Read();
- kCond = Read();
- kCons = Read();
- kQuote = Read();
- kDefine = Read();
- }
- function Crunch(e, B) {
- var x, y, i;
- if (e >= 0) return e;
- x = Crunch(Car(e), B);
- y = Crunch(Cdr(e), B);
- for (i = B - 2; i >= cx; i -= 2) {
- if (x == Car(i) &&
- y == Cdr(i)) {
- return i - B;
- }
- }
- return Cons(x, y) - B;
- }
- function Compact(x) {
- var C, B = cx, A = 0;
- x = Crunch(x, B), C = cx;
- while (C < B) Set(--A, Get(--B));
- return cx = A, x;
- }
- function Remove(x, y) {
- if (!y) return y;
- if (x == Car(Car(y))) return Cdr(y);
- return Cons(Car(y), Remove(x, Cdr(y)));
- }
- function Define(x, a) {
- return Compact(Cons(x, Remove(Car(x), a)));
- }
- //
`
- ////////////////////////////////////////////////////////////////////////////////
- // ANSI POSIX C Specific Code
- Ord(c) {
- return c;
- }
- Throw(x) {
- if (fail < 255) ++fail;
- longjmp(undefined, ~x);
- }
- PrintChar(b) {
- fputwc(b, stdout);
- }
- SaveAlist(a) {
- }
- ReadChar() {
- int b, c, t;
- static char *freeme;
- static char *line = "NIL T EQ CAR CDR ATOM COND CONS QUOTE DEFINE ";
- if (line || (line = freeme = bestlineWithHistory("* ", "sectorlisp"))) {
- if (*line) {
- c = *line++ & 0377;
- if (c >= 0300) {
- for (b = 0200; c & b; b >>= 1) c ^= b;
- while ((*line & 0300) == 0200) {
- c <<= 6;
- c |= *line++ & 0177;
- }
- }
- } else {
- free(freeme);
- freeme = 0;
- line = 0;
- c = '\n';
- }
- t = dx;
- dx = c;
- return t;
- } else {
- exit(fail);
- }
- }
- main(argc, argv)
- char *argv[];
- {
- var x, a, A;
- setlocale(LC_ALL, "");
- bestlineSetXlatCallback(bestlineUppercase);
- funcall = Funcall;
- for (x = 1; x < argc; ++x) {
- if (argv[x][0] == '-' && argv[x][1] == 't') {
- funcall = Funtrace;
- } else {
- fputs("Usage: ", stderr);
- fputs(argv[0], stderr);
- fputs(" [-t] <input.lisp >errput.lisp\n", stderr);
- exit(1);
- }
- }
- LoadBuiltins();
- for (a = 0;;) {
- A = cx;
- if (!(x = setjmp(undefined))) {
- x = Read();
- if (x < 0 && Car(x) == kDefine) {
- a = Define(Cdr(x), a);
- SaveAlist(a);
- continue;
- }
- x = Eval(x, a);
- } else {
- x = ~x;
- PrintChar('?');
- }
- Print(x);
- PrintChar('\n');
- Gc(A, 0);
- }
- }
- #if 0
- //`
- ////////////////////////////////////////////////////////////////////////////////
- // JavaScript Specific Code for https://justine.lol/
- var a, code, index, output, funcall, M, Null;
- var eOutput, eEval, eReset, eLoad, eTrace, ePrograms, eDump;
- var eGets, eSets, eMs, eAtoms, eCode, eHeap, eReads, eWrites, eClear;
- function Throw(x) {
- throw x;
- }
- function Reset() {
- var i;
- a = 0;
- cx = 0;
- cHeap = 0;
- cGets = 0;
- cSets = 0;
- cReads = 0;
- cPrints = 0;
- Null = 16384;
- M = new Array(Null * 2);
- // for (i = 0; i < M.length; ++i) {
- // M[i] = 0; /* make json smaller */
- // }
- Load("NIL T EQ CAR CDR ATOM COND CONS QUOTE DEFINE ");
- LoadBuiltins()
- }
- function PrintU16(c) {
- output += String.fromCharCode(c);
- }
- function IsHighSurrogate(c) {
- return (0xfc00 & c) == 0xd800;
- }
- function IsLowSurrogate(c) {
- return (0xfc00 & c) == 0xdc00;
- }
- function GetHighSurrogate(c) {
- return ((c - 0x10000) >> 10) + 0xD800;
- }
- function GetLowSurrogate(c) {
- return ((c - 0x10000) & 1023) + 0xDC00;
- }
- function ComposeUtf16(c, d) {
- return ((c - 0xD800) << 10) + (d - 0xDC00) + 0x10000;
- }
- function PrintChar(c) {
- if (c < 0x10000) {
- PrintU16(c);
- } else if (c < 0x110000) {
- PrintU16(GetHighSurrogate(c));
- PrintU16(GetLowSurrogate(c));
- } else {
- PrintU16(0xFFFD);
- }
- }
- function Ord(s) {
- var c, d;
- c = s.charCodeAt(0);
- if (IsHighSurrogate(c)) {
- if (code.length > 1 && IsLowSurrogate((d = s.charCodeAt(1)))) {
- c = ComposeUtf16(c, d);
- } else {
- c = 0xFFFD;
- }
- } else if (IsLowSurrogate(c)) {
- c = 0xFFFD;
- }
- return c;
- }
- function ReadChar() {
- var c, d, t;
- if (code.length) {
- if (index < code.length) {
- c = code.charCodeAt(index++);
- if (IsHighSurrogate(c)) {
- if (index < code.length &&
- IsLowSurrogate((d = code.charCodeAt(index)))) {
- c = ComposeUtf16(c, d), ++index;
- } else {
- c = 0xFFFD;
- }
- } else if (IsLowSurrogate(c)) {
- c = 0xFFFD;
- }
- } else {
- code = "";
- c = 0;
- }
- t = dx;
- dx = c;
- return t;
- } else {
- Throw(0);
- }
- }
- function Lisp() {
- var x, A, d, t;
- d = 0;
- cGets = 0;
- cSets = 0;
- cHeap = cx;
- cReads = 0;
- cPrints = 0;
- output = "";
- while (dx) {
- if (dx <= Ord(' ')) {
- ReadChar();
- } else {
- t = GetMillis();
- A = cx;
- try {
- x = Read();
- if (x < 0 && Car(x) == kDefine) {
- a = Define(Cdr(x), a);
- continue;
- }
- x = Eval(x, a);
- } catch (z) {
- PrintChar(Ord('?'));
- x = z;
- }
- Print(x);
- PrintChar(Ord('\n'));
- Gc(A, 0);
- d += GetMillis() - t;
- }
- }
- eOutput.innerText = output;
- SaveAlist(a);
- SaveOutput();
- ReportUsage(d);
- }
- function Load(s) {
- index = 0;
- dx = Ord(' ');
- code = s + "\n";
- }
- function OnEval() {
- Load(g_editor.getValue());
- Lisp();
- SetStorage("input", g_editor.getValue());
- }
- function OnBeforeUnload() {
- SetStorage("input", g_editor.getValue());
- }
- function OnDump() {
- var t;
- output = "";
- t = GetMillis();
- DumpDefines(a);
- eOutput.innerText = output;
- t = GetMillis() - t;
- SaveOutput();
- ReportUsage(t);
- }
- function OnReset(e) {
- var t;
- output = "";
- t = GetMillis();
- try {
- if (!e.shiftKey) DumpDefines(a);
- eOutput.innerText = output;
- Reset();
- } catch (e) {
- /* ignored */
- }
- t = GetMillis() - t;
- RemoveStorage("alist");
- SaveOutput();
- ReportUsage(t);
- }
- function OnClear() {
- output = "";
- eOutput.innerText = output;
- SaveOutput();
- ReportUsage(0);
- }
- function OnTrace() {
- var t;
- Load(g_editor.getValue());
- t = panic;
- depth = 0;
- panic = 10000;
- funcall = Funtrace;
- Lisp();
- funcall = Funcall;
- panic = t;
- }
- function OnLoad() {
- if (ePrograms.className == "dropdown-content") {
- ePrograms.className = "dropdown-content show";
- } else {
- ePrograms.className = "dropdown-content";
- }
- }
- function OnWindowClick(e) {
- if (e.target && !e.target.matches("#load")) {
- ePrograms.className = "dropdown-content";
- }
- }
- function OnWindowKeyDown(e) {
- if (e.key == "Escape") {
- ePrograms.className = "dropdown-content";
- }
- }
- function SaveAlist(a) {
- output = "";
- DumpAlist(a);
- SetStorage("alist", output);
- }
- function RestoreMachine() {
- var v;
- if ((v = GetStorage("output"))) {
- eOutput.innerText = v;
- }
- if ((v = GetStorage("input"))) {
- g_editor.setValue(v);
- }
- if ((v = GetStorage("alist"))) {
- Reset();
- Load(v);
- a = Compact(Read());
- } else if ((v = JSON.parse(GetStorage("machine")))) {
- M = v[0];
- a = v[1];
- cx = v[2];
- cHeap = cx;
- }
- }
- function SaveOutput() {
- SetStorage("input", g_editor.getValue());
- SetStorage("output", eOutput.innerText);
- }
- function FormatInt(i) {
- return i.toLocaleString();
- }
- function FormatDuration(d) {
- return d ? Math.round(d * 1000) / 1000 : 0;
- }
- function ReportUsage(ms) {
- var i, atom, code, heap;
- code = -cx >> 1;
- heap = -cHeap >> 1;
- for (atom = i = 0; i < Null / 2; ++i) {
- if (M[Null + i]) ++atom;
- }
- if (eGets) eGets.innerText = FormatInt(cGets);
- if (eSets) eSets.innerText = FormatInt(cSets);
- if (eMs) eMs.innerText = FormatInt(ms);
- if (eAtoms) eAtoms.innerText = FormatInt(atom);
- if (eCode) eCode.innerText = FormatInt(code);
- if (eHeap) eHeap.innerText = FormatInt(heap - code);
- if (eReads) eReads.innerText = FormatInt(cReads);
- if (ePrints) ePrints.innerText = FormatInt(cPrints);
- }
- function Discount(f) {
- return function() {
- var x, g, h, s;
- g = cGets;
- s = cSets;
- h = cHeap;
- x = f.apply(this, arguments);
- cHeap = h;
- cSets = s;
- cGets = g;
- return x;
- };
- }
- function GetMillis() {
- if (typeof performance != "undefined") {
- return performance.now();
- } else {
- return 0;
- }
- }
- function GetStorage(k) {
- if (typeof localStorage != "undefined") {
- return localStorage.getItem(g_lisp + "." + k);
- } else {
- return null;
- }
- }
- function RemoveStorage(k) {
- if (typeof localStorage != "undefined") {
- localStorage.removeItem(g_lisp + "." + k);
- }
- }
- function SetStorage(k, v) {
- if (typeof localStorage != "undefined") {
- localStorage.setItem(g_lisp + "." + k, v);
- }
- }
- function SetUp() {
- funcall = Funcall;
- Read = Discount(Read);
- Print = Discount(Print);
- Define = Discount(Define);
- eLoad = document.getElementById("load");
- eReset = document.getElementById("reset");
- eTrace = document.getElementById("trace");
- eOutput = document.getElementById("output");
- eEval = document.getElementById("eval");
- eClear = document.getElementById("clear");
- eDump = document.getElementById("dump");
- ePrograms = document.getElementById("programs");
- eGets = document.getElementById("cGets");
- eSets = document.getElementById("cSets");
- eMs = document.getElementById("cMs");
- eAtoms = document.getElementById("cAtoms");
- eCode = document.getElementById("cCode");
- eHeap = document.getElementById("cHeap");
- eReads = document.getElementById("cReads");
- ePrints = document.getElementById("cPrints");
- window.onkeydown = OnWindowKeyDown;
- if (window.onbeforeunload) window.onbeforeunload = OnBeforeUnload;
- if (ePrograms) window.onclick = OnWindowClick;
- if (eLoad) eLoad.onclick = OnLoad;
- if (eReset) eReset.onclick = OnReset;
- if (eTrace) eTrace.onclick = OnTrace;
- if (eEval) eEval.onclick = OnEval;
- if (eDump) eDump.onclick = OnDump;
- if (eClear) eClear.onclick = OnClear;
- }
- //
`
- #endif
- //`
|