mirror of
https://github.com/kanaka/mal.git
synced 2024-11-10 12:47:45 +03:00
ES6: all optionals and self-hosting.
This commit is contained in:
parent
e5c4e656ba
commit
afa79313d8
39
es6/core.js
39
es6/core.js
@ -1,4 +1,7 @@
|
||||
import { _equal_Q, _list_Q, _clone, Sym, Atom } from './types';
|
||||
import { _equal_Q, _clone, _list_Q, _sequential_Q,
|
||||
_keyword, _keyword_Q, _vector, _vector_Q,
|
||||
_hash_map, _hash_map_Q, _assoc_BANG, _dissoc_BANG,
|
||||
Sym, Atom } from './types';
|
||||
import { pr_str } from './printer';
|
||||
import { readline } from './node_readline';
|
||||
import { read_str } from './reader';
|
||||
@ -47,7 +50,23 @@ function nth(lst, idx) {
|
||||
}
|
||||
|
||||
function conj(lst, ...args) {
|
||||
return b.slice(1).reverse().concat(lst);
|
||||
if (_list_Q(lst)) {
|
||||
return args.reverse().concat(lst);
|
||||
} else {
|
||||
return _vector(...lst.concat(args));
|
||||
}
|
||||
}
|
||||
|
||||
function keys(hm) {
|
||||
let ks = [];
|
||||
for (let k of hm.keys()) { ks.push(k) };
|
||||
return ks;
|
||||
}
|
||||
|
||||
function vals(hm) {
|
||||
let vs = [];
|
||||
for (let v of hm.values()) { vs.push(v) };
|
||||
return vs;
|
||||
}
|
||||
|
||||
// Metadata functions
|
||||
@ -65,11 +84,14 @@ function with_meta(obj, m) {
|
||||
export const core_ns = new Map([
|
||||
['=', _equal_Q],
|
||||
['throw', mal_throw],
|
||||
|
||||
['nil?', a => a === null],
|
||||
['true?', a => a === true],
|
||||
['false?', a => a === false],
|
||||
['symbol', a => new Sym(a)],
|
||||
['symbol?', a => a instanceof Sym],
|
||||
['keyword', a => _keyword(a)],
|
||||
['keyword?', a => _keyword_Q(a)],
|
||||
|
||||
['pr-str', do_pr_str],
|
||||
['str', str],
|
||||
@ -91,7 +113,18 @@ export const core_ns = new Map([
|
||||
|
||||
['list', (...a) => a],
|
||||
['list?', _list_Q],
|
||||
['vector', _vector],
|
||||
['vector?', _vector_Q],
|
||||
['hash-map', _hash_map],
|
||||
['map?', _hash_map_Q],
|
||||
['assoc', (m,...a) => _assoc_BANG(_clone(m), ...a)],
|
||||
['dissoc', (m,...a) => _dissoc_BANG(_clone(m), ...a)],
|
||||
['get', (m,a) => m === null ? null : m.has(a) ? m.get(a) : null],
|
||||
['contains?', (m,a) => m.has(a)],
|
||||
['keys', keys],
|
||||
['vals', vals],
|
||||
|
||||
['sequential?', _sequential_Q],
|
||||
['cons', (a,b) => [a].concat(b)],
|
||||
['concat', (...a) => a.reduce((x,y) => x.concat(y), [])],
|
||||
['nth', nth],
|
||||
@ -110,5 +143,5 @@ export const core_ns = new Map([
|
||||
['atom?', a => a instanceof Atom],
|
||||
['deref', atm => atm.val],
|
||||
['reset!', (atm,a) => atm.val = a],
|
||||
['swap!', (atm,f,args) => atm.val = f(...[atm.val].concat(args))]
|
||||
['swap!', (atm,f,...args) => atm.val = f(...[atm.val].concat(args))]
|
||||
]);
|
||||
|
@ -1,11 +1,20 @@
|
||||
import { Sym, Atom } from './types';
|
||||
import { Sym, _list_Q, _vector_Q, _hash_map_Q, Atom } from './types';
|
||||
|
||||
export function pr_str(obj, print_readably) {
|
||||
if (typeof print_readably === 'undefined') { print_readably = true; }
|
||||
var _r = print_readably;
|
||||
if (obj instanceof Array) {
|
||||
if (_list_Q(obj)) {
|
||||
var ret = obj.map(function(e) { return pr_str(e,_r); });
|
||||
return "(" + ret.join(' ') + ")";
|
||||
} else if (_vector_Q(obj)) {
|
||||
var ret = obj.map(function(e) { return pr_str(e,_r); });
|
||||
return "[" + ret.join(' ') + "]";
|
||||
} else if (_hash_map_Q(obj)) {
|
||||
var ret = [];
|
||||
for (let [k,v] of obj) {
|
||||
ret.push(pr_str(k,_r), pr_str(v,_r));
|
||||
}
|
||||
return "{" + ret.join(' ') + "}";
|
||||
} else if (typeof obj === "string") {
|
||||
if (obj[0] === '\u029e') {
|
||||
return ':' + obj.slice(1);
|
||||
@ -19,7 +28,7 @@ export function pr_str(obj, print_readably) {
|
||||
} else if (obj === null) {
|
||||
return "nil";
|
||||
} else if (obj instanceof Atom) {
|
||||
return "(atom " + obj.val + ")";
|
||||
return "(atom " + pr_str(obj.val,_r) + ")";
|
||||
} else {
|
||||
return obj.toString();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import * as types from './types';
|
||||
import { _symbol, _keyword, _vector, _hash_map } from './types';
|
||||
|
||||
export class BlankException extends Error {}
|
||||
|
||||
@ -34,7 +34,7 @@ function read_atom (reader) {
|
||||
.replace(/\\"/g, '"')
|
||||
.replace(/\\n/g, "\n"); // string
|
||||
} else if (token[0] === ":") {
|
||||
return types._keyword(token.slice(1));
|
||||
return _keyword(token.slice(1));
|
||||
} else if (token === "nil") {
|
||||
return null;
|
||||
} else if (token === "true") {
|
||||
@ -42,7 +42,7 @@ function read_atom (reader) {
|
||||
} else if (token === "false") {
|
||||
return false;
|
||||
} else {
|
||||
return types._symbol(token); // symbol
|
||||
return _symbol(token); // symbol
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,29 +65,47 @@ function read_list(reader, start, end) {
|
||||
return ast;
|
||||
}
|
||||
|
||||
// read vector of tokens
|
||||
function read_vector(reader) {
|
||||
return _vector(...read_list(reader, '[', ']'));
|
||||
}
|
||||
|
||||
// read hash-map key/value pairs
|
||||
function read_hash_map(reader) {
|
||||
return _hash_map(...read_list(reader, '{', '}'));
|
||||
}
|
||||
|
||||
function read_form(reader) {
|
||||
var token = reader.peek();
|
||||
switch (token) {
|
||||
// reader macros/transforms
|
||||
case ';': return null; // Ignore comments
|
||||
case '\'': reader.next();
|
||||
return [types._symbol('quote'), read_form(reader)];
|
||||
return [_symbol('quote'), read_form(reader)];
|
||||
case '`': reader.next();
|
||||
return [types._symbol('quasiquote'), read_form(reader)];
|
||||
return [_symbol('quasiquote'), read_form(reader)];
|
||||
case '~': reader.next();
|
||||
return [types._symbol('unquote'), read_form(reader)];
|
||||
return [_symbol('unquote'), read_form(reader)];
|
||||
case '~@': reader.next();
|
||||
return [types._symbol('splice-unquote'), read_form(reader)];
|
||||
return [_symbol('splice-unquote'), read_form(reader)];
|
||||
case '^': reader.next();
|
||||
var meta = read_form(reader);
|
||||
return [types._symbol('with-meta'), read_form(reader), meta];
|
||||
return [_symbol('with-meta'), read_form(reader), meta];
|
||||
case '@': reader.next();
|
||||
return [types._symbol('deref'), read_form(reader)];
|
||||
return [_symbol('deref'), read_form(reader)];
|
||||
|
||||
// list
|
||||
case ')': throw new Error("unexpected ')'");
|
||||
case '(': return read_list(reader);
|
||||
|
||||
// vector
|
||||
case ']': throw new Error("unexpected ']'");
|
||||
case '[': return read_vector(reader);
|
||||
|
||||
// hash-map
|
||||
case '}': throw new Error("unexpected '}'");
|
||||
case '{': return read_hash_map(reader);
|
||||
|
||||
// atom
|
||||
default: return read_atom(reader);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { readline } from './node_readline';
|
||||
import { Sym, _list_Q } from './types';
|
||||
import { Sym, _list_Q, _vector, _vector_Q, _hash_map_Q } from './types';
|
||||
import { BlankException, read_str } from './reader';
|
||||
import { pr_str } from './printer';
|
||||
|
||||
@ -16,6 +16,14 @@ const eval_ast = (ast, env) => {
|
||||
}
|
||||
} else if (_list_Q(ast)) {
|
||||
return ast.map((x) => EVAL(x, env));
|
||||
} else if (_vector_Q(ast)) {
|
||||
return _vector(...ast.map((x) => EVAL(x, env)));
|
||||
} else if (_hash_map_Q(ast)) {
|
||||
let new_hm = new Map();
|
||||
for (let [k, v] of ast) {
|
||||
new_hm.set(EVAL(k, env), EVAL(v, env));
|
||||
}
|
||||
return new_hm;
|
||||
} else {
|
||||
return ast;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { readline } from './node_readline';
|
||||
import { Sym, _list_Q } from './types';
|
||||
import { Sym, _list_Q, _vector, _vector_Q, _hash_map_Q } from './types';
|
||||
import { BlankException, read_str } from './reader';
|
||||
import { pr_str } from './printer';
|
||||
import { new_env, env_set, env_get } from './env';
|
||||
@ -13,6 +13,14 @@ const eval_ast = (ast, env) => {
|
||||
return env_get(env, ast)
|
||||
} else if (_list_Q(ast)) {
|
||||
return ast.map((x) => EVAL(x, env));
|
||||
} else if (_vector_Q(ast)) {
|
||||
return _vector(...ast.map((x) => EVAL(x, env)));
|
||||
} else if (_hash_map_Q(ast)) {
|
||||
let new_hm = new Map();
|
||||
for (let [k, v] of ast) {
|
||||
new_hm.set(EVAL(k, env), EVAL(v, env));
|
||||
}
|
||||
return new_hm;
|
||||
} else {
|
||||
return ast;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { readline } from './node_readline';
|
||||
import { Sym, _list_Q } from './types';
|
||||
import { Sym, _list_Q, _vector, _vector_Q, _hash_map_Q } from './types';
|
||||
import { BlankException, read_str } from './reader';
|
||||
import { pr_str } from './printer';
|
||||
import { new_env, env_set, env_get } from './env';
|
||||
@ -14,12 +14,21 @@ const eval_ast = (ast, env) => {
|
||||
return env_get(env, ast)
|
||||
} else if (_list_Q(ast)) {
|
||||
return ast.map((x) => EVAL(x, env));
|
||||
} else if (_vector_Q(ast)) {
|
||||
return _vector(...ast.map((x) => EVAL(x, env)));
|
||||
} else if (_hash_map_Q(ast)) {
|
||||
let new_hm = new Map();
|
||||
for (let [k, v] of ast) {
|
||||
new_hm.set(EVAL(k, env), EVAL(v, env));
|
||||
}
|
||||
return new_hm;
|
||||
} else {
|
||||
return ast;
|
||||
}
|
||||
}
|
||||
|
||||
const EVAL = (ast, env) => {
|
||||
//console.log("EVAL:", pr_str(ast, true));
|
||||
if (!_list_Q(ast)) { return eval_ast(ast, env) }
|
||||
|
||||
let [{ name: a0sym }, a1, a2, a3] = ast;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { readline } from './node_readline';
|
||||
import { Sym, _list_Q, _malfunc, _malfunc_Q } from './types';
|
||||
import { Sym, _list_Q, _vector, _vector_Q, _hash_map_Q,
|
||||
_malfunc, _malfunc_Q } from './types';
|
||||
import { BlankException, read_str } from './reader';
|
||||
import { pr_str } from './printer';
|
||||
import { new_env, env_set, env_get } from './env';
|
||||
@ -14,6 +15,14 @@ const eval_ast = (ast, env) => {
|
||||
return env_get(env, ast)
|
||||
} else if (_list_Q(ast)) {
|
||||
return ast.map((x) => EVAL(x, env));
|
||||
} else if (_vector_Q(ast)) {
|
||||
return _vector(...ast.map((x) => EVAL(x, env)));
|
||||
} else if (_hash_map_Q(ast)) {
|
||||
let new_hm = new Map();
|
||||
for (let [k, v] of ast) {
|
||||
new_hm.set(EVAL(k, env), EVAL(v, env));
|
||||
}
|
||||
return new_hm;
|
||||
} else {
|
||||
return ast;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { readline } from './node_readline';
|
||||
import { Sym, _list_Q, _malfunc, _malfunc_Q } from './types';
|
||||
import { Sym, _list_Q, _vector, _vector_Q, _hash_map_Q,
|
||||
_malfunc, _malfunc_Q } from './types';
|
||||
import { BlankException, read_str } from './reader';
|
||||
import { pr_str } from './printer';
|
||||
import { new_env, env_set, env_get } from './env';
|
||||
@ -14,6 +15,14 @@ const eval_ast = (ast, env) => {
|
||||
return env_get(env, ast)
|
||||
} else if (_list_Q(ast)) {
|
||||
return ast.map((x) => EVAL(x, env));
|
||||
} else if (_vector_Q(ast)) {
|
||||
return _vector(...ast.map((x) => EVAL(x, env)));
|
||||
} else if (_hash_map_Q(ast)) {
|
||||
let new_hm = new Map();
|
||||
for (let [k, v] of ast) {
|
||||
new_hm.set(EVAL(k, env), EVAL(v, env));
|
||||
}
|
||||
return new_hm;
|
||||
} else {
|
||||
return ast;
|
||||
}
|
||||
@ -82,7 +91,7 @@ REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\"))
|
||||
|
||||
if (process.argv.length > 2) {
|
||||
env_set(repl_env, '*ARGV*', process.argv.slice(3));
|
||||
REPL('(load-file "' + process.argv[2] + '")');
|
||||
REP('(load-file "' + process.argv[2] + '")');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { readline } from './node_readline';
|
||||
import { Sym, _list_Q, _malfunc, _malfunc_Q, _sequential_Q } from './types';
|
||||
import { Sym, _list_Q, _vector, _vector_Q, _hash_map_Q, _sequential_Q,
|
||||
_malfunc, _malfunc_Q } from './types';
|
||||
import { BlankException, read_str } from './reader';
|
||||
import { pr_str } from './printer';
|
||||
import { new_env, env_set, env_get } from './env';
|
||||
@ -28,6 +29,14 @@ const eval_ast = (ast, env) => {
|
||||
return env_get(env, ast)
|
||||
} else if (_list_Q(ast)) {
|
||||
return ast.map((x) => EVAL(x, env));
|
||||
} else if (_vector_Q(ast)) {
|
||||
return _vector(...ast.map((x) => EVAL(x, env)));
|
||||
} else if (_hash_map_Q(ast)) {
|
||||
let new_hm = new Map();
|
||||
for (let [k, v] of ast) {
|
||||
new_hm.set(EVAL(k, env), EVAL(v, env));
|
||||
}
|
||||
return new_hm;
|
||||
} else {
|
||||
return ast;
|
||||
}
|
||||
@ -101,7 +110,7 @@ REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\"))
|
||||
|
||||
if (process.argv.length > 2) {
|
||||
env_set(repl_env, '*ARGV*', process.argv.slice(3));
|
||||
REPL('(load-file "' + process.argv[2] + '")');
|
||||
REP('(load-file "' + process.argv[2] + '")');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { readline } from './node_readline';
|
||||
import { Sym, _list_Q, _malfunc, _malfunc_Q, _sequential_Q } from './types';
|
||||
import { Sym, _list_Q, _vector, _vector_Q, _hash_map_Q, _sequential_Q,
|
||||
_malfunc, _malfunc_Q } from './types';
|
||||
import { BlankException, read_str } from './reader';
|
||||
import { pr_str } from './printer';
|
||||
import { new_env, env_set, env_get } from './env';
|
||||
@ -44,6 +45,14 @@ const eval_ast = (ast, env) => {
|
||||
return env_get(env, ast)
|
||||
} else if (_list_Q(ast)) {
|
||||
return ast.map((x) => EVAL(x, env));
|
||||
} else if (_vector_Q(ast)) {
|
||||
return _vector(...ast.map((x) => EVAL(x, env)));
|
||||
} else if (_hash_map_Q(ast)) {
|
||||
let new_hm = new Map();
|
||||
for (let [k, v] of ast) {
|
||||
new_hm.set(EVAL(k, env), EVAL(v, env));
|
||||
}
|
||||
return new_hm;
|
||||
} else {
|
||||
return ast;
|
||||
}
|
||||
@ -128,7 +137,7 @@ REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first x
|
||||
|
||||
if (process.argv.length > 2) {
|
||||
env_set(repl_env, '*ARGV*', process.argv.slice(3));
|
||||
REPL('(load-file "' + process.argv[2] + '")');
|
||||
REP('(load-file "' + process.argv[2] + '")');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { readline } from './node_readline';
|
||||
import { Sym, _list_Q, _malfunc, _malfunc_Q, _sequential_Q } from './types';
|
||||
import { Sym, _list_Q, _vector, _vector_Q, _hash_map_Q, _sequential_Q,
|
||||
_malfunc, _malfunc_Q } from './types';
|
||||
import { BlankException, read_str } from './reader';
|
||||
import { pr_str } from './printer';
|
||||
import { new_env, env_set, env_get } from './env';
|
||||
@ -44,6 +45,14 @@ const eval_ast = (ast, env) => {
|
||||
return env_get(env, ast)
|
||||
} else if (_list_Q(ast)) {
|
||||
return ast.map((x) => EVAL(x, env));
|
||||
} else if (_vector_Q(ast)) {
|
||||
return _vector(...ast.map((x) => EVAL(x, env)));
|
||||
} else if (_hash_map_Q(ast)) {
|
||||
let new_hm = new Map();
|
||||
for (let [k, v] of ast) {
|
||||
new_hm.set(EVAL(k, env), EVAL(v, env));
|
||||
}
|
||||
return new_hm;
|
||||
} else {
|
||||
return ast;
|
||||
}
|
||||
@ -139,7 +148,7 @@ REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first x
|
||||
|
||||
if (process.argv.length > 2) {
|
||||
env_set(repl_env, '*ARGV*', process.argv.slice(3));
|
||||
REPL('(load-file "' + process.argv[2] + '")');
|
||||
REP('(load-file "' + process.argv[2] + '")');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { readline } from './node_readline';
|
||||
import { Sym, _list_Q, _malfunc, _malfunc_Q, _sequential_Q } from './types';
|
||||
import { Sym, _list_Q, _vector, _vector_Q, _hash_map_Q, _sequential_Q,
|
||||
_malfunc, _malfunc_Q } from './types';
|
||||
import { BlankException, read_str } from './reader';
|
||||
import { pr_str } from './printer';
|
||||
import { new_env, env_set, env_get } from './env';
|
||||
@ -44,6 +45,14 @@ const eval_ast = (ast, env) => {
|
||||
return env_get(env, ast)
|
||||
} else if (_list_Q(ast)) {
|
||||
return ast.map((x) => EVAL(x, env));
|
||||
} else if (_vector_Q(ast)) {
|
||||
return _vector(...ast.map((x) => EVAL(x, env)));
|
||||
} else if (_hash_map_Q(ast)) {
|
||||
let new_hm = new Map();
|
||||
for (let [k, v] of ast) {
|
||||
new_hm.set(EVAL(k, env), EVAL(v, env));
|
||||
}
|
||||
return new_hm;
|
||||
} else {
|
||||
return ast;
|
||||
}
|
||||
@ -140,7 +149,7 @@ REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first x
|
||||
|
||||
if (process.argv.length > 2) {
|
||||
env_set(repl_env, '*ARGV*', process.argv.slice(3));
|
||||
REPL('(load-file "' + process.argv[2] + '")');
|
||||
REP('(load-file "' + process.argv[2] + '")');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
102
es6/types.js
102
es6/types.js
@ -1,11 +1,12 @@
|
||||
// General functions
|
||||
|
||||
//function _sequential_Q(lst) { return _list_Q(lst) || _vector_Q(lst); }
|
||||
export const _sequential_Q = (lst) => _list_Q(lst)
|
||||
export const _sequential_Q = lst => _list_Q(lst) || _vector_Q(lst)
|
||||
|
||||
export function _obj_type(obj) {
|
||||
if (obj instanceof Sym) { return 'symbol'; }
|
||||
else if (_list_Q(obj)) { return 'list'; }
|
||||
else if (_vector_Q(obj)) { return 'vector'; }
|
||||
else if (_hash_map_Q(obj)) { return 'hash-map'; }
|
||||
else if (obj === null) { return 'nil'; }
|
||||
else if (obj === true) { return 'true'; }
|
||||
else if (obj === false) { return 'false'; }
|
||||
@ -19,21 +20,8 @@ export function _obj_type(obj) {
|
||||
}
|
||||
}
|
||||
|
||||
export function _clone(obj) {
|
||||
if (obj instanceof Sym) {
|
||||
return new Sym(obj.name);
|
||||
} else if (_list_Q(obj)) {
|
||||
return obj.slice(0);
|
||||
} else if (obj instanceof Function) {
|
||||
return obj.clone();
|
||||
} else {
|
||||
throw Error("Unsupported type for clone");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function _equal_Q (a, b) {
|
||||
var ota = _obj_type(a), otb = _obj_type(b);
|
||||
let ota = _obj_type(a), otb = _obj_type(b);
|
||||
if (!(ota === otb || (_sequential_Q(a) && _sequential_Q(b)))) {
|
||||
return false;
|
||||
}
|
||||
@ -42,24 +30,40 @@ export function _equal_Q (a, b) {
|
||||
case 'list':
|
||||
case 'vector':
|
||||
if (a.length !== b.length) { return false; }
|
||||
for (var i=0; i<a.length; i++) {
|
||||
for (let i=0; i<a.length; i++) {
|
||||
if (! _equal_Q(a[i], b[i])) { return false; }
|
||||
}
|
||||
return true;
|
||||
// case 'hash-map':
|
||||
// var akeys = Object.keys(a).sort(),
|
||||
// bkeys = Object.keys(b).sort();
|
||||
// if (akeys.length !== bkeys.length) { return false; }
|
||||
// for (var i=0; i<akeys.length; i++) {
|
||||
// if (akeys[i] !== bkeys[i]) { return false; }
|
||||
// if (! equal_Q(a[akeys[i]], b[bkeys[i]])) { return false; }
|
||||
// }
|
||||
// return true;
|
||||
case 'hash-map':
|
||||
let akeys = Object.keys(a).sort(),
|
||||
bkeys = Object.keys(b).sort();
|
||||
if (akeys.length !== bkeys.length) { return false; }
|
||||
for (let i=0; i<akeys.length; i++) {
|
||||
if (akeys[i] !== bkeys[i]) { return false; }
|
||||
if (! _equal_Q(a.get(akeys[i]), b.get(bkeys[i]))) { return false; }
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return a === b;
|
||||
}
|
||||
}
|
||||
|
||||
export function _clone(obj) {
|
||||
if (obj instanceof Sym) {
|
||||
return new Sym(obj.name);
|
||||
} else if (_list_Q(obj)) {
|
||||
return obj.slice(0);
|
||||
} else if (_vector_Q(obj)) {
|
||||
return _vector(...obj.slice(0));
|
||||
} else if (_hash_map_Q(obj)) {
|
||||
return new Map(obj.entries());
|
||||
} else if (obj instanceof Function) {
|
||||
return obj.clone();
|
||||
} else {
|
||||
throw Error("Unsupported type for clone");
|
||||
}
|
||||
}
|
||||
|
||||
// Functions
|
||||
export function _malfunc(f, ast, env, params) {
|
||||
f.ast = ast;
|
||||
@ -72,9 +76,9 @@ export function _malfunc(f, ast, env, params) {
|
||||
}
|
||||
export const _malfunc_Q = f => f.ast ? true : false;
|
||||
Function.prototype.clone = function() {
|
||||
var that = this;
|
||||
var temp = function () { return that.apply(this, arguments); };
|
||||
for( let key in this ) {
|
||||
let that = this;
|
||||
let temp = function () { return that.apply(this, arguments); };
|
||||
for (let key in this ) {
|
||||
if (this.hasOwnProperty(key)) {
|
||||
temp[key] = this[key];
|
||||
}
|
||||
@ -92,9 +96,49 @@ export class Sym {
|
||||
export const _symbol = name => new Sym(name);
|
||||
export const _symbol_Q = obj => obj instanceof Sym;
|
||||
|
||||
// Keywords
|
||||
export const _keyword = obj => _keyword_Q(obj) ? obj : "\u029e" + obj;
|
||||
export const _keyword_Q = obj => typeof obj === 'string' && obj[0] === '\u029e';
|
||||
|
||||
// Lists
|
||||
export const _list_Q = obj => Array.isArray(obj) && !obj.__isvector__;
|
||||
|
||||
// Vectors
|
||||
export function _vector(...args) {
|
||||
let v = args.slice(0);
|
||||
v.__isvector__ = true;
|
||||
return v;
|
||||
}
|
||||
export const _vector_Q = obj => Array.isArray(obj) && !!obj.__isvector__
|
||||
|
||||
// Hash Maps
|
||||
export function _hash_map(...args) {
|
||||
if (args % 2 === 1) {
|
||||
throw new Error("Odd number of hash map arguments");
|
||||
}
|
||||
return _assoc_BANG(new Map(), ...args);
|
||||
}
|
||||
export const _hash_map_Q = hm => hm instanceof Map;
|
||||
export function _assoc_BANG(hm, ...args) {
|
||||
if (args % 2 === 1) {
|
||||
throw new Error("Odd number of assoc arguments");
|
||||
}
|
||||
for (let i=0; i<args.length; i+=2) {
|
||||
if (typeof args[i] !== "string") {
|
||||
throw new Error("expected hash-map key string, got: " + (typeof args[i]));
|
||||
}
|
||||
hm.set(args[i], args[i+1]);
|
||||
}
|
||||
return hm;
|
||||
}
|
||||
export function _dissoc_BANG(hm, ...args) {
|
||||
for (let i=0; i<args.length; i++) {
|
||||
hm.delete(args[i]);
|
||||
}
|
||||
return hm;
|
||||
}
|
||||
|
||||
|
||||
// Atoms
|
||||
export class Atom {
|
||||
constructor(val) { this.val = val; }
|
||||
|
Loading…
Reference in New Issue
Block a user