#ifndef INCLUDED_LIST_H #define INCLUDED_LIST_H #include "argcountmacro.h" #include "base.h" #include 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