aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2024-06-07 17:11:48 +0200
committerFederico Angelilli <code@fedang.net>2024-06-07 17:11:48 +0200
commit33801aad0f98f2fcbb45d552cf2a9c85bd166d7b (patch)
treef467c4a8cee2b7a8056bb74e1debb074025ada74
parentb2398c1735f0482e83b811fed49550ea3d9d32a2 (diff)
Refactor sexp to handle pairs
-rw-r--r--any_log.h15
-rw-r--r--any_sexp.h63
-rw-r--r--test/log.c2
-rw-r--r--test/sexp.c4
4 files changed, 49 insertions, 35 deletions
diff --git a/any_log.h b/any_log.h
index c760e69..9134b8e 100644
--- a/any_log.h
+++ b/any_log.h
@@ -142,15 +142,15 @@ typedef enum {
// f | double | "%lf"
// s | char * (0-terminated) | "%s"
//
-// c | any_log_formatter_t (function), void *
+// g | any_log_formatter_t (function), void *
//
// If no type specifier is given the function will assume the type given
// by ANY_LOG_VALUE_DEFAULT_TYPE (by default string).
//
-// You can log custom types with the 'c' specifier. Then you will have to
-// pass two parameters: a format function of type any_log_formatter_t and
-// a value parameter of type void *.
-// By defining ANY_LOG_NO_CUSTOM you can disable the custom type specifier.
+// The 'g' specifier is handled differently than the others. It needs two parameters,
+// the first must be a custom formatter function (of type any_log_formatter_t) to
+// format the second value of type void *.
+// By defining ANY_LOG_NO_CUSTOM you can disable this custom type specifier.
//
// Example usage of value logging
//
@@ -160,7 +160,7 @@ typedef enum {
// "p:window", window_handle,
// "f:scale", scale_factor_dpi,
// "b:hidden", visibility == HIDDEN,
-// "c:widgets", ANY_LOG_FORMATTER(widget_format), widgets,
+// "g:widgets", ANY_LOG_FORMATTER(widget_format), widgets,
// "appname", "nice app");
//
// In the implementation you can customize the format of every key-value pair
@@ -180,6 +180,7 @@ typedef enum {
// #define ANY_LOG_VALUE_DOUBLE(key, value) "\"%s\": %lf", key, value
// #define ANY_LOG_VALUE_STRING(key, value) "\"%s \": \"%s\"", key, value
// #define ANY_LOG_VALUE_AFTER(level, module, func, message) "}\n"
+// #define ANY_LOG_NO_CUSTOM
// #include "any_log.h"
//
// As with log_trace and log_debug, log_value_trace and log_value_debug can be
@@ -609,7 +610,7 @@ void any_log_value(any_log_level_t level, const char *module,
}
#ifndef ANY_LOG_NO_CUSTOM
- case 'c': {
+ case 'g': {
any_log_formatter_t formatter = va_arg(args, any_log_formatter_t);
void *value = va_arg(args, void *);
ANY_LOG_VALUE_CUSTOM(key, any_log_stream, formatter, value);
diff --git a/any_sexp.h b/any_sexp.h
index 4ee401e..3b24ca2 100644
--- a/any_sexp.h
+++ b/any_sexp.h
@@ -65,11 +65,12 @@ typedef void *any_sexp_t;
#define ANY_SEXP_ERROR (any_sexp_t)UINTPTR_MAX
#define ANY_SEXP_NIL (any_sexp_t)NULL
-#define ANY_SEXP_BITS_SHIFT (sizeof(uintptr_t) * 8 - 4)
-#define ANY_SEXP_UNTAG(sexp) (any_sexp_t)((uintptr_t)(sexp) & ~((uintptr_t)0xf << ANY_SEXP_BITS_SHIFT))
+#define ANY_SEXP_BIT_SHIFT (sizeof(uintptr_t) * 8 - 4)
+#define ANY_SEXP_BIT_SIGN ((uintptr_t)1 << (ANY_SEXP_BIT_SHIFT - 1))
+#define ANY_SEXP_UNTAG(sexp) (any_sexp_t)((uintptr_t)(sexp) & ~((uintptr_t)0xf << ANY_SEXP_BIT_SHIFT))
-#define ANY_SEXP_TAG(sexp, tag) (any_sexp_t)((uintptr_t)(sexp) | ((uintptr_t)tag << ANY_SEXP_BITS_SHIFT))
-#define ANY_SEXP_GET_TAG(sexp) (((uintptr_t)(sexp) >> ANY_SEXP_BITS_SHIFT) & 0xf)
+#define ANY_SEXP_TAG(sexp, tag) (any_sexp_t)((uintptr_t)(sexp) | ((uintptr_t)tag << ANY_SEXP_BIT_SHIFT))
+#define ANY_SEXP_GET_TAG(sexp) (((uintptr_t)(sexp) >> ANY_SEXP_BIT_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)))
#define ANY_SEXP_GET_STRING(sexp) (((char *)ANY_SEXP_UNTAG(sexp)))
@@ -78,12 +79,11 @@ typedef void *any_sexp_t;
static inline intptr_t any_sexp_number_untag(any_sexp_t sexp)
{
uintptr_t ptr = (uintptr_t)ANY_SEXP_UNTAG(sexp);
- uintptr_t sign_bit = (uintptr_t)1 << (ANY_SEXP_BITS_SHIFT - 1);
- uintptr_t clear = ptr & ~(sign_bit | (uintptr_t)0xf << ANY_SEXP_BITS_SHIFT);
+ uintptr_t clear = ptr & ~((uintptr_t)0x1f << (ANY_SEXP_BIT_SHIFT - 1));
// NOTE: Pad with 1's to adjust the two's complement when the sign is negative
- if (ptr & sign_bit)
- clear |= (uintptr_t)0x1f << (ANY_SEXP_BITS_SHIFT - 1);
+ if (ptr & ANY_SEXP_BIT_SIGN)
+ clear |= (uintptr_t)0x1f << (ANY_SEXP_BIT_SHIFT - 1);
return *(intptr_t *)&clear;
}
@@ -411,7 +411,7 @@ static int any_sexp_writer_puts(any_sexp_writer_t *writer, const char *string)
static int any_sexp_writer_putnum(any_sexp_writer_t *writer, intptr_t value)
{
- int c;
+ int c = 0;
if (value > 9) {
c = any_sexp_writer_putnum(writer, value / 10);
value %= 10;
@@ -435,16 +435,17 @@ int any_sexp_write(any_sexp_writer_t *writer, any_sexp_t sexp)
case ANY_SEXP_TAG_ERROR:
return any_sexp_writer_puts(writer, "<error>");
- case ANY_SEXP_TAG_NIL:
- 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_NIL: {
+ const char nil[3] = { ANY_SEXP_CHAR_OPEN, ANY_SEXP_CHAR_CLOSE, '\0' };
+ return any_sexp_writer_puts(writer, nil);
+ }
case ANY_SEXP_TAG_CONS: {
+ any_sexp_t car = any_sexp_car(sexp), cdr = any_sexp_cdr(sexp);
+
#ifndef ANY_SEXP_NO_QUOTE
- any_sexp_t cdr = any_sexp_cdr(sexp);
- if (ANY_SEXP_IS_SYMBOL(any_sexp_car(sexp)) && ANY_SEXP_IS_NIL(any_sexp_cdr(cdr)) &&
- !strcmp(ANY_SEXP_GET_SYMBOL(any_sexp_car(sexp)), ANY_SEXP_QUOTE_SYMBOL)) {
+ if (ANY_SEXP_IS_SYMBOL(car) && ANY_SEXP_IS_NIL(any_sexp_cdr(cdr)) &&
+ !strcmp(ANY_SEXP_GET_SYMBOL(car), ANY_SEXP_QUOTE_SYMBOL)) {
if (writer->putc(ANY_SEXP_CHAR_QUOTE, writer->stream) == EOF)
return EOF;
@@ -457,19 +458,28 @@ int any_sexp_write(any_sexp_writer_t *writer, any_sexp_t sexp)
return EOF;
int c = 2, tmp;
- while (!ANY_SEXP_IS_NIL(sexp) && !ANY_SEXP_IS_ERROR(sexp)) {
- tmp = any_sexp_write(writer, any_sexp_car(sexp));
- sexp = any_sexp_cdr(sexp);
-
+ while (true) {
+ tmp = any_sexp_write(writer, car);
if (tmp == EOF)
return EOF;
+ c += tmp;
- if (!ANY_SEXP_IS_NIL(sexp)) {
+ if (ANY_SEXP_IS_CONS(cdr)) {
if (writer->putc(' ', writer->stream) == EOF)
return EOF;
- tmp++;
- }
- c += tmp;
+
+ car = any_sexp_car(cdr);
+ cdr = any_sexp_cdr(cdr);
+ c++;
+ } else if (!ANY_SEXP_IS_NIL(cdr)) {
+ if (any_sexp_writer_puts(writer, " . ") == EOF)
+ return EOF;
+
+ car = cdr;
+ cdr = ANY_SEXP_NIL;
+ c += 3;
+ } else
+ break;
}
if (writer->putc(ANY_SEXP_CHAR_CLOSE, writer->stream) == EOF)
@@ -590,12 +600,11 @@ any_sexp_t any_sexp_number(intptr_t value)
#ifndef ANY_SEXP_NO_BOXING
// Handle the sign bit!
- uintptr_t sign_bit = (uintptr_t)1 << (ANY_SEXP_BITS_SHIFT - 1);
uintptr_t sexp = *(uintptr_t *)&value;
- sexp &= ~(sign_bit | (uintptr_t)0xf << ANY_SEXP_BITS_SHIFT);
+ sexp &= ~((uintptr_t)0x1f << (ANY_SEXP_BIT_SHIFT - 1));
if (value < 0)
- sexp |= sign_bit;
+ sexp |= ANY_SEXP_BIT_SIGN;
return ANY_SEXP_TAG(sexp, ANY_SEXP_TAG_NUMBER);
#else
diff --git a/test/log.c b/test/log.c
index 5b6293d..48244de 100644
--- a/test/log.c
+++ b/test/log.c
@@ -93,7 +93,7 @@ int main()
"p:window", NULL,
"f:scale", 1.23,
"b:hidden", true,
- "c:pairs", ANY_LOG_FORMATTER(pairs_format), pairs,
+ "g:pairs", ANY_LOG_FORMATTER(pairs_format), pairs,
"appname", "nice app");
// Test any_log_format
diff --git a/test/sexp.c b/test/sexp.c
index 8070156..3adf3ab 100644
--- a/test/sexp.c
+++ b/test/sexp.c
@@ -30,6 +30,10 @@ int main()
sexp = any_sexp_read(&reader);
}
+ any_sexp_t pair = any_sexp_cons(any_sexp_number(1), any_sexp_number(2));
+ any_sexp_print(pair);
+ any_sexp_free_list(pair);
+
//printf("%zu\n", sizeof(any_sexp_t));
return 0;