cons-lists/src/lists.coffee

82 lines
2.1 KiB
CoffeeScript
Raw Normal View History

2015-05-13 23:20:16 +00:00
vectorp = (a) -> toString.call(a) == '[object Array]'
cellp = (a) -> vectorp(a) and a.__list == true
pairp = (a) -> cellp(a) and (a.length == 2)
listp = (a) -> (pairp a) and (pairp cdr a)
recordp = (a) -> Object.prototype.toString.call(a) == '[object Object]'
nilp = (a) -> cellp(a) and a.length == 0
nil = (-> l = []; l.__list = true; l)()
cons = (a, b = nil) ->
l = if not (a?) then [] else if (nilp a) then b else [a, b]
l.__list = true
l
car = (a) -> a[0]
cdr = (a) -> a[1]
vectorToList = (v, p) ->
p = if p? then p else 0
if p >= v.length then return nil
# Annoying, but since lists are represented as nested arrays, they
# have to be intercepted first. The use of duck-typing here is
# frustrating, but I suppose the eventual runtime will be doing
# something like this anyway for base types.
item = if pairp(v[p]) then v[p] else if vectorp(v[p]) then vectorToList(v[p]) else v[p]
cons(item, vectorToList(v, p + 1))
list = (v...) ->
ln = v.length;
(nl = (a) ->
cons(v[a], if (a < ln) then (nl(a + 1)) else nil))(0)
listToVector = (l, v = []) ->
return v if nilp l
v.push if pairp (car l) then listToVector(car l) else (car l)
listToVector (cdr l), v
# This is the simplified version. It can't be used stock with reader,
# because read() returns a rich version decorated with extra
# information.
metacadr = (m) ->
seq = m.match(/c([ad]+)r/)[1].split('')
return (l) ->
inner = (l, s) ->
return nil if nilp l
return l if s.length == 0
inner ((if s.pop() == 'a' then car else cdr)(l)), s
inner(l, seq)
module.exports =
cons: cons
nil: nil
car: car
cdr: cdr
list: list
nilp: nilp
pairp: pairp
vectorp: vectorp
recordp: recordp
vectorToList: vectorToList
listToVector: listToVector
setcar: (a, l) -> l[0] = a; a
setcdr: (a, l) -> l[1] = a; a
cadr: (l) -> car (cdr l)
cddr: (l) -> cdr (cdr l)
cdar: (l) -> cdr (car l)
caar: (l) -> car (car l)
caddr: (l) -> car (cdr (cdr l))
cdddr: (l) -> cdr (cdr (cdr l))
cadar: (l) -> car (cdr (car l))
cddar: (l) -> cdr (cdr (car l))
caadr: (l) -> car (car (cdr l))
cdadr: (l) -> cdr (car (cdr l))
metacadr: metacadr