Files
glisp/src/list.h

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