/* Copyright (C) 2010, 2011 Tony Garnock-Jones. All rights reserved. */ #ifndef cmsg_sexp_h #define cmsg_sexp_h typedef struct sexp_data_t_ { refcount_t refcount; cmsg_bytes_t data; } sexp_data_t; typedef enum sexp_type_t_ { SEXP_BYTES, SEXP_SLICE, SEXP_DISPLAY_HINT, SEXP_PAIR } sexp_type_t; typedef struct sexp_t_ { refcount_t refcount; sexp_type_t kind; union { cmsg_bytes_t bytes; struct { sexp_data_t *data; size_t offset; size_t length; } slice; struct { struct sexp_t_ *head; struct sexp_t_ *tail; } pair; /* and display-hint */ } data; } sexp_t; extern sexp_t *sexp_empty_bytes; extern void init_sexp(void); extern void done_sexp(void); extern sexp_t *sexp_incref(sexp_t *x); extern sexp_t *sexp_decref(sexp_t *x); extern void sexp_data_destructor(sexp_data_t *data); extern void sexp_destructor(sexp_t *x); extern sexp_data_t *sexp_data_copy(cmsg_bytes_t body, size_t offset, size_t length); extern sexp_data_t *sexp_data_alias(cmsg_bytes_t body); extern sexp_t *sexp_cstring(char const *str); extern sexp_t *sexp_bytes(cmsg_bytes_t bytes); extern sexp_t *sexp_slice(sexp_data_t *data, size_t offset, size_t length); extern sexp_t *sexp_display_hint(sexp_t *hint, sexp_t *body); extern sexp_t *sexp_cons(sexp_t *head, sexp_t *tail); static inline int sexp_simple_stringp(sexp_t *x) { return (x != NULL) && ((x->kind == SEXP_BYTES) || (x->kind == SEXP_SLICE)); } static inline int sexp_stringp(sexp_t *x) { return sexp_simple_stringp(x) || ((x != NULL) && (x->kind == SEXP_DISPLAY_HINT)); } static inline int sexp_pairp(sexp_t *x) { return (x != NULL) && (x->kind == SEXP_PAIR); } extern cmsg_bytes_t sexp_data(sexp_t *x); extern int sexp_cmp(sexp_t *a, sexp_t *b); static inline sexp_t *sexp_head(sexp_t *x) { assert(x->kind == SEXP_PAIR); return x->data.pair.head; } static inline sexp_t *sexp_tail(sexp_t *x) { assert(x->kind == SEXP_PAIR); return x->data.pair.tail; } static inline sexp_t *sexp_hint(sexp_t *x) { assert(x->kind == SEXP_DISPLAY_HINT); return x->data.pair.head; } static inline sexp_t *sexp_body(sexp_t *x) { assert(x->kind == SEXP_DISPLAY_HINT); return x->data.pair.tail; } #define sexp_setter_(settername,fieldname) \ static inline sexp_t *settername(sexp_t *x, sexp_t *y) { \ sexp_t *old; \ assert(x->kind == SEXP_PAIR); \ INCREF(y); \ old = x->data.pair.fieldname; \ x->data.pair.fieldname = y; \ DECREF(old, sexp_destructor); \ return x; \ } sexp_setter_(sexp_sethead, head) sexp_setter_(sexp_settail, tail) static inline sexp_t *sexp_push(sexp_t *oldstack, sexp_t *val) { sexp_t *newstack = INCREF(sexp_cons(val, oldstack)); DECREF(oldstack, sexp_destructor); return newstack; } static inline sexp_t *sexp_pop(sexp_t *oldstack, sexp_t **valp) { sexp_t *nextstack = INCREF(sexp_tail(oldstack)); sexp_t *val = INCREF(sexp_head(oldstack)); DECREF(oldstack, sexp_destructor); UNGRAB(val); if (valp != NULL) { *valp = val; } return nextstack; } static inline int sexp_pseudo_pop(sexp_t **px) { *px = sexp_tail(*px); return sexp_pairp(*px); } static inline sexp_t *sexp_listtail(sexp_t *list, size_t dropcount) { while (dropcount) { list = sexp_tail(list); dropcount--; } return list; } static inline sexp_t *sexp_listref(sexp_t *list, size_t index) { return sexp_head(sexp_listtail(list, index)); } extern sexp_t *sexp_assoc(sexp_t *list, cmsg_bytes_t key); extern size_t sexp_length(sexp_t *list); extern sexp_t *sexp_new_queue(void); extern int sexp_queue_emptyp(sexp_t *q); extern void sexp_queue_pushback(sexp_t *q, sexp_t *x); extern void sexp_enqueue(sexp_t *q, sexp_t *x); extern sexp_t *sexp_dequeue(sexp_t *q); #endif