#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "jv.h"
#include "jv_dtoa.h"
#include "jv_unicode.h"
#include "jv_alloc.h"
#include "jv_dtoa.h"
typedef const char* presult;
#define TRY(x) do {presult msg__ = (x); if (msg__) return msg__; } while(0)
#ifdef __GNUC__
#define pfunc __attribute__((warn_unused_result)) presult
#else
#define pfunc presult
#endif
enum last_seen {
JV_LAST_NONE = 0,
JV_LAST_OPEN_ARRAY = '[',
JV_LAST_OPEN_OBJECT = '{',
JV_LAST_COLON = ':',
JV_LAST_COMMA = ',',
JV_LAST_VALUE = 'V',
};
struct jv_parser {
const char* curr_buf;
int curr_buf_length;
int curr_buf_pos;
int curr_buf_is_partial;
int eof;
unsigned bom_strip_position;
int flags;
jv* stack; // parser
int stackpos; // parser
int stacklen; // both (optimization; it's really pathlen for streaming)
jv path; // streamer
enum last_seen last_seen; // streamer
jv output; // streamer
jv next; // both
char* tokenbuf;
int tokenpos;
int tokenlen;
int line, column;
struct dtoa_context dtoa;
enum {
JV_PARSER_NORMAL,
JV_PARSER_STRING,
JV_PARSER_STRING_ESCAPE,
JV_PARSER_WAITING_FOR_RS // parse error, waiting for RS
} st;
unsigned int last_ch_was_ws:1;
};
static void parser_init(struct jv_parser* p, int flags) {
p->flags = flags;
if ((p->flags & JV_PARSE_STREAMING)) {
p->path = jv_array();
} else {
p->path = jv_invalid();
p->flags &= ~(JV_PARSE_STREAM_ERRORS);
}
p->stack = 0;
p->stacklen = p->stackpos = 0;
p->last_seen = JV_LAST_NONE;
p->output = jv_invalid();
p->next = jv_invalid();
p->tokenbuf = 0;
p->tokenlen = p->tokenpos = 0;
if ((p->flags & JV_PARSE_SEQ))
p->st = JV_PARSER_WAITING_FOR_RS;
else
p->st = JV_PARSER_NORMAL;
p->eof = 0;
p->curr_buf = 0;
p->curr_buf_length = p->curr_buf_pos = p->curr_buf_is_partial = 0;
p->bom_strip_position = 0;
p->last_ch_was_ws = 0;
p->line = 1;
p->column = 0;
jvp_dtoa_context_init(&p->dtoa);
}
static void parser_reset(struct jv_parser* p) {
if ((p->flags & JV_PARSE_STREAMING)) {
jv_free(p->path);
p->path = jv_array();
p->stacklen = 0;
}
p->last_seen = JV_LAST_NONE;
jv_free(p->output);
p->output = jv_invalid();
jv_free(p->next);
p->next = jv_invalid();
for (int i=0; i<p->stackpos; i++)
jv_free(p->stack[i]);
p->stackpos = 0;
p->tokenpos = 0;
p->st = JV_PARSER_NORMAL;
}
static void parser_free(struct jv_parser* p) {
parser_reset(p);
jv_free(p->path);
jv_free(p->output);
jv_mem_free(p->stack);
jv_mem_free(p->tokenbuf);
jvp_dtoa_context_free(&p->dtoa);
}
static pfunc value(struct jv_parser* p, jv val) {
if ((p->flags & JV_PARSE_STREAMING)) {
if (jv_is_valid(p->next) || p->last_seen == JV_LAST_VALUE)
return "Expected separator between values";
if (p->stacklen > 0)
p->last_seen = JV_LAST_VALUE;
else
p->last_seen = JV_LAST_NONE;
} else {
if (jv_is_valid(p->next)) return "Expected separator between values";
}
jv_free(p->next);
p->next = val;
return 0;
}
static void push(struct jv_parser* p, jv v) {
assert(p->stackpos <= p->stacklen);
if (p->stackpos == p->stacklen) {
p->stacklen = p->stacklen * 2 + 10;
p->stack = jv_mem_realloc(p->stack, p->stacklen * sizeof(jv));
}
assert(p->stackpos < p->stacklen);
p->stack[p->stackpos++] = v;
}
static pfunc parse_token(struct jv_parser* p, char ch) {