129 lines
3.8 KiB
C
129 lines
3.8 KiB
C
#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;
|
|
MARK_OBJECT_ADDED(newcar, cons);
|
|
}
|
|
|
|
static ALWAYS_INLINE void RPLACD(LispVal *cons, LispVal *newcdr) {
|
|
assert(CONSP(cons));
|
|
((LispCons *) cons)->cdr = newcdr;
|
|
MARK_OBJECT_ADDED(newcdr, cons);
|
|
}
|
|
|
|
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 FIRST(x) XCAR(x)
|
|
#define SECOND(x) XCAR(XCDR(x))
|
|
#define THIRD(x) XCAR(XCDR(XCDR(x)))
|
|
#define FOURTH(x) XCAR(XCDR(XCDR(XCDR(x))))
|
|
#define FIFTH(x) XCAR(XCDR(XCDR(XCDR(XCDR(x)))))
|
|
|
|
#define DOLIST(v, l) \
|
|
for (LispVal *_tail = (l), *v = XCAR(_tail); !NILP(_tail); \
|
|
_tail = XCDR(_tail), v = XCAR(_tail))
|
|
|
|
#define DOTAILS(v, l) for (LispVal *v = (l); !NILP(v); v = XCDR_SAFE(v))
|
|
|
|
// return -1 list is circular
|
|
intptr_t list_length(LispVal *list);
|
|
// Return true if the length of LIST == SIZE
|
|
bool list_length_eq(LispVal *list, intptr_t size);
|
|
|
|
DECLARE_FUNCTION(cons, (LispVal * car, LispVal *cdr));
|
|
DECLARE_FUNCTION(length, (LispVal * list));
|
|
DECLARE_FUNCTION(length_eq, (LispVal * list, LispVal *length));
|
|
DECLARE_FUNCTION(nreverse, (LispVal * list));
|
|
DECLARE_FUNCTION(listp, (LispVal * obj));
|
|
DECLARE_FUNCTION(list, (LispVal * args));
|
|
static ALWAYS_INLINE void CHECK_LISTP(LispVal *obj) {
|
|
if (!LISTP(obj)) {
|
|
signal_type_error(obj, LIST(Qlist));
|
|
}
|
|
}
|
|
|
|
DECLARE_FUNCTION(plist_put, (LispVal * plist, LispVal *prop, LispVal *value));
|
|
DECLARE_FUNCTION(plist_get, (LispVal * plist, LispVal *prop, LispVal *def));
|
|
|
|
#endif
|