82 lines
2.1 KiB
CoffeeScript
82 lines
2.1 KiB
CoffeeScript
|
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
|