js-slang
Version:
Javascript-based implementations of Source, written in Typescript
823 lines (821 loc) • 22.7 kB
JavaScript
/*
convention:
_ --> -
E --> = (since all scheme basic procedures are in lower case)
Q --> ?
B --> !
L --> <
G --> >
to be changed with regex.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.booleanEQ = exports.booleanQ = exports.not = exports.or = exports.and = exports.$true = exports.string_Gnumber = exports.number_Gstring = exports.exact = exports.inexact = exports.expt = exports.exact_integer_sqrt = exports.square = exports.rationalize = exports.round = exports.truncate = exports.ceiling = exports.floor = exports.lcm = exports.gcd = exports.remainder = exports.modulo = exports.quotient = exports.abs = exports.divide = exports.minus = exports.multiply = exports.plus = exports.min = exports.max = exports.evenQ = exports.oddQ = exports.negativeQ = exports.positiveQ = exports.zeroQ = exports.GE = exports.LE = exports.G = exports.L = exports.E = exports.exact_integerQ = exports.exactQ = exports.integerQ = exports.rationalQ = exports.realQ = exports.complexQ = exports.numberQ = exports.equalQ = exports.eqvQ = exports.eqQ = void 0;
exports.string_copy = exports.list_Gstring = exports.string_Glist = exports.string_append = exports.substring = exports.stringGEQ = exports.stringLEQ = exports.stringGQ = exports.stringLQ = exports.stringEQ = exports.string_setB = exports.string_ref = exports.string_length = exports.string = exports.make_string = exports.stringQ = exports.string_Gsymbol = exports.symbol_Gstring = exports.symbolEQ = exports.symbolQ = exports._Symbol = exports.list_copy = exports.assoc = exports.assv = exports.assq = exports.member = exports.memv = exports.memq = exports.list_setB = exports.list_ref = exports.list_tail = exports.reverse = exports.append = exports.length = exports.list_star = exports.list = exports.make_list = exports.listQ = exports.nullQ = exports.cddr = exports.cdar = exports.cadr = exports.caar = exports.set_cdrB = exports.set_carB = exports.cdr = exports.car = exports.cons = exports.pairQ = exports.$list_to_array = void 0;
exports.newline = exports.error = exports.map = exports.apply = exports.procedureQ = exports.vector_fillB = exports.vector_append = exports.vector_copyB = exports.vector_copy = exports.string_Gvector = exports.vector_Gstring = exports.list_Gvector = exports.vector_Glist = exports.vector_setB = exports.vector_ref = exports.vector_length = exports.vector = exports.make_vector = exports.vectorQ = exports.string_for_each = exports.string_map = exports.string_fillB = exports.string_copyB = void 0;
// Splice resolver
// class SpliceMark {
// val: Pair | null;
// }
// // maps over a list. if the list contains a splice mark, it will
// // splice the list into the result list.
// export let resolve_splice = function (xs: any): Pair | null {
// if (!pairQ(xs)) {
// if (xs instanceof SpliceMark) {
// return xs.val;
// }
// const car_xs = car(xs);
// const cdr_xs = cdr(xs);
// if (car_xs instanceof SpliceMark) {
// return append(car_xs.val, resolve_splice(cdr_xs as Pair));
// } else {
// return cons(car_xs, resolve_splice(cdr_xs as Pair));
// }
// }
// export let make_splice = function(xs: any) {
// if (!listQ(xs)) {
// throw new Error("unquote-splicing: expected list, got " + xs.toString());
// }
// return new SpliceMark(xs);
// }
// Equivalence predicates
let eqQ = function (x, y) {
if (x instanceof _Symbol && y instanceof _Symbol) {
return x.sym === y.sym;
}
return x === y;
};
exports.eqQ = eqQ;
let eqvQ = function (x, y) {
if (x === y) {
return true;
}
else if (typeof x === "number" && typeof y === "number") {
return isNaN(x) && isNaN(y);
}
else if (x instanceof _Symbol && y instanceof _Symbol) {
return x.sym === y.sym;
}
else {
return false;
}
};
exports.eqvQ = eqvQ;
let equalQ = function (x, y) {
if (x === y) {
return true;
}
else if (typeof x === "number" && typeof y === "number") {
return isNaN(x) && isNaN(y);
}
else if ((0, exports.pairQ)(x) && (0, exports.pairQ)(y)) {
return (0, exports.equalQ)((0, exports.car)(x), (0, exports.car)(y)) && (0, exports.equalQ)((0, exports.cdr)(x), (0, exports.cdr)(y));
}
else if (x instanceof _Symbol && y instanceof _Symbol) {
return x.sym === y.sym;
}
else {
return false;
}
};
exports.equalQ = equalQ;
// Numbers
let numberQ = function (n) {
return typeof n === "number";
};
exports.numberQ = numberQ;
let complexQ = function (n) {
return typeof n === "number";
};
exports.complexQ = complexQ;
let realQ = function (n) {
return typeof n === "number";
};
exports.realQ = realQ;
let rationalQ = function (n) {
return typeof n === "number";
};
exports.rationalQ = rationalQ;
let integerQ = function (n) {
return typeof n === "number" && n % 1 === 0;
};
exports.integerQ = integerQ;
let exactQ = function (n) {
return typeof n === "number" && n % 1 === 0;
};
exports.exactQ = exactQ;
let exact_integerQ = function (n) {
return typeof n === "number" && n % 1 === 0;
};
exports.exact_integerQ = exact_integerQ;
let E = function (...args) {
let acc = true;
for (let i = 0; i < args.length - 1; i++) {
if (!(0, exports.numberQ)(args[i])) {
throw new Error("procedure =: expected number, got " + args[i].toString());
}
acc = acc && args[i] === args[i + 1];
}
return acc;
};
exports.E = E;
let L = function (...args) {
let acc = true;
for (let i = 0; i < args.length - 1; i++) {
if (!(0, exports.numberQ)(args[i])) {
throw new Error("procedure <: expected number, got " + args[i].toString());
}
acc = acc && args[i] < args[i + 1];
}
return acc;
};
exports.L = L;
let G = function (...args) {
let acc = true;
for (let i = 0; i < args.length - 1; i++) {
if (!(0, exports.numberQ)(args[i])) {
throw new Error("procedure >: expected number, got " + args[i].toString());
}
acc = acc && args[i] > args[i + 1];
}
return acc;
};
exports.G = G;
let LE = function (...args) {
let acc = true;
for (let i = 0; i < args.length - 1; i++) {
if (!(0, exports.numberQ)(args[i])) {
throw new Error("procedure <=: expected number, got " + args[i].toString());
}
acc = acc && args[i] <= args[i + 1];
}
return acc;
};
exports.LE = LE;
let GE = function (...args) {
let acc = true;
for (let i = 0; i < args.length - 1; i++) {
if (!(0, exports.numberQ)(args[i])) {
throw new Error("procedure >=: expected number, got " + args[i].toString());
}
acc = acc && args[i] >= args[i + 1];
}
return acc;
};
exports.GE = GE;
let zeroQ = function (n) {
return (0, exports.E)(n, 0);
};
exports.zeroQ = zeroQ;
let positiveQ = function (n) {
return (0, exports.G)(n, 0);
};
exports.positiveQ = positiveQ;
let negativeQ = function (n) {
return (0, exports.L)(n, 0);
};
exports.negativeQ = negativeQ;
let oddQ = function (n) {
if (!(0, exports.numberQ)(n)) {
throw new Error("procedure odd?: expected number, got " + n.toString());
}
return n % 2 !== 0;
};
exports.oddQ = oddQ;
let evenQ = function (n) {
if (!(0, exports.numberQ)(n)) {
throw new Error("procedure even?: expected number, got " + n.toString());
}
return n % 2 === 0;
};
exports.evenQ = evenQ;
let max = function (...args) {
return Math.max(...args);
};
exports.max = max;
let min = function (...args) {
return Math.min(...args);
};
exports.min = min;
let plus = function (...args) {
return args.reduce((a, b) => a + b, 0);
};
exports.plus = plus;
let multiply = function (...args) {
return args.reduce((a, b) => a * b, 1);
};
exports.multiply = multiply;
let minus = function (...args) {
if (args.length < 2) {
return -args[0];
}
return args.slice(1).reduce((a, b) => a - b, args[0]);
};
exports.minus = minus;
let divide = function (...args) {
if (args.length < 2) {
return 1 / args[0];
}
return args.slice(1).reduce((a, b) => a / b, args[0]);
};
exports.divide = divide;
let abs = function (x) {
return Math.abs(x);
};
exports.abs = abs;
let quotient = function (x, y) {
return Math.trunc(x / y);
};
exports.quotient = quotient;
let modulo = function (x, y) {
return x % y;
};
exports.modulo = modulo;
let remainder = function (x, y) {
return x % y;
};
exports.remainder = remainder;
let gcd = function (...args) {
return args.reduce((a, b) => {
if (a === 0) {
return (0, exports.abs)(b);
}
return (0, exports.gcd)((0, exports.abs)(b % a), (0, exports.abs)(a));
}, 0);
};
exports.gcd = gcd;
let lcm = function (...args) {
return args.reduce((a, b) => {
return (0, exports.abs)(a * b) / (0, exports.gcd)(a, b);
}, 1);
};
exports.lcm = lcm;
let floor = function (x) {
return Math.floor(x);
};
exports.floor = floor;
let ceiling = function (x) {
return Math.ceil(x);
};
exports.ceiling = ceiling;
let truncate = function (x) {
return Math.trunc(x);
};
exports.truncate = truncate;
let round = function (x) {
return Math.round(x);
};
exports.round = round;
let rationalize = function (x, y) {
return x / y;
};
exports.rationalize = rationalize;
let square = function (x) {
return x * x;
};
exports.square = square;
let exact_integer_sqrt = function (x) {
return Math.sqrt(x);
};
exports.exact_integer_sqrt = exact_integer_sqrt;
let expt = function (x, y) {
return Math.pow(x, y);
};
exports.expt = expt;
let inexact = function (x) {
return x;
};
exports.inexact = inexact;
let exact = function (x) {
return x;
};
exports.exact = exact;
let number_Gstring = function (x) {
return x.toString();
};
exports.number_Gstring = number_Gstring;
let string_Gnumber = function (x) {
return Number(x);
};
exports.string_Gnumber = string_Gnumber;
// Booleans
// Important value for the interpreter:
// As truthy and falsy values in Scheme are different
// from JavaScript, this will convert the value to Scheme's truthy value.
const $true = function (b) {
if (b === false) {
return false;
}
return true;
};
exports.$true = $true;
let and = function (...args) {
return args.reduce((a, b) => (0, exports.$true)(a) && b, true);
};
exports.and = and;
let or = function (...args) {
return args.reduce((a, b) => (0, exports.$true)(a) || b, false);
};
exports.or = or;
let not = function (b) {
if (b === false) {
return true;
}
return false;
};
exports.not = not;
let booleanQ = function (b) {
return b === true || b === false;
};
exports.booleanQ = booleanQ;
let booleanEQ = function (b1, b2) {
return b1 === b2;
};
exports.booleanEQ = booleanEQ;
// Pairs
// Special function needed by base scm-slang
// to work with lists.
const $list_to_array = function (l) {
let acc = [];
while (!(0, exports.nullQ)(l)) {
acc.push((0, exports.car)(l));
l = (0, exports.cdr)(l);
}
return acc;
};
exports.$list_to_array = $list_to_array;
let pairQ = function (p) {
return p instanceof Array && p.length === 2;
};
exports.pairQ = pairQ;
let cons = function (car, cdr) {
return [car, cdr];
};
exports.cons = cons;
let car = function (p) {
if (p === null) {
(0, exports.error)("car: null pair");
}
return p[0];
};
exports.car = car;
let cdr = function (p) {
if (p === null) {
(0, exports.error)("cdr: null pair");
}
return p[1];
};
exports.cdr = cdr;
let set_carB = function (p, val) {
if (p === null) {
(0, exports.error)("set-car!: null pair");
}
p[0] = val;
};
exports.set_carB = set_carB;
let set_cdrB = function (p, val) {
if (p === null) {
(0, exports.error)("set-cdr!: null pair");
}
p[1] = val;
};
exports.set_cdrB = set_cdrB;
let caar = function (p) {
return (0, exports.car)((0, exports.car)(p));
};
exports.caar = caar;
let cadr = function (p) {
return (0, exports.car)((0, exports.cdr)(p));
};
exports.cadr = cadr;
let cdar = function (p) {
return (0, exports.cdr)((0, exports.car)(p));
};
exports.cdar = cdar;
let cddr = function (p) {
return (0, exports.cdr)((0, exports.cdr)(p));
};
exports.cddr = cddr;
let nullQ = function (p) {
return p === null;
};
exports.nullQ = nullQ;
let listQ = function (p) {
return p === null ? true : (0, exports.pairQ)(p) && (0, exports.listQ)((0, exports.cdr)(p));
};
exports.listQ = listQ;
let make_list = function (n, val = null) {
let acc = null;
for (let i = 0; i < n; i++) {
acc = (0, exports.cons)(val, acc);
}
return acc;
};
exports.make_list = make_list;
let list = function (...args) {
let acc = null;
for (let i = args.length - 1; i >= 0; i--) {
acc = (0, exports.cons)(args[i], acc);
}
return acc;
};
exports.list = list;
let list_star = function (...args) {
let acc = args[args.length - 1];
for (let i = args.length - 2; i >= 0; i--) {
acc = (0, exports.cons)(args[i], acc);
}
return acc;
};
exports.list_star = list_star;
let length = function (p) {
let acc = 0;
while (p !== null) {
acc++;
p = (0, exports.cdr)(p);
}
return acc;
};
exports.length = length;
let append = function (...args) {
if (args.length === 0) {
return null;
}
else if (args.length === 1) {
return args[0];
}
else {
if (args[0] === null) {
return (0, exports.append)(...args.slice(1));
}
else {
return (0, exports.cons)((0, exports.car)(args[0]), (0, exports.append)((0, exports.cdr)(args[0]), ...args.slice(1)));
}
}
};
exports.append = append;
let reverse = function (p) {
let acc = null;
while (p !== null) {
acc = (0, exports.cons)((0, exports.car)(p), acc);
p = (0, exports.cdr)(p);
}
return acc;
};
exports.reverse = reverse;
let list_tail = function (p, n) {
if (n === 0) {
return p;
}
else {
return (0, exports.list_tail)((0, exports.cdr)(p), n - 1);
}
};
exports.list_tail = list_tail;
let list_ref = function (p, n) {
return (0, exports.car)((0, exports.list_tail)(p, n));
};
exports.list_ref = list_ref;
let list_setB = function (p, n, val) {
(0, exports.set_carB)((0, exports.list_tail)(p, n), val);
};
exports.list_setB = list_setB;
let memq = function (item, p) {
if (p === null) {
return false;
}
else if ((0, exports.eqQ)((0, exports.car)(p), item)) {
return p;
}
else {
return (0, exports.memq)(item, (0, exports.cdr)(p));
}
};
exports.memq = memq;
let memv = function (item, p) {
if (p === null) {
return false;
}
else if ((0, exports.eqvQ)((0, exports.car)(p), item)) {
return p;
}
else {
return (0, exports.memv)(item, (0, exports.cdr)(p));
}
};
exports.memv = memv;
let member = function (item, p) {
if (p === null) {
return false;
}
else if ((0, exports.equalQ)((0, exports.car)(p), item)) {
return p;
}
else {
return (0, exports.member)(item, (0, exports.cdr)(p));
}
};
exports.member = member;
let assq = function (item, p) {
if (p === null) {
return false;
}
else if ((0, exports.eqQ)((0, exports.caar)(p), item)) {
return (0, exports.car)(p);
}
else {
return (0, exports.assq)(item, (0, exports.cdr)(p));
}
};
exports.assq = assq;
let assv = function (item, p) {
if (p === null) {
return false;
}
else if ((0, exports.eqvQ)((0, exports.caar)(p), item)) {
return (0, exports.car)(p);
}
else {
return (0, exports.assv)(item, (0, exports.cdr)(p));
}
};
exports.assv = assv;
let assoc = function (item, p) {
if (p === null) {
return false;
}
else if ((0, exports.equalQ)((0, exports.caar)(p), item)) {
return (0, exports.car)(p);
}
else {
return (0, exports.assoc)(item, (0, exports.cdr)(p));
}
};
exports.assoc = assoc;
let list_copy = function (p) {
if (p === null) {
return null;
}
else {
return (0, exports.cons)((0, exports.car)(p), (0, exports.list_copy)((0, exports.cdr)(p)));
}
};
exports.list_copy = list_copy;
// Symbols
class _Symbol {
constructor(sym) {
this.sym = sym;
}
toString() {
return this.sym;
}
equals(other) {
return other instanceof _Symbol && this.sym === other.sym;
}
}
exports._Symbol = _Symbol;
let symbolQ = function (s) {
return s instanceof _Symbol;
};
exports.symbolQ = symbolQ;
let symbolEQ = function (s1, s2) {
return s1 instanceof _Symbol && s2 instanceof _Symbol && s1.equals(s2);
};
exports.symbolEQ = symbolEQ;
let symbol_Gstring = function (s) {
return s.sym;
};
exports.symbol_Gstring = symbol_Gstring;
let string_Gsymbol = function (s) {
return new _Symbol(s);
};
exports.string_Gsymbol = string_Gsymbol;
// Strings
let stringQ = function (s) {
return typeof s === "string";
};
exports.stringQ = stringQ;
let make_string = function (n, ch = " ") {
let acc = "";
for (let i = 0; i < n; i++) {
acc += ch;
}
return acc;
};
exports.make_string = make_string;
let string = function (...args) {
return args.join("");
};
exports.string = string;
let string_length = function (s) {
return s.length;
};
exports.string_length = string_length;
let string_ref = function (s, n) {
return s[n];
};
exports.string_ref = string_ref;
// Immutable strings. this does not work.
let string_setB = function (s, n, ch) {
//s[n] = ch;
};
exports.string_setB = string_setB;
let stringEQ = function (s1, s2) {
return s1 === s2;
};
exports.stringEQ = stringEQ;
let stringLQ = function (s1, s2) {
return s1 < s2;
};
exports.stringLQ = stringLQ;
let stringGQ = function (s1, s2) {
return s1 > s2;
};
exports.stringGQ = stringGQ;
let stringLEQ = function (s1, s2) {
return s1 <= s2;
};
exports.stringLEQ = stringLEQ;
let stringGEQ = function (s1, s2) {
return s1 >= s2;
};
exports.stringGEQ = stringGEQ;
let substring = function (s, start, end = s.length) {
return s.slice(start, end);
};
exports.substring = substring;
let string_append = function (...args) {
return args.join("");
};
exports.string_append = string_append;
let string_Glist = function (s) {
let acc = null;
for (let i = s.length - 1; i >= 0; i--) {
acc = (0, exports.cons)(s[i], acc);
}
return acc;
};
exports.string_Glist = string_Glist;
let list_Gstring = function (p) {
let acc = "";
while (p !== null) {
acc += (0, exports.car)(p);
p = (0, exports.cdr)(p);
}
return acc;
};
exports.list_Gstring = list_Gstring;
let string_copy = function (s) {
return s;
};
exports.string_copy = string_copy;
// Does nothing.
let string_copyB = function (s) {
return s;
};
exports.string_copyB = string_copyB;
// Does nothing.
let string_fillB = function (s, ch) {
for (let i = 0; i < s.length; i++) {
//s[i] = ch;
}
};
exports.string_fillB = string_fillB;
let string_map = function (f, s) {
let acc = "";
for (let i = 0; i < s.length; i++) {
acc += f(s[i]);
}
return acc;
};
exports.string_map = string_map;
let string_for_each = function (f, s) {
for (let i = 0; i < s.length; i++) {
f(s[i]);
}
};
exports.string_for_each = string_for_each;
let vectorQ = function (v) {
return v instanceof Array;
};
exports.vectorQ = vectorQ;
let make_vector = function (n, fill = null) {
let acc = [];
for (let i = 0; i < n; i++) {
acc.push(fill);
}
return acc;
};
exports.make_vector = make_vector;
let vector = function (...args) {
return args;
};
exports.vector = vector;
let vector_length = function (v) {
return v.length;
};
exports.vector_length = vector_length;
let vector_ref = function (v, n) {
return v[n];
};
exports.vector_ref = vector_ref;
let vector_setB = function (v, n, item) {
v[n] = item;
};
exports.vector_setB = vector_setB;
let vector_Glist = function (v) {
let acc = null;
for (let i = v.length - 1; i >= 0; i--) {
acc = (0, exports.cons)(v[i], acc);
}
return acc;
};
exports.vector_Glist = vector_Glist;
let list_Gvector = function (p) {
let acc = [];
while (p !== null) {
acc.push((0, exports.car)(p));
p = (0, exports.cdr)(p);
}
return acc;
};
exports.list_Gvector = list_Gvector;
let vector_Gstring = function (v) {
let acc = "";
for (let i = 0; i < v.length; i++) {
acc += v[i];
}
return acc;
};
exports.vector_Gstring = vector_Gstring;
let string_Gvector = function (s) {
let acc = [];
for (let i = 0; i < s.length; i++) {
acc.push(s[i]);
}
return acc;
};
exports.string_Gvector = string_Gvector;
let vector_copy = function (v) {
return [...v];
};
exports.vector_copy = vector_copy;
let vector_copyB = function (to, at, from, start = undefined, end = undefined) {
if (start === undefined) {
start = 0;
}
if (end === undefined) {
end = from.length;
}
to.splice(at, end - start, ...from.slice(start, end));
return to;
};
exports.vector_copyB = vector_copyB;
let vector_append = function (...args) {
return args.reduce((a, b) => a.concat(b), []);
};
exports.vector_append = vector_append;
let vector_fillB = function (v, fill) {
for (let i = 0; i < v.length; i++) {
v[i] = fill;
}
};
exports.vector_fillB = vector_fillB;
// Control features
let procedureQ = function (p) {
return typeof p === "function";
};
exports.procedureQ = procedureQ;
let apply = function (proc, ...args) {
if (!(0, exports.pairQ)(args[args.length - 1])) {
throw new Error("Last argument to apply must be a list");
}
let last = args.pop();
args = args.concat((0, exports.$list_to_array)(last));
return proc(...args);
};
exports.apply = apply;
let map = function (proc, ...args) {
const arg = [];
for (let j = 0; j < args.length; j++) {
if (args[j] === null) {
return null;
}
arg.push((0, exports.car)(args[j]));
args[j] = (0, exports.cdr)(args[j]);
}
return (0, exports.cons)(proc(...arg), (0, exports.map)(proc, ...args));
};
exports.map = map;
// Exception handling
let error = function (msg) {
throw new Error(msg);
};
exports.error = error;
// Environments and evaluation
// Input and output
let newline = function () {
console.log();
};
exports.newline = newline;
//# sourceMappingURL=scheme-base.js.map
;