diff options
Diffstat (limited to 'any_sexp.h')
| -rw-r--r-- | any_sexp.h | 127 |
1 files changed, 92 insertions, 35 deletions
@@ -33,7 +33,9 @@ typedef enum { ANY_SEXP_TAG_NIL = 0, ANY_SEXP_TAG_CONS = 1 << 0, ANY_SEXP_TAG_SYMBOL = 1 << 1, +#ifndef ANY_SEXP_NO_STRING ANY_SEXP_TAG_STRING = 1 << 2, +#endif } any_sexp_tag_t; #ifdef ANY_SEXP_NO_BOXING @@ -52,7 +54,10 @@ typedef struct any_sexp { #define ANY_SEXP_GET_TAG(sexp) ((sexp).tag) #define ANY_SEXP_GET_CONS(sexp) ((sexp).cons) #define ANY_SEXP_GET_SYMBOL(sexp) ((sexp).symbol) + +#ifndef ANY_SEXP_NO_STRING #define ANY_SEXP_GET_STRING(sexp) ((sexp).symbol) +#endif #else @@ -68,7 +73,10 @@ typedef void *any_sexp_t; #define ANY_SEXP_GET_TAG(sexp) (((uintptr_t)(sexp) >> ANY_SEXP_BITS_SHIFT) & 0xf) #define ANY_SEXP_GET_CONS(sexp) ((any_sexp_cons_t *)ANY_SEXP_UNTAG(sexp)) #define ANY_SEXP_GET_SYMBOL(sexp) (((char *)ANY_SEXP_UNTAG(sexp))) + +#ifndef ANY_SEXP_NO_STRING #define ANY_SEXP_GET_STRING(sexp) (((char *)ANY_SEXP_UNTAG(sexp))) +#endif #endif @@ -85,9 +93,9 @@ typedef struct any_sexp_cons { any_sexp_t cdr; } any_sexp_cons_t; -typedef char (*any_sexp_getchar_t)(void *stream); +typedef int (*any_sexp_getchar_t)(void *stream); -typedef int (*any_sexp_fprintf_t)(void *stream, const char *format, ...); +typedef int (*any_sexp_putchar_t)(int c, FILE *stream); #ifndef ANY_SEXP_NO_READER @@ -98,7 +106,7 @@ typedef int (*any_sexp_fprintf_t)(void *stream, const char *format, ...); typedef struct { any_sexp_getchar_t getc; void *stream; - char c; + int c; } any_sexp_reader_t; typedef struct { @@ -120,11 +128,11 @@ any_sexp_t any_sexp_read(any_sexp_reader_t *reader); #ifndef ANY_SEXP_NO_WRITER typedef struct { - any_sexp_fprintf_t fprintf; + any_sexp_putchar_t putc; void *stream; } any_sexp_writer_t; -void any_sexp_writer_init(any_sexp_writer_t *writer, any_sexp_fprintf_t fprintf, void *stream); +void any_sexp_writer_init(any_sexp_writer_t *writer, any_sexp_putchar_t putc, void *stream); int any_sexp_write(any_sexp_writer_t *writer, any_sexp_t sexp); @@ -140,8 +148,12 @@ any_sexp_t any_sexp_nil(void); any_sexp_t any_sexp_symbol(char *symbol, size_t length); +#ifndef ANY_SEXP_NO_STRING + any_sexp_t any_sexp_string(char *string, size_t length); +#endif + any_sexp_t any_sexp_quote(any_sexp_t sexp); any_sexp_t any_sexp_cons(any_sexp_t car, any_sexp_t cdr); @@ -362,9 +374,19 @@ any_sexp_t any_sexp_read(any_sexp_reader_t *reader) #ifndef ANY_SEXP_NO_WRITER -void any_sexp_writer_init(any_sexp_writer_t *writer, any_sexp_fprintf_t fprintf, void *stream) +static int any_sexp_writer_puts(any_sexp_writer_t *writer, const char *string) +{ + int i; + for (i = 0; string[i] != '\0', i++) { + if (writer->putc(string[i], writer->stream) == EOF) + return EOF; + } + return i; +} + +void any_sexp_writer_init(any_sexp_writer_t *writer, any_sexp_putchar_t putc, void *stream) { - writer->fprintf = fprintf; + writer->putc = putc; writer->stream = stream; } @@ -372,36 +394,64 @@ int any_sexp_write(any_sexp_writer_t *writer, any_sexp_t sexp) { switch (ANY_SEXP_GET_TAG(sexp)) { case ANY_SEXP_TAG_ERROR: - return writer->fprintf(writer->stream, "<error>"); + return any_sexp_writer_puts(writer, "<error>"); case ANY_SEXP_TAG_NIL: - return writer->fprintf(writer->stream, "()"); + return writer->putc(ANY_SEXP_CHAR_OPEN, writer->stream) == EOF + || writer->putc(ANY_SEXP_CHAR_CLOSE, writer->stream) == EOF + ? EOF : 2; case ANY_SEXP_TAG_CONS: { - int c = writer->fprintf(writer->stream, "("); + if (writer->putc(ANY_SEXP_CHAR_OPEN, writer->stream) == EOF) + return EOF; + + int c = 2, tmp; while (!ANY_SEXP_IS_NIL(sexp) && !ANY_SEXP_IS_ERROR(sexp)) { - c += any_sexp_write(writer, any_sexp_car(sexp)); + tmp = any_sexp_write(writer, any_sexp_car(sexp)); sexp = any_sexp_cdr(sexp); - if (!ANY_SEXP_IS_NIL(sexp)) - c += writer->fprintf(writer->stream, " "); + if (tmp == EOF) + return EOF; + + if (!ANY_SEXP_IS_NIL(sexp)) { + if (writer->putc(' ', writer->stream) == EOF) + return EOF; + tmp++; + } + c += tmp; } - c += writer->fprintf(writer->stream, ")"); + + if (writer->putc(ANY_SEXP_CHAR_CLOSE, writer->stream) == EOF) + return EOF; + return c; } case ANY_SEXP_TAG_SYMBOL: - return writer->fprintf(writer->stream, "%s", ANY_SEXP_GET_SYMBOL(sexp)); + return any_sexp_writer_puts(writer, ANY_SEXP_GET_SYMBOL(sexp)); - case ANY_SEXP_TAG_STRING: - return writer->fprintf(writer->stream, "\"%s\"", ANY_SEXP_GET_STRING(sexp)); +#ifndef ANY_SEXP_NO_STRING + case ANY_SEXP_TAG_STRING: { + if (writer->putc(ANY_SEXP_CHAR_STRING, writer->stream) == EOF) + return EOF; + + int c = any_sexp_writer_puts(writer, ANY_SEXP_GET_STRING(sexp)); + if (c == EOF) + return EOF; + + if (writer->putc(ANY_SEXP_CHAR_STRING, writer->stream) == EOF) + return EOF; + + return c + 2; + } +#endif } } int any_sexp_fprint(any_sexp_t sexp, FILE *file) { any_sexp_writer_t writer; - any_sexp_writer_init(&writer, (any_sexp_fprintf_t)fprintf, file); + any_sexp_writer_init(&writer, (any_sexp_putchar_t)fputc, file); return any_sexp_write(&writer, sexp); } @@ -438,42 +488,47 @@ any_sexp_t any_sexp_nil(void) any_sexp_t any_sexp_symbol(char *symbol, size_t length) { - any_sexp_t sexp = any_sexp_string(symbol, length); - if (ANY_SEXP_IS_ERROR(sexp)) + if (symbol == NULL) return ANY_SEXP_ERROR; - // Override tag + char *copy = ANY_SEXP_MALLOC(length + 1); + if (copy == NULL) + return ANY_SEXP_ERROR; + + memcpy(copy, symbol, length); + copy[length] = '\0'; + #ifndef ANY_SEXP_NO_BOXING - return ANY_SEXP_TAG(ANY_SEXP_UNTAG(sexp), ANY_SEXP_TAG_SYMBOL); + return ANY_SEXP_TAG(copy, ANY_SEXP_TAG_SYMBOL); #else - sexp.tag = ANY_SEXP_TAG_SYMBOL; + any_sexp_t sexp = { + .tag = ANY_SEXP_TAG_SYMBOL, + .symbol = copy, + }; return sexp; #endif } +#ifndef ANY_SEXP_NO_STRING + any_sexp_t any_sexp_string(char *string, size_t length) { - if (string == NULL) - return ANY_SEXP_ERROR; - char *copy = ANY_SEXP_MALLOC(length + 1); - if (copy == NULL) + any_sexp_t sexp = any_sexp_symbol(string, length); + if (ANY_SEXP_IS_ERROR(sexp)) return ANY_SEXP_ERROR; - memcpy(copy, string, length); - copy[length] = '\0'; - + // Override the tag #ifndef ANY_SEXP_NO_BOXING - return ANY_SEXP_TAG(copy, ANY_SEXP_TAG_STRING); + return ANY_SEXP_TAG(ANY_SEXP_UNTAG(sexp), ANY_SEXP_TAG_STRING); #else - any_sexp_t sexp = { - .tag = ANY_SEXP_TAG_STRING, - .symbol = copy, - }; + sexp.tag = ANY_SEXP_TAG_STRING; return sexp; #endif } +#endif + any_sexp_t any_sexp_quote(any_sexp_t sexp) { any_sexp_t quote = any_sexp_symbol(ANY_SEXP_QUOTE_SYMBOL, strlen(ANY_SEXP_QUOTE_SYMBOL)); @@ -553,7 +608,9 @@ void any_sexp_free(any_sexp_t sexp) break; case ANY_SEXP_TAG_SYMBOL: +#ifndef ANY_SEXP_NO_STRING case ANY_SEXP_TAG_STRING: +#endif ANY_SEXP_FREE(ANY_SEXP_GET_SYMBOL(sexp)); break; } |
