summaryrefslogtreecommitdiff
path: root/src/libjson/neoas-json-parser.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/libjson/neoas-json-parser.h')
-rw-r--r--src/libjson/neoas-json-parser.h462
1 files changed, 462 insertions, 0 deletions
diff --git a/src/libjson/neoas-json-parser.h b/src/libjson/neoas-json-parser.h
new file mode 100644
index 0000000..b586b52
--- /dev/null
+++ b/src/libjson/neoas-json-parser.h
@@ -0,0 +1,462 @@
+#ifndef NEOAS_JSON_PARSER_H_INCLUDED
+# define NEOAS_JSON_PARSER_H_INCLUDED
+
+# include <stdbool.h>
+
+struct memory_allocator;
+
+struct json_parser;
+
+static inline int json_parser_init (const struct memory_allocator *allocator,
+ struct json_parser *parser);
+
+static inline void json_parser_deinit (struct json_parser *parser);
+
+static inline void json_parser_set (struct json_parser *parser,
+ int (*handle_null) (void *),
+ int (*handle_bool) (void *, bool),
+ int (*handle_number) (void *, double),
+ int (*handle_string) (void *, size_t,
+ const char *),
+ int (*handle_object_start) (void *,
+ void **),
+ int (*object_next_key) (void *, void *,
+ size_t,
+ const char *),
+ int (*handle_object_stop) (void *,
+ void *),
+ int (*handle_array_start) (void *,
+ void **),
+ int (*array_next_key) (void *, void *,
+ size_t),
+ int (*handle_array_stop) (void *, void *),
+ int (*handle_grammar_error) (void *),
+ void *context);
+
+static inline int json_parser_push_null (struct json_parser *parser);
+static inline int json_parser_push_bool (struct json_parser *parser,
+ bool boolean);
+static inline int json_parser_push_number (struct json_parser *parser,
+ double number);
+static inline int json_parser_push_string (struct json_parser *parser,
+ size_t length, const char *str);
+static inline int json_parser_push_object_start (struct json_parser *parser);
+static inline int json_parser_push_object_assoc (struct json_parser *parser);
+static inline int json_parser_push_object_stop (struct json_parser *parser);
+static inline int json_parser_push_array_start (struct json_parser *parser);
+static inline int json_parser_push_array_stop (struct json_parser *parser);
+static inline int json_parser_push_next (struct json_parser *parser);
+
+# include <assert.h>
+# include <string.h>
+
+enum json_parser_frame_type
+{
+ JSON_PARSER_FRAME_OBJECT,
+ JSON_PARSER_FRAME_ARRAY
+};
+
+struct json_parser_array_frame
+{
+ size_t next_index;
+};
+
+struct json_parser_object_frame
+{
+ bool has_key;
+};
+
+union json_parser_frame_u
+{
+ struct json_parser_array_frame array;
+ struct json_parser_object_frame object;
+};
+
+struct json_parser_frame
+{
+ enum json_parser_frame_type type;
+ union json_parser_frame_u u;
+ void *user_data;
+};
+
+struct json_parser
+{
+ size_t max_stack;
+ size_t stack_top;
+ struct json_parser_frame *stack;
+ struct memory_allocator allocator;
+ size_t next_key_size;
+ char *next_key;
+ int (*handle_null) (void *);
+ int (*handle_bool) (void *, bool);
+ int (*handle_number) (void *, double);
+ int (*handle_string) (void *, size_t, const char *);
+ int (*handle_object_start) (void *, void **);
+ int (*object_next_key) (void *, void *, size_t, const char *);
+ int (*handle_object_stop) (void *, void *);
+ int (*handle_array_start) (void *, void **);
+ int (*array_next_key) (void *, void *, size_t);
+ int (*handle_array_stop) (void *, void *);
+ int (*handle_grammar_error) (void *);
+ void *context;
+};
+
+static inline int
+json_parser_init (const struct memory_allocator *allocator,
+ struct json_parser *parser)
+{
+ parser->max_stack = 4;
+ parser->stack_top = 0;
+ if (ALLOCATE (parser->stack, parser->max_stack) < 0)
+ {
+ return -1;
+ }
+ copy_allocator (&(parser->allocator), allocator);
+ parser->next_key_size = 0;
+ parser->next_key = NULL;
+ parser->handle_null = NULL;
+ parser->handle_bool = NULL;
+ parser->handle_number = NULL;
+ parser->handle_string = NULL;
+ parser->handle_object_start = NULL;
+ parser->object_next_key = NULL;
+ parser->handle_object_stop = NULL;
+ parser->handle_array_start = NULL;
+ parser->array_next_key = NULL;
+ parser->handle_array_stop = NULL;
+ parser->handle_grammar_error = NULL;
+ parser->context = NULL;
+ return 0;
+}
+
+static inline void
+json_parser_deinit (struct json_parser *parser)
+{
+ const struct memory_allocator *allocator = &(parser->allocator);
+ for (size_t i = parser->stack_top; i-- > 0;)
+ {
+ struct json_parser_frame *frame = &(parser->stack[i]);
+ switch (frame->type)
+ {
+ case JSON_PARSER_FRAME_OBJECT:
+ /* Ignore failure, the front-end must liberate all memory. */
+ parser->handle_object_stop (parser->context, frame->user_data);
+ break;
+ case JSON_PARSER_FRAME_ARRAY:
+ parser->handle_array_stop (parser->context, frame->user_data);
+ break;
+ default:
+ assert (false);
+ }
+ }
+ DEALLOCATE (parser->stack);
+ DEALLOCATE (parser->next_key);
+}
+
+static inline void
+json_parser_set (struct json_parser *parser,
+ int (*handle_null) (void *),
+ int (*handle_bool) (void *, bool),
+ int (*handle_number) (void *, double),
+ int (*handle_string) (void *, size_t, const char *),
+ int (*handle_object_start) (void *, void **),
+ int (*object_next_key) (void *, void *, size_t,
+ const char *),
+ int (*handle_object_stop) (void *, void *),
+ int (*handle_array_start) (void *, void **),
+ int (*array_next_key) (void *, void *, size_t),
+ int (*handle_array_stop) (void *, void *),
+ int (*handle_grammar_error) (void *), void *context)
+{
+ const struct memory_allocator *allocator = &(parser->allocator);
+ DEALLOCATE (parser->next_key);
+ parser->next_key_size = 0;
+ parser->next_key = NULL;
+ parser->handle_null = handle_null;
+ parser->handle_bool = handle_bool;
+ parser->handle_number = handle_number;
+ parser->handle_string = handle_string;
+ parser->handle_object_start = handle_object_start;
+ parser->object_next_key = object_next_key;
+ parser->handle_object_stop = handle_object_stop;
+ parser->handle_array_start = handle_array_start;
+ parser->array_next_key = array_next_key;
+ parser->handle_array_stop = handle_array_stop;
+ parser->handle_grammar_error = handle_grammar_error;
+ parser->context = context;
+}
+
+static inline int
+json_parser_push_null (struct json_parser *parser)
+{
+ if (parser->next_key != NULL)
+ {
+ /* No: we should be reading a colon now */
+ return parser->handle_grammar_error (parser->context);
+ }
+ if (parser->stack_top == 0)
+ {
+ return parser->handle_grammar_error (parser->context);
+ }
+ return parser->handle_null (parser->context);
+}
+
+static inline int
+json_parser_push_bool (struct json_parser *parser, bool value)
+{
+ if (parser->next_key != NULL)
+ {
+ /* No: we should be reading a colon now */
+ return parser->handle_grammar_error (parser->context);
+ }
+ if (parser->stack_top == 0)
+ {
+ return parser->handle_grammar_error (parser->context);
+ }
+ return parser->handle_bool (parser->context, value);
+}
+
+static inline int
+json_parser_push_number (struct json_parser *parser, double value)
+{
+ if (parser->next_key != NULL)
+ {
+ /* No: we should be reading a colon now */
+ return parser->handle_grammar_error (parser->context);
+ }
+ if (parser->stack_top == 0)
+ {
+ return parser->handle_grammar_error (parser->context);
+ }
+ return parser->handle_number (parser->context, value);
+}
+
+static inline int
+json_parser_push_string (struct json_parser *parser, size_t size,
+ const char *key)
+{
+ const struct memory_allocator *allocator = &(parser->allocator);
+ /* There are 2 possibilities: either we’re reading an object key, or
+ we are reading a value. */
+ if (parser->stack_top == 0)
+ {
+ /* We’re not in an object, and this is a string: it cannot be a
+ top-level value. */
+ return parser->handle_grammar_error (parser->context);
+ }
+ struct json_parser_frame *top = &(parser->stack[parser->stack_top - 1]);
+ if (top->type == JSON_PARSER_FRAME_ARRAY)
+ {
+ goto reading_value;
+ }
+ assert (top->type == JSON_PARSER_FRAME_OBJECT);
+ struct json_parser_object_frame *frame = &(top->u.object);
+ if (frame->has_key)
+ {
+ goto reading_value;
+ }
+ if (parser->next_key != NULL)
+ {
+ /* Two strings before the colon: invalid */
+ return parser->handle_grammar_error (parser->context);
+ }
+ char *copy;
+ if (ALLOCATE (copy, size + 1) < 0)
+ {
+ return -1;
+ }
+ memcpy (copy, key, size);
+ copy[size] = '\0';
+ parser->next_key_size = size;
+ parser->next_key = copy;
+ return 0;
+reading_value:
+ if (parser->next_key != NULL)
+ {
+ /* No: we should be reading a colon now */
+ return parser->handle_grammar_error (parser->context);
+ }
+ return parser->handle_string (parser->context, size, key);
+}
+
+static inline int
+extend_stack (struct json_parser *parser)
+{
+ const struct memory_allocator *allocator = &(parser->allocator);
+ size_t new_size = 2 * parser->max_stack;
+ if (REALLOCATE (parser->stack, new_size) < 0)
+ {
+ return -1;
+ }
+ parser->max_stack = new_size;
+ return 0;
+}
+
+static inline int
+json_parser_push_object_start (struct json_parser *parser)
+{
+ if (parser->next_key != NULL)
+ {
+ /* No: we should be reading a colon now */
+ return parser->handle_grammar_error (parser->context);
+ }
+ if (parser->stack_top == parser->max_stack)
+ {
+ int error = extend_stack (parser);
+ if (error)
+ {
+ return error;
+ }
+ }
+ parser->stack[parser->stack_top].type = JSON_PARSER_FRAME_OBJECT;
+ parser->stack[parser->stack_top].u.object.has_key = false;
+ int error = parser->handle_object_start (parser->context,
+ &(parser->
+ stack[parser->
+ stack_top].user_data));
+ if (error)
+ {
+ parser->stack[parser->stack_top].user_data = NULL;
+ }
+ parser->stack_top++;
+ return error;
+}
+
+static inline int
+json_parser_push_object_assoc (struct json_parser *parser)
+{
+ const struct memory_allocator *allocator = &(parser->allocator);
+ if (parser->next_key == NULL)
+ {
+ /* No: we don’t have a key! */
+ return parser->handle_grammar_error (parser->context);
+ }
+ assert (parser->stack_top > 0);
+ struct json_parser_frame *frame = &(parser->stack[parser->stack_top - 1]);
+ if (frame->type != JSON_PARSER_FRAME_OBJECT)
+ {
+ /* No: wtf, a ':' in an array? */
+ return parser->handle_grammar_error (parser->context);
+ }
+ assert (frame->type == JSON_PARSER_FRAME_OBJECT);
+ if (frame->u.object.has_key)
+ {
+ /* No: two colons for the same key */
+ return parser->handle_grammar_error (parser->context);
+ }
+ frame->u.object.has_key = true;
+ int error = parser->object_next_key (parser->context, frame->user_data,
+ parser->next_key_size,
+ parser->next_key);
+ DEALLOCATE (parser->next_key);
+ parser->next_key = NULL;
+ return error;
+}
+
+static inline int
+json_parser_push_object_stop (struct json_parser *parser)
+{
+ if (parser->next_key != NULL)
+ {
+ /* No: we should be reading a colon now */
+ return parser->handle_grammar_error (parser->context);
+ }
+ if (parser->stack_top == 0)
+ {
+ /* More data past the end of stream */
+ return parser->handle_grammar_error (parser->context);
+ }
+ parser->stack_top--;
+ return parser->handle_object_stop (parser->context,
+ parser->stack[parser->
+ stack_top].user_data);
+}
+
+static inline int
+json_parser_push_array_start (struct json_parser *parser)
+{
+ if (parser->next_key != NULL)
+ {
+ /* No: we should be reading a colon now */
+ return parser->handle_grammar_error (parser->context);
+ }
+ if (parser->stack_top == parser->max_stack)
+ {
+ int error = extend_stack (parser);
+ if (error)
+ {
+ return error;
+ }
+ }
+ struct json_parser_frame *frame = &(parser->stack[parser->stack_top]);
+ frame->type = JSON_PARSER_FRAME_ARRAY;
+ frame->u.array.next_index = 0;
+ int error = parser->handle_array_start (parser->context,
+ &(frame->user_data));
+ if (error)
+ {
+ parser->stack[parser->stack_top].user_data = NULL;
+ }
+ parser->stack_top++;
+ if (error == 0)
+ {
+ error =
+ parser->array_next_key (parser->context, frame->user_data,
+ (frame->u.array.next_index)++);
+ }
+ return error;
+}
+
+static inline int
+json_parser_push_array_stop (struct json_parser *parser)
+{
+ if (parser->next_key != NULL)
+ {
+ /* No: we should be reading a colon now */
+ return parser->handle_grammar_error (parser->context);
+ }
+ if (parser->stack_top == 0)
+ {
+ /* More data past the end of stream */
+ return parser->handle_grammar_error (parser->context);
+ }
+ parser->stack_top--;
+ return parser->handle_array_stop (parser->context,
+ parser->stack[parser->
+ stack_top].user_data);
+}
+
+static inline int
+json_parser_push_next (struct json_parser *parser)
+{
+ if (parser->next_key != NULL)
+ {
+ /* wtf?? */
+ return parser->handle_grammar_error (parser->context);
+ }
+ if (parser->stack_top == 0)
+ {
+ /* This cannot be a top-level element */
+ return parser->handle_grammar_error (parser->context);
+ }
+ assert (parser->stack_top > 0);
+ struct json_parser_frame *frame = &(parser->stack[parser->stack_top - 1]);
+ if (frame->type == JSON_PARSER_FRAME_ARRAY)
+ {
+ return parser->array_next_key (parser->context, frame->user_data,
+ (frame->u.array.next_index)++);
+ }
+ else if (frame->type == JSON_PARSER_FRAME_OBJECT)
+ {
+ frame->u.object.has_key = false;
+ return 0;
+ }
+ else
+ {
+ assert (false);
+ }
+ abort ();
+ return 0;
+}
+
+#endif /* NEOAS_JSON_PARSER_H_INCLUDED */