diff --git a/elisp/list.js b/elisp/list.js index 42582f9..4cc65ca 100644 --- a/elisp/list.js +++ b/elisp/list.js @@ -83,43 +83,22 @@ LispCons.prototype.unlist = function() { LispCons.prototype.nth = function(n) { var i = 0, - e, - cons = this; -// print('[LispCons.nth] calling cons.isNil - cons: ' + cons + ' - _cdr: ' + cons._cdr); + cons = this, + e = cons.car(); while (i <= n && !cons.isNil()) { e = cons.car(); cons = cons.cdr(); ++i; } - return n > (i-1) ? type.NIL : e; + return 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()) { + var e = this, + i = 1; + while (i <= n && !e.isNil()) { e = e.cdr(); ++i; } - return n > i ? type.NIL : e; + return 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; -} \ No newline at end of file diff --git a/elisp/primitives.js b/elisp/primitives.js index 1e87d48..7328c09 100644 --- a/elisp/primitives.js +++ b/elisp/primitives.js @@ -46,19 +46,63 @@ var notFunc = function(fn) { }; exports.notFunc = notFunc; -var makePrimitiveBooleanFunc = function(fn) { +var makeBooleanFunc = function(fn) { return function(x){ return x[fn]() ? type.T : type.NIL; }; }; -exports.makePrimitiveBooleanFunc = makePrimitiveBooleanFunc; +exports.makeBooleanFunc = makeBooleanFunc; + +// TODO FIXME make NIL act like the empty list +var makeNilFn = function(fn) { + return function(arg){ return arg.isNil() ? arg : arg[fn](); }; +}; + +var makeZeroFn = function(fn) { + return function(arg){ return arg.isNil() ? new type.LispNumber(0) : arg[fn](); }; +}; init.hook('Define Primitive Variables and Functions', function() { - var type = require('elisp/types'); - definePrimitive('consp', ['symbol'], makePrimitiveBooleanFunc('isCons'), - "Return T if symbol is a cons, nil otherwise."); + + definePrimitive('consp', ['symbol'], makeBooleanFunc('isCons'), + "Return t if symbol is a cons, nil otherwise."); - definePrimitive('atom', ['symbol'], makePrimitiveBooleanFunc('isAtom'), - "Return T if symbol is not a cons or is nil, nil otherwise."); + definePrimitive('atom', ['symbol'], makeBooleanFunc('isAtom'), + "Return t if symbol is not a cons or is nil, nil otherwise."); + + +// list functions + definePrimitive('car', ['arg'], makeNilFn('car'), + "Return the car of list. If arg is nil, return nil. \ +Error if arg is not nil and not a cons cell."); + + definePrimitive('cdr', ['arg'], makeNilFn('cdr'), + "Return the cdr of list. If arg is nil, return nil. \ +Error if arg is not nil and not a cons cell."); + + definePrimitive('nth', ['n', 'arg'], function(n, arg){ + return arg.isNil() ? arg : arg.nth(n.value()); + }, "Return the nth element of list. \ +n counts from zero. If list is not that long, nil is returned."); + + definePrimitive('nthcdr', ['n', 'arg'], function(n, arg){ + return arg.isNil() ? arg : arg.nthcdr(n.value()); + }, "Take cdr n times on list, returns the result."); + + definePrimitive('cadr', ['arg'], makeNilFn('cadr'), + "Return the car of the cdr of x."); + + definePrimitive('caddr', ['arg'], makeNilFn('caddr'), + "Return the car of the cdr of the cdr of x."); + + definePrimitive('cadddr', ['arg'], makeNilFn('cadddr'), + "Return the car of the cdr of the cdr of the cdr of x."); + +////////// +///// FIXME new symbol table! this makes the current one barf, because it sucks +///// +// definePrimitive('length', ['arg'], makeZeroFn('length'), +// "Return the length of list."); + definePrimitive('symbol-name', ['symbol'], function(symbol) { return new type.LispString(symbol.symbolName()); }, "Return a symbol's name, a string.");