summaryrefslogtreecommitdiff
path: root/src/json-lexer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/json-lexer.c')
-rw-r--r--src/json-lexer.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/json-lexer.c b/src/json-lexer.c
new file mode 100644
index 0000000..4357d1a
--- /dev/null
+++ b/src/json-lexer.c
@@ -0,0 +1,282 @@
+#include <config.h>
+#include "libjson/neoas-json-lexer-and-parser.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdbool.h>
+
+static inline void *checked_alloc (void *, size_t n, size_t type);
+static inline void *checked_realloc (void *, void *allocated, size_t n,
+ size_t type);
+static inline void checked_free (void *, void *memory);
+static inline void assert_everything_freed (void *);
+
+#define MAX_ALLOCS 64
+struct alloc_registry
+{
+ size_t n_allocated;
+ void *addresses[MAX_ALLOCS];
+ size_t sizes[MAX_ALLOCS];
+};
+
+static inline void *
+checked_alloc (void *ctx, size_t n, size_t type)
+{
+ struct alloc_registry *registry = ctx;
+ if (registry->n_allocated >= MAX_ALLOCS)
+ {
+ return NULL;
+ }
+ if (n * type >= 8192)
+ {
+ return NULL;
+ }
+ void *mem = calloc (n, type);
+ if (mem == NULL)
+ {
+ return NULL;
+ }
+ registry->addresses[registry->n_allocated] = mem;
+ registry->sizes[registry->n_allocated] = n * type;
+ registry->n_allocated++;
+ return mem;
+}
+
+static inline void *
+checked_realloc (void *ctx, void *mem, size_t n, size_t type)
+{
+ struct alloc_registry *registry = ctx;
+ for (size_t i = 0; i < registry->n_allocated; i++)
+ {
+ if (registry->addresses[i] == mem)
+ {
+ void *newmem = realloc (mem, n * type);
+ if (newmem == NULL)
+ {
+ return NULL;
+ }
+ registry->addresses[i] = newmem;
+ registry->sizes[i] = n * type;
+ return newmem;
+ }
+ }
+ assert (false);
+}
+
+static inline void
+checked_free (void *ctx, void *mem)
+{
+ struct alloc_registry *registry = ctx;
+ if (mem == NULL)
+ {
+ return;
+ }
+ for (size_t i = 0; i < registry->n_allocated; i++)
+ {
+ if (registry->addresses[i] == mem)
+ {
+ free (registry->addresses[i]);
+ registry->n_allocated--;
+ registry->addresses[i] = registry->addresses[registry->n_allocated];
+ registry->sizes[i] = registry->sizes[registry->n_allocated];
+ return;
+ }
+ }
+ assert (false);
+}
+
+static inline void
+assert_everything_freed (void *ctx)
+{
+ struct alloc_registry *registry = ctx;
+ assert (registry->n_allocated == 0);
+}
+
+static inline int
+handle_null (void *ctx)
+{
+ assert (ctx == NULL);
+ printf ("Null\n");
+ return 0;
+}
+
+static inline int
+handle_bool (void *ctx, bool value)
+{
+ assert (ctx == NULL);
+ printf ("Boolean: %c\n", value ? 'T' : 'F');
+ return 0;
+}
+
+static inline int
+handle_number (void *ctx, double value)
+{
+ assert (ctx == NULL);
+ printf ("Number: %g\n", value);
+ return 0;
+}
+
+static inline int
+handle_string (void *ctx, size_t len, const char *str)
+{
+ assert (ctx == NULL);
+ printf ("String (%lu): ", len);
+ for (size_t i = 0; i < len; i++)
+ {
+ if (str[i] < 32 || str[i] == '\r' || str[i] == '\n')
+ {
+ printf ("\\%d", (int) ((uint8_t) str[i]));
+ }
+ else
+ {
+ printf ("%c", str[i]);
+ }
+ }
+ printf ("\n");
+ return 0;
+}
+
+static inline int
+handle_object_start (void *ctx, void **user_data)
+{
+ assert (ctx == NULL);
+ *user_data = NULL;
+ printf ("Open object\n");
+ return 0;
+}
+
+static inline int
+object_next_key (void *ctx, void *user_data, size_t len, const char *key)
+{
+ assert (ctx == NULL);
+ assert (user_data == NULL);
+ printf ("Switch to key (%lu): ", len);
+ for (size_t i = 0; i < len; i++)
+ {
+ if (key[i] < 32 || key[i] == '\r' || key[i] == '\n')
+ {
+ printf ("\\%d", (int) ((uint8_t) key[i]));
+ }
+ else
+ {
+ printf ("%c", key[i]);
+ }
+ }
+ printf ("\n");
+ return 0;
+}
+
+static inline int
+handle_object_stop (void *ctx, void *user_data)
+{
+ assert (ctx == NULL);
+ assert (user_data == NULL);
+ printf ("Close object\n");
+ return 0;
+}
+
+static inline int
+handle_array_start (void *ctx, void **user_data)
+{
+ assert (ctx == NULL);
+ *user_data = NULL;
+ printf ("Open array\n");
+ return 0;
+}
+
+static inline int
+array_next_key (void *ctx, void *user_data, size_t index)
+{
+ assert (ctx == NULL);
+ assert (user_data == NULL);
+ printf ("Switch to array key (%lu)\n", index);
+ return 0;
+}
+
+static inline int
+handle_array_stop (void *ctx, void *user_data)
+{
+ assert (ctx == NULL);
+ assert (user_data == NULL);
+ printf ("Close array\n");
+ return 0;
+}
+
+static inline int
+handle_next (void *ctx)
+{
+ assert (ctx == NULL);
+ printf ("Next\n");
+ return 0;
+}
+
+static inline int
+handle_syntax_error (void *ctx)
+{
+ assert (ctx == NULL);
+ printf ("Syntax error\n");
+ return 0;
+}
+
+static inline int
+handle_grammar_error (void *ctx)
+{
+ assert (ctx == NULL);
+ printf ("Grammar error\n");
+ return 0;
+}
+
+static inline int
+handle_rejected_input (void *ctx, char c)
+{
+ assert (ctx == NULL);
+ printf ("Rejected input: %c\n", c);
+ return 0;
+}
+
+static inline ssize_t
+do_pull (void *ctx, size_t request, void *data)
+{
+ assert (ctx == NULL);
+ assert (request >= 1);
+ int c = getchar ();
+ if (c >= 0)
+ {
+ uint8_t b = c;
+ uint8_t *dst = data;
+ *dst = b;
+ return 1;
+ }
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ /* This does not call bindtextdomain(...) because it is not a
+ user-facing program. */
+ (void) argc;
+ (void) argv;
+ struct alloc_registry registry = {
+ .n_allocated = 0
+ };
+ struct memory_allocator allocator = {
+ .allocate = checked_alloc,
+ .reallocate = checked_realloc,
+ .deallocate = checked_free,
+ .context = &registry
+ };
+ int error = json_lexer_and_parser_lex (&allocator, do_pull, NULL,
+ handle_null, handle_bool,
+ handle_number, handle_string,
+ handle_object_start, object_next_key,
+ handle_object_stop,
+ handle_array_start, array_next_key,
+ handle_array_stop,
+ handle_syntax_error,
+ handle_grammar_error,
+ handle_rejected_input, NULL);
+ assert_everything_freed (&registry);
+ return error;
+}