elisp.js/elisp/list.js

126 lines
No EOL
3 KiB
JavaScript

////
// Emacs Lisp implementation in JavaScript.
//
// Copyright (c) 2009 Sami Samhuri - sami.samhuri@gmail.com
//
// Released under the terms of the MIT license. See the included file
// LICENSE.
var type = require('elisp/types'),
utils = require('elisp/utils'),
LispCons = type.LispCons,
NIL = type.NIL;
LispCons.prototype.car = function() {
// print('[LispCons.car] calling this.isNil - this: ' + this + ' - _car: ' + this._car);
// print('------');
// print('' + this._tag);
// print('------');
// print('car: ' + this._car._tag);
// print('------');
// print('cdr: ' + this._cdr._tag);
// print('------');
//utils.pp(this);
return this.isNil() ? this : this._car;
};
LispCons.prototype.cdr = function() {
// print('[LispCons.cdr] calling this.isNil - this: ' + this + ' - _cdr: ' + this._cdr);
return this.isNil() ? this : this._cdr;
};
LispCons.prototype.cadr = function() {
return this.cdr().car();
};
LispCons.prototype.caddr = function() {
return this.cdr().cdr().car();
};
LispCons.prototype.cadddr = function() {
return this.cdr().cdr().cdr().car();
};
LispCons.prototype.length = function() {
return this._length;
};
LispCons.prototype.last = function() {
var last,
cons = this;
// print('[LispCons.last] calling cons.isNil - cons: ' + cons + ' - _cdr: ' + cons._cdr);
while (!cons.isNil()) {
last = cons;
cons = cons.cdr();
}
return last.car();
};
LispCons.prototype.map = function(fn) {
var list = [],
i = 0,
cons = this;
// print('[LispCons.map] calling cons.isNil - cons: ' + cons + ' - _car: ' + cons._car + ' _cdr: ' + this._cdr);
while (!cons.isNil()) {
list.push(fn(cons.car(), i));
cons = cons.cdr();
++i;
}
return list.length > 0 ? type.mkList(list) : type.NIL;
};
LispCons.prototype.reduce = function(accum, fn) {
var i = 0,
n = this._length;
while (i < n) {
accum = fn(accum, this.nth(i++));
}
return accum;
};
LispCons.prototype.unlist = function() {
return this.reduce([], function(x){return x;});
};
LispCons.prototype.nth = function(n) {
var i = 0,
e,
cons = this;
// print('[LispCons.nth] calling cons.isNil - cons: ' + cons + ' - _cdr: ' + cons._cdr);
while (i <= n && !cons.isNil()) {
e = cons.car();
cons = cons.cdr();
++i;
}
return n > --i ? type.NIL : e;
};
LispCons.prototype.nthcdr = function(n) {
var e = this.cdr(),
i = 0;
// print('[LispCons.nthcdr] calling e.isNil - e: ' + e + ' - _cdr: ' + e._cdr);
while (i < n && !e.isNil()) {
e = e.cdr();
++i;
}
return n > i ? type.NIL : e;
};
// Make NIL act like a list ... there's got to be a better way
NIL.unlist = function(){return [];};
NIL._length = 0;
NIL.length = function(){return 0;};
NIL.reduce = function(accum){return accum;};
nilMethods = ['car', 'cdr', 'cadr', 'caddr', 'cadddr',
'last', 'map', 'nthcdr', 'nth'];
var nilFn = function(){return NIL;};
for (var method in nilMethods) {
NIL[method] = nilFn;
}