Reader
This commit is contained in:
105
src/list.h
Normal file
105
src/list.h
Normal file
@ -0,0 +1,105 @@
|
||||
#ifndef INCLUDED_LIST_H
|
||||
#define INCLUDED_LIST_H
|
||||
|
||||
#include "argcountmacro.h"
|
||||
#include "base.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
DEFOBJTYPE(Cons, CONS, CONSP, {
|
||||
LispVal *car;
|
||||
LispVal *cdr;
|
||||
});
|
||||
|
||||
static ALWAYS_INLINE bool LISTP(LispVal *obj) {
|
||||
return NILP(obj) || CONSP(obj);
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE LispVal *CONS(LispVal *car, LispVal *cdr) {
|
||||
LispCons *obj = (LispCons *) lisp_alloc_object(sizeof(LispCons), TYPE_CONS);
|
||||
obj->car = car;
|
||||
obj->cdr = cdr;
|
||||
return obj;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE LispVal *XCAR(LispVal *cons) {
|
||||
assert(CONSP(cons) || NILP(cons));
|
||||
return NILP(cons) ? Qnil : ((LispCons *) cons)->car;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE LispVal *XCDR(LispVal *cons) {
|
||||
assert(CONSP(cons) || NILP(cons));
|
||||
return NILP(cons) ? Qnil : ((LispCons *) cons)->cdr;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE LispVal *XCAR_SAFE(LispVal *cons) {
|
||||
return CONSP(cons) ? XCAR(cons) : Qnil;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE LispVal *XCDR_SAFE(LispVal *cons) {
|
||||
return CONSP(cons) ? XCDR(cons) : Qnil;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void RPLACA(LispVal *cons, LispVal *newcar) {
|
||||
assert(CONSP(cons));
|
||||
((LispCons *) cons)->car = newcar;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void RPLACD(LispVal *cons, LispVal *newcdr) {
|
||||
assert(CONSP(cons));
|
||||
((LispCons *) cons)->cdr = newcdr;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE LispVal *LIST1(LispVal *v1) {
|
||||
return CONS(v1, Qnil);
|
||||
}
|
||||
static ALWAYS_INLINE LispVal *LIST2(LispVal *v1, LispVal *v2) {
|
||||
return CONS(v1, LIST1(v2));
|
||||
}
|
||||
static ALWAYS_INLINE LispVal *LIST3(LispVal *v1, LispVal *v2, LispVal *v3) {
|
||||
return CONS(v1, LIST2(v2, v3));
|
||||
}
|
||||
static ALWAYS_INLINE LispVal *LIST4(LispVal *v1, LispVal *v2, LispVal *v3,
|
||||
LispVal *v4) {
|
||||
return CONS(v1, LIST3(v2, v3, v4));
|
||||
}
|
||||
static ALWAYS_INLINE LispVal *LIST5(LispVal *v1, LispVal *v2, LispVal *v3,
|
||||
LispVal *v4, LispVal *v5) {
|
||||
return CONS(v1, LIST4(v2, v3, v4, v5));
|
||||
}
|
||||
static ALWAYS_INLINE LispVal *LIST6(LispVal *v1, LispVal *v2, LispVal *v3,
|
||||
LispVal *v4, LispVal *v5, LispVal *v6) {
|
||||
return CONS(v1, LIST5(v2, v3, v4, v5, v6));
|
||||
}
|
||||
static ALWAYS_INLINE LispVal *LIST_N(int count, ...) {
|
||||
va_list list;
|
||||
va_start(list, count);
|
||||
LispVal *acc = Qnil;
|
||||
LispVal *end;
|
||||
while (count--) {
|
||||
LispVal *next = CONS(va_arg(list, LispVal *), Qnil);
|
||||
if (NILP(acc)) {
|
||||
acc = next;
|
||||
end = acc;
|
||||
} else {
|
||||
RPLACD(end, next);
|
||||
end = next;
|
||||
}
|
||||
}
|
||||
va_end(list);
|
||||
return acc;
|
||||
}
|
||||
#define LIST(...) MACRO_CALLN(LIST, __VA_ARGS__)
|
||||
|
||||
#define FOREACH(l, v) \
|
||||
for (LispVal *_tail = (l), *v = XCAR(_tail); !NILP(_tail); \
|
||||
_tail = XCDR(_tail), v = XCAR(_tail))
|
||||
|
||||
#define FOREACH_TAIL(l, v) for (LispVal *v = (l); !NILP(v); v = XCDR_SAFE(v))
|
||||
|
||||
intptr_t list_length(LispVal *list);
|
||||
|
||||
DECLARE_FUNCTION(cons, (LispVal * car, LispVal *cdr));
|
||||
DECLARE_FUNCTION(length, (LispVal * list));
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user