Change error output to be in the hands of the library user instead of the library
This commit is contained in:
parent
1b649fb582
commit
d7e8c5ccbb
1
doc/examples/.gitignore
vendored
1
doc/examples/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
output
|
||||
parse
|
||||
parse_file
|
||||
*.o
|
||||
|
||||
@ -8,7 +8,7 @@ int main(int argc, char** argv){
|
||||
}
|
||||
|
||||
//Read in json argument allowing all RJP extensions (comments, trailing comma)
|
||||
RJP_value* root = rjp_parse(argv[1], RJP_PARSE_ALL_EXT);
|
||||
RJP_value* root = rjp_parse(argv[1], RJP_PARSE_ALL_EXT, NULL);
|
||||
|
||||
//returns NULL on error
|
||||
if(!root){
|
||||
|
||||
@ -22,7 +22,7 @@ int main(int argc, char** argv){
|
||||
fclose(fp);
|
||||
|
||||
//Read in json argument allowing all RJP extensions (comments, trailing comma)
|
||||
RJP_value* root = rjp_parse(buffer, RJP_PARSE_ALL_EXT);
|
||||
RJP_value* root = rjp_parse(buffer, RJP_PARSE_ALL_EXT, NULL);
|
||||
|
||||
//returns NULL on error
|
||||
if(!root){
|
||||
|
||||
@ -108,7 +108,11 @@ typedef struct RJP_parse_callback{
|
||||
int(*read)(char*,int,void*);
|
||||
void* data;
|
||||
}RJP_parse_callback;
|
||||
|
||||
typedef struct RJP_parse_error{
|
||||
void* parsestate;
|
||||
int errcode;
|
||||
int row, column;
|
||||
}RJP_parse_error;
|
||||
|
||||
/***************** NON OBJECT OPERATIONS *******************/
|
||||
void* rjp_alloc(RJP_index nbytes);
|
||||
@ -121,10 +125,14 @@ RJP_index rjp_escape_strlen(const char* str);
|
||||
RJP_string rjp_escape(const char* src);
|
||||
|
||||
/***************** GENERIC OPERATIONS *******************/
|
||||
RJP_value* rjp_parse(const char* str, int flags);
|
||||
RJP_value* rjp_parse_cback(int flags, RJP_parse_callback* cbacks);
|
||||
RJP_value* rjp_simple_parse(const char* str);
|
||||
RJP_value* rjp_parse(const char* str, int flags, RJP_parse_error* err);
|
||||
RJP_value* rjp_parse_cback(int flags, RJP_parse_callback* cbacks, RJP_parse_error* err);
|
||||
char* rjp_to_json(const RJP_value* root, int pretty);
|
||||
|
||||
char* rjp_parse_error_to_string(RJP_parse_error* err);
|
||||
void rjp_delete_parse_error(RJP_parse_error* err);
|
||||
|
||||
RJP_value* rjp_new_null(void);
|
||||
RJP_value* rjp_new_int(RJP_int val);
|
||||
RJP_value* rjp_new_float(RJP_float val);
|
||||
|
||||
@ -24,6 +24,9 @@
|
||||
#define RJP_LEX_CBACK_BUFFER_SIZE 512
|
||||
#define RJP_LEX_CBACK_STR_SIZE 64
|
||||
|
||||
#define RJP_LEX_TYPE_NORMAL 0
|
||||
#define RJP_LEX_TYPE_CBACK 1
|
||||
|
||||
#define rjp_lex_accept 1
|
||||
//DFA states. odd numbers are accepting states
|
||||
typedef enum RJP_lex_category{
|
||||
@ -79,9 +82,12 @@ typedef struct RJP_lex_state{
|
||||
RJP_lex_category node; //tracks current dfa state
|
||||
RJP_index length; //length of current token which parser will utilize
|
||||
RJP_index offset; //offset in the str buffer that the parser should start from. must be 0 in callback lexer
|
||||
int type;
|
||||
}RJP_lex_state;
|
||||
|
||||
void irjp_init_lex_cback_state(RJP_lex_state* state);
|
||||
void irjp_init_lex_state(RJP_lex_state* state);
|
||||
void irjp_delete_lex_state(RJP_lex_state* state);
|
||||
RJP_lex_category irjp_lex(RJP_lex_state* state);
|
||||
RJP_lex_category irjp_lex_cback(RJP_lex_state* state, RJP_parse_callback* cbacks);
|
||||
|
||||
|
||||
@ -30,7 +30,9 @@ namespace rjp{
|
||||
|
||||
string to_json(const value& val, int format = RJP_FORMAT_PRETTY);
|
||||
value parse_json(const rexy::string_base& str, RJP_parse_flag = RJP_PARSE_NONE);
|
||||
value parse_json(const rexy::string_base& str, RJP_parse_flag, RJP_parse_error&);
|
||||
value parse_json(const char* str, RJP_parse_flag = RJP_PARSE_NONE);
|
||||
value parse_json(const char* str, RJP_parse_flag, RJP_parse_error&);
|
||||
namespace detail{
|
||||
template<int... Indexes>
|
||||
struct sequence_tup{};
|
||||
@ -66,6 +68,7 @@ namespace rjp{
|
||||
return ph(c, size, typename sequence_gen<sizeof...(Args)>::type{});
|
||||
}
|
||||
};
|
||||
RJP_value* parse_cback(RJP_parse_flag f, RJP_parse_callback* cb, RJP_parse_error& err);
|
||||
RJP_value* parse_cback(RJP_parse_flag f, RJP_parse_callback* cb);
|
||||
int irjp_parse_callback(char* dest, int size, void* userdata);
|
||||
}
|
||||
@ -77,6 +80,14 @@ namespace rjp{
|
||||
cb.read = detail::irjp_parse_callback;
|
||||
return value(detail::parse_cback(f, &cb), true);
|
||||
}
|
||||
template<class Func, class... Args>
|
||||
value parse_json(RJP_parse_flag f, RJP_parse_error& err, Func&& func, Args&&... args){
|
||||
RJP_parse_callback cb;
|
||||
detail::invoker_impl<Func,Args...> inv(std::forward<Func>(func), std::forward<Args>(args)...);
|
||||
cb.data = static_cast<void*>(&inv);
|
||||
cb.read = detail::irjp_parse_callback;
|
||||
return value(detail::parse_cback(f, &cb, err), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -32,19 +32,28 @@ namespace rjp{
|
||||
s.reset(rjp_to_json(val.raw(), format));
|
||||
return s;
|
||||
}
|
||||
value parse_json(const rexy::string_base& str, RJP_parse_flag flags, RJP_parse_error& err){
|
||||
return parse_json(str.get(), flags, err);
|
||||
}
|
||||
value parse_json(const rexy::string_base& str, RJP_parse_flag flags){
|
||||
return value(rjp_parse(str.get(), flags), true);
|
||||
return parse_json(str.get(), flags);
|
||||
}
|
||||
value parse_json(const char* str, RJP_parse_flag flags){
|
||||
return value(rjp_parse(str, flags), true);
|
||||
return value(rjp_parse(str, flags, NULL), true);
|
||||
}
|
||||
value parse_json(const char* str, RJP_parse_flag flags, RJP_parse_error& err){
|
||||
return value(rjp_parse(str, flags, &err), true);
|
||||
}
|
||||
namespace detail{
|
||||
int irjp_parse_callback(char* dest, int size, void* userdata){
|
||||
invoker* inv = static_cast<invoker*>(userdata);
|
||||
return inv->run(dest, size);
|
||||
}
|
||||
RJP_value* parse_cback(RJP_parse_flag f, RJP_parse_callback* cb, RJP_parse_error& err){
|
||||
return rjp_parse_cback(f, cb, &err);
|
||||
}
|
||||
RJP_value* parse_cback(RJP_parse_flag f, RJP_parse_callback* cb){
|
||||
return rjp_parse_cback(f, cb);
|
||||
return rjp_parse_cback(f, cb, NULL);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
||||
@ -19,6 +19,8 @@ int read_callback(char* c, int size, const char* data, int datalen, int& datapos
|
||||
int handle_res(const rjp::value& res){
|
||||
if(res.valid()){
|
||||
fprintf(stderr, "Accepted\n");
|
||||
}else{
|
||||
fprintf(stderr, "Rejected\n");
|
||||
}
|
||||
return !res.valid();
|
||||
}
|
||||
|
||||
@ -27,7 +27,18 @@ void irjp_init_lex_cback_state(RJP_lex_state* state){
|
||||
state->strcap = RJP_LEX_CBACK_STR_SIZE;
|
||||
state->buff = rjp_alloc(RJP_LEX_CBACK_BUFFER_SIZE);
|
||||
state->buffcap = RJP_LEX_CBACK_BUFFER_SIZE;
|
||||
state->type = RJP_LEX_TYPE_CBACK;
|
||||
}
|
||||
void irjp_init_lex_state(RJP_lex_state* state){
|
||||
state->type = RJP_LEX_TYPE_NORMAL;
|
||||
}
|
||||
void irjp_delete_lex_state(RJP_lex_state* state){
|
||||
if(state->type == RJP_LEX_TYPE_CBACK){
|
||||
rjp_free(state->str);
|
||||
rjp_free(state->buff);
|
||||
}
|
||||
}
|
||||
|
||||
static RJP_lex_category irjp_lex_accept(RJP_lex_category val, RJP_lex_state* state){
|
||||
state->node = rjp_lex_start;
|
||||
return val;
|
||||
|
||||
184
src/rjp_parse.c
184
src/rjp_parse.c
@ -28,8 +28,19 @@
|
||||
|
||||
|
||||
#define RJP_INITIAL_PARSE_DEPTH 16
|
||||
#define RJP_PARSE_STATUS_ERR 1
|
||||
#define RJP_PARSE_STATUS_SUC 2
|
||||
|
||||
typedef enum RJP_parse_status{
|
||||
RJP_PARSE_STATUS_SUC,
|
||||
RJP_PARSE_STATUS_ERR,
|
||||
RJP_PARSE_STATUS_MISSING_VALUE,
|
||||
RJP_PARSE_STATUS_MISSING_COMMA,
|
||||
RJP_PARSE_STATUS_INVALID,
|
||||
RJP_PARSE_STATUS_NO_ROOT_VALUE,
|
||||
RJP_PARSE_STATUS_MISSING_KEY,
|
||||
RJP_PARSE_STATUS_MISSING_COLON,
|
||||
RJP_PARSE_STATUS_EXCESS_DATA,
|
||||
RJP_PARSE_STATUS_MISSING_CLOSE_BRACE,
|
||||
}RJP_parse_status;
|
||||
|
||||
|
||||
typedef enum RJP_parse_target{
|
||||
@ -57,8 +68,8 @@ typedef struct RJP_parse_state{
|
||||
RJP_value* lastadded;
|
||||
RJP_lex_state lexstate;
|
||||
int row, column;
|
||||
const _Bool allow_comments;
|
||||
const _Bool allow_trail_comma;
|
||||
_Bool allow_comments;
|
||||
_Bool allow_trail_comma;
|
||||
}RJP_parse_state;
|
||||
|
||||
static void irjp_init_parse_stack(RJP_parse_stack* s){
|
||||
@ -175,15 +186,14 @@ static void irjp_init_parse_state(RJP_parse_state* state, const char* str){
|
||||
}
|
||||
static void irjp_delete_parse_state(RJP_parse_state* state){
|
||||
irjp_delete_parse_stack(&state->target_stack);
|
||||
irjp_delete_lex_state(&state->lexstate);
|
||||
}
|
||||
static void irjp_delete_parse_state_no_preserve_root(RJP_parse_state* state){
|
||||
irjp_delete_parse_state(state);
|
||||
rjp_free_value(state->root);
|
||||
state->root = NULL;
|
||||
}
|
||||
|
||||
static inline int irjp_parse_error(RJP_parse_state* state, const char* str){
|
||||
DIAG_PRINT(stderr, "%s: %d:%d\n", str, state->column, state->row);
|
||||
return RJP_PARSE_STATUS_ERR;
|
||||
}
|
||||
|
||||
static int irjp_parse_handle_lexcat(RJP_lex_category cat, RJP_parse_state* state){
|
||||
if(cat == rjp_lex_line_comment || cat == rjp_lex_block_comment)
|
||||
cat = irjp_convert_comment(state->allow_comments);
|
||||
@ -196,14 +206,14 @@ static int irjp_parse_handle_lexcat(RJP_lex_category cat, RJP_parse_state* state
|
||||
return RJP_PARSE_STATUS_SUC;
|
||||
}
|
||||
if(cat == rjp_lex_invalid)
|
||||
return irjp_parse_error(state, "Invalid token");
|
||||
return RJP_PARSE_STATUS_INVALID;
|
||||
|
||||
switch(irjp_parse_stack_current(&state->target_stack)){
|
||||
|
||||
case rjp_parse_start:
|
||||
irjp_parse_stack_set(&state->target_stack, rjp_parse_end);
|
||||
if(irjp_init_value(state->root, cat, state)){
|
||||
return irjp_parse_error(state, "Expected value");
|
||||
return RJP_PARSE_STATUS_NO_ROOT_VALUE;
|
||||
}
|
||||
break;
|
||||
case rjp_parse_first_mem_key:
|
||||
@ -216,10 +226,10 @@ static int irjp_parse_handle_lexcat(RJP_lex_category cat, RJP_parse_state* state
|
||||
if(cat == rjp_lex_string){
|
||||
irjp_parse_stack_set(&state->target_stack, rjp_parse_key_colon);
|
||||
if(!irjp_add_value_to_object(state, state->lexstate.str+state->lexstate.offset, state->lexstate.length)){
|
||||
return irjp_parse_error(state, "Expected member key");
|
||||
return RJP_PARSE_STATUS_MISSING_KEY;
|
||||
}
|
||||
}else{
|
||||
return irjp_parse_error(state, "Expected member key");
|
||||
return RJP_PARSE_STATUS_MISSING_KEY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -232,19 +242,19 @@ static int irjp_parse_handle_lexcat(RJP_lex_category cat, RJP_parse_state* state
|
||||
case rjp_parse_arr_value:
|
||||
irjp_parse_stack_set(&state->target_stack, rjp_parse_arr_comma);
|
||||
if(!irjp_add_value_to_array(cat, state))
|
||||
return irjp_parse_error(state, "Expected value");
|
||||
return RJP_PARSE_STATUS_MISSING_VALUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case rjp_parse_key_colon:
|
||||
if(cat != rjp_lex_colon)
|
||||
return irjp_parse_error(state, "Expected member key");
|
||||
return RJP_PARSE_STATUS_MISSING_COLON;
|
||||
irjp_parse_stack_set(&state->target_stack, rjp_parse_obj_value);
|
||||
break;
|
||||
case rjp_parse_obj_value:
|
||||
irjp_parse_stack_set(&state->target_stack, rjp_parse_obj_comma);
|
||||
if(irjp_init_value(state->lastadded, cat, state)){
|
||||
return irjp_parse_error(state, "Expected value");
|
||||
return RJP_PARSE_STATUS_MISSING_VALUE;
|
||||
}
|
||||
break;
|
||||
case rjp_parse_obj_comma:
|
||||
@ -254,7 +264,7 @@ static int irjp_parse_handle_lexcat(RJP_lex_category cat, RJP_parse_state* state
|
||||
irjp_parse_stack_pop(&state->target_stack);
|
||||
state->curr = state->curr->parent;
|
||||
}else{
|
||||
return irjp_parse_error(state, "Expected comma");
|
||||
return RJP_PARSE_STATUS_MISSING_COMMA;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -265,13 +275,13 @@ static int irjp_parse_handle_lexcat(RJP_lex_category cat, RJP_parse_state* state
|
||||
irjp_parse_stack_pop(&state->target_stack);
|
||||
state->curr = state->curr->parent;
|
||||
}else{
|
||||
return irjp_parse_error(state, "Expected comma");
|
||||
return RJP_PARSE_STATUS_MISSING_COMMA;
|
||||
}
|
||||
break;
|
||||
|
||||
case rjp_parse_end:
|
||||
if(state->lexstate.str[state->lexstate.offset] != 0)
|
||||
return irjp_parse_error(state, "Excess data after end of JSON");
|
||||
return RJP_PARSE_STATUS_EXCESS_DATA;
|
||||
};
|
||||
return RJP_PARSE_STATUS_SUC;
|
||||
}
|
||||
@ -279,18 +289,19 @@ static int irjp_parse_handle_lexcat(RJP_lex_category cat, RJP_parse_state* state
|
||||
//parse loop. it is a successful state though as it just indicates end of input.
|
||||
static int irjp_handle_final_parse_token(RJP_parse_state* state, RJP_lex_category cat){
|
||||
if(state->target_stack.position != 0)
|
||||
return irjp_parse_error(state, "Missing closing brace");
|
||||
return RJP_PARSE_STATUS_MISSING_CLOSE_BRACE;
|
||||
if(cat == rjp_lex_end)
|
||||
return RJP_PARSE_STATUS_SUC;
|
||||
return irjp_parse_error(state, "Invalid Token");
|
||||
return RJP_PARSE_STATUS_INVALID;
|
||||
}
|
||||
|
||||
//Basic parse loop
|
||||
static int irjp_parse(RJP_parse_state* state){
|
||||
RJP_lex_category cat;
|
||||
RJP_parse_status status;
|
||||
for(cat = irjp_lex(&state->lexstate);cat & rjp_lex_accept;cat = irjp_lex(&state->lexstate),state->row += state->lexstate.length){
|
||||
if(irjp_parse_handle_lexcat(cat, state) != RJP_PARSE_STATUS_SUC)
|
||||
return RJP_PARSE_STATUS_ERR;
|
||||
if((status = irjp_parse_handle_lexcat(cat, state)) != RJP_PARSE_STATUS_SUC)
|
||||
return status;
|
||||
}
|
||||
return irjp_handle_final_parse_token(state, cat);
|
||||
}
|
||||
@ -298,43 +309,126 @@ static int irjp_parse(RJP_parse_state* state){
|
||||
//Callback parse loop
|
||||
static int irjp_parse_cback(RJP_parse_state* state, RJP_parse_callback* cback){
|
||||
RJP_lex_category cat;
|
||||
RJP_parse_status status;
|
||||
for(cat = irjp_lex_cback(&state->lexstate, cback);cat & rjp_lex_accept;cat = irjp_lex_cback(&state->lexstate, cback),state->row += state->lexstate.length){
|
||||
if(irjp_parse_handle_lexcat(cat, state) != RJP_PARSE_STATUS_SUC)
|
||||
return RJP_PARSE_STATUS_ERR;
|
||||
if((status = irjp_parse_handle_lexcat(cat, state)) != RJP_PARSE_STATUS_SUC)
|
||||
return status;
|
||||
}
|
||||
return irjp_handle_final_parse_token(state, cat);
|
||||
}
|
||||
RJP_value* rjp_parse(const char* str, int flags){
|
||||
RJP_parse_state state = {.allow_comments = (flags & RJP_PARSE_ALLOW_COMMENTS),
|
||||
.allow_trail_comma = (flags & RJP_PARSE_ALLOW_TRAILING_COMMA)
|
||||
|
||||
char* rjp_parse_error_to_string(RJP_parse_error* err){
|
||||
RJP_parse_state* state = (RJP_parse_state*)err->parsestate;
|
||||
RJP_parse_status status = err->errcode;
|
||||
char* buffer = NULL;
|
||||
const char* format = NULL;
|
||||
switch(status){
|
||||
case RJP_PARSE_STATUS_MISSING_VALUE:
|
||||
format = "Expected value before '%.*s'";
|
||||
buffer = rjp_alloc(snprintf(NULL, 0, format, (int)state->lexstate.length, (state->lexstate.str + state->lexstate.offset)) + 1);
|
||||
sprintf(buffer, format, (int)state->lexstate.length, (state->lexstate.str + state->lexstate.offset));
|
||||
break;
|
||||
case RJP_PARSE_STATUS_MISSING_COMMA:
|
||||
format = "Expected comma before '%.*s'";
|
||||
buffer = rjp_alloc(snprintf(NULL, 0, format, (int)state->lexstate.length, (state->lexstate.str + state->lexstate.offset)) + 1);
|
||||
sprintf(buffer, format, (int)state->lexstate.length, (state->lexstate.str + state->lexstate.offset));
|
||||
break;
|
||||
case RJP_PARSE_STATUS_INVALID:
|
||||
format = "Invalid lex token '%.*s'";
|
||||
buffer = rjp_alloc(snprintf(NULL, 0, format, (int)state->lexstate.length, (state->lexstate.str + state->lexstate.offset)) + 1);
|
||||
sprintf(buffer, format, (int)state->lexstate.length, (state->lexstate.str + state->lexstate.offset));
|
||||
break;
|
||||
case RJP_PARSE_STATUS_NO_ROOT_VALUE:
|
||||
format = "Missing root JSON value";
|
||||
buffer = rjp_alloc(snprintf(NULL, 0, format) + 1);
|
||||
sprintf(buffer, format);
|
||||
break;
|
||||
case RJP_PARSE_STATUS_MISSING_KEY:
|
||||
format = "Expected key before '%.*s'";
|
||||
buffer = rjp_alloc(snprintf(NULL, 0, format, (int)state->lexstate.length, (state->lexstate.str + state->lexstate.offset)) + 1);
|
||||
sprintf(buffer, format, (int)state->lexstate.length, (state->lexstate.str + state->lexstate.offset));
|
||||
break;
|
||||
case RJP_PARSE_STATUS_MISSING_COLON:
|
||||
format = "Expected colon before '%.*s'";
|
||||
buffer = rjp_alloc(snprintf(NULL, 0, format, (int)state->lexstate.length, (state->lexstate.str + state->lexstate.offset)) + 1);
|
||||
sprintf(buffer, format, (int)state->lexstate.length, (state->lexstate.str + state->lexstate.offset));
|
||||
break;
|
||||
case RJP_PARSE_STATUS_EXCESS_DATA:
|
||||
format = "Excess data after JSON";
|
||||
buffer = rjp_alloc(snprintf(NULL, 0, format) + 1);
|
||||
sprintf(buffer, format);
|
||||
break;
|
||||
case RJP_PARSE_STATUS_MISSING_CLOSE_BRACE:
|
||||
format = "Missing closing brace";
|
||||
buffer = rjp_alloc(snprintf(NULL, 0, format) + 1);
|
||||
sprintf(buffer, format);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
irjp_init_parse_state(&state, str);
|
||||
int status = irjp_parse(&state);
|
||||
return buffer;
|
||||
}
|
||||
void rjp_delete_parse_error(RJP_parse_error* err){
|
||||
irjp_delete_parse_state_no_preserve_root((RJP_parse_state*)err->parsestate);
|
||||
rjp_free(err->parsestate);
|
||||
}
|
||||
|
||||
RJP_value* rjp_simple_parse(const char* str){
|
||||
return rjp_parse(str, RJP_PARSE_NONE, NULL);
|
||||
}
|
||||
|
||||
RJP_value* rjp_parse(const char* str, int flags, RJP_parse_error* err){
|
||||
RJP_parse_state* state = rjp_calloc(sizeof(RJP_parse_state), 1);
|
||||
state->allow_comments = (flags & RJP_PARSE_ALLOW_COMMENTS);
|
||||
state->allow_trail_comma = (flags & RJP_PARSE_ALLOW_TRAILING_COMMA);
|
||||
|
||||
irjp_init_parse_state(state, str);
|
||||
irjp_init_lex_state(&state->lexstate);
|
||||
int status = irjp_parse(state);
|
||||
if(status == RJP_PARSE_STATUS_SUC){
|
||||
irjp_delete_parse_stack(&state.target_stack);
|
||||
return state.root;
|
||||
irjp_delete_parse_state(state);
|
||||
RJP_value* root = state->root;
|
||||
rjp_free(state);
|
||||
return root;
|
||||
}else{
|
||||
irjp_delete_parse_state(&state);
|
||||
if(err){
|
||||
err->parsestate = state;
|
||||
err->errcode = status;
|
||||
err->row = state->column;
|
||||
err->column = state->row;
|
||||
}else{
|
||||
irjp_delete_parse_state_no_preserve_root(state);
|
||||
rjp_free(state);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//Callback based parse. Runs identical to normal parsing except sets up callback
|
||||
//lex state and calls callback lex function
|
||||
RJP_value* rjp_parse_cback(int flags, RJP_parse_callback* cback){
|
||||
RJP_parse_state state = {.allow_comments = (flags & RJP_PARSE_ALLOW_COMMENTS),
|
||||
.allow_trail_comma = (flags & RJP_PARSE_ALLOW_TRAILING_COMMA)
|
||||
};
|
||||
irjp_init_parse_state(&state, NULL);
|
||||
irjp_init_lex_cback_state(&state.lexstate);
|
||||
int status = irjp_parse_cback(&state, cback);
|
||||
rjp_free(state.lexstate.str);
|
||||
rjp_free(state.lexstate.buff);
|
||||
RJP_value* rjp_parse_cback(int flags, RJP_parse_callback* cback, RJP_parse_error* err){
|
||||
RJP_parse_state* state = rjp_calloc(sizeof(RJP_parse_state), 1);
|
||||
state->allow_comments = (flags & RJP_PARSE_ALLOW_COMMENTS);
|
||||
state->allow_trail_comma = (flags & RJP_PARSE_ALLOW_TRAILING_COMMA);
|
||||
|
||||
irjp_init_parse_state(state, NULL);
|
||||
irjp_init_lex_cback_state(&state->lexstate);
|
||||
int status = irjp_parse_cback(state, cback);
|
||||
if(status == RJP_PARSE_STATUS_SUC){
|
||||
irjp_delete_parse_stack(&state.target_stack);
|
||||
return state.root;
|
||||
irjp_delete_parse_state(state);
|
||||
RJP_value* root = state->root;
|
||||
rjp_free(state);
|
||||
return root;
|
||||
}else{
|
||||
irjp_delete_parse_state(&state);
|
||||
if(err){
|
||||
err->parsestate = state;
|
||||
err->errcode = status;
|
||||
err->row = state->column;
|
||||
err->column = state->row;
|
||||
}else{
|
||||
irjp_delete_parse_state_no_preserve_root(state);
|
||||
rjp_free(state);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,15 +25,16 @@ int read_callback(char* c, int size, void* userdata){
|
||||
return i;
|
||||
}
|
||||
|
||||
int handle_res(RJP_value* res){
|
||||
int handle_res(RJP_value* res, RJP_parse_error* err){
|
||||
if(res){
|
||||
fprintf(stderr, "Accepted\n");
|
||||
}
|
||||
#ifndef RJP_ENABLE_DIAGNOSTICS
|
||||
else{
|
||||
fprintf(stderr, "Failed\n");
|
||||
char* buf = rjp_parse_error_to_string(err);
|
||||
rjp_delete_parse_error(err);
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
rjp_free(buf);
|
||||
}
|
||||
#endif
|
||||
int failed = res == NULL;
|
||||
rjp_free_value(res);
|
||||
return failed;
|
||||
@ -44,14 +45,16 @@ int test_cbacks(const char* str, RJP_parse_flag flags){
|
||||
cbacks.read = read_callback;
|
||||
cbacks.data = &cback_data;
|
||||
RJP_value* res;
|
||||
res = rjp_parse_cback(flags, &cbacks);
|
||||
return handle_res(res);
|
||||
RJP_parse_error err;
|
||||
res = rjp_parse_cback(flags, &cbacks, &err);
|
||||
return handle_res(res, &err);
|
||||
}
|
||||
|
||||
int test(const char* str, RJP_parse_flag flags){
|
||||
RJP_value* res;
|
||||
res = rjp_parse(str, flags);
|
||||
return handle_res(res);
|
||||
RJP_parse_error err;
|
||||
res = rjp_parse(str, flags, &err);
|
||||
return handle_res(res, &err);
|
||||
}
|
||||
|
||||
struct parse_pair{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user