diff options
Diffstat (limited to 'src/libjson/neoas-json-parser.h')
-rw-r--r-- | src/libjson/neoas-json-parser.h | 462 |
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 */ |