optimize error handling in json module

This commit is contained in:
ValKmjolnir 2023-11-29 23:24:29 +08:00
parent 135665a5df
commit bd3ae8c440
3 changed files with 75 additions and 13 deletions

View File

@ -37,6 +37,8 @@ std::string get_content(token_type type) {
case token_type::tok_id: return "identifier"; case token_type::tok_id: return "identifier";
case token_type::tok_bool: return "boolean"; case token_type::tok_bool: return "boolean";
} }
// unreachable
return "";
} }
struct token { struct token {
@ -46,7 +48,6 @@ struct token {
class json { class json {
private: private:
usize parse_error = 0;
std::string text = ""; std::string text = "";
usize line = 1; usize line = 1;
usize ptr = 0; usize ptr = 0;
@ -77,11 +78,16 @@ private:
var vector_object_generate(gc*); var vector_object_generate(gc*);
void hash_member(nas_hash&, gc*); void hash_member(nas_hash&, gc*);
var hash_object_generate(gc*); var hash_object_generate(gc*);
void check_eof();
static std::string& error_info() {
static std::string info = "";
return info;
}
public: public:
std::string stringify(var&); std::string stringify(var&);
var parse(const std::string&, gc*); var parse(const std::string&, gc*);
bool has_error() const { return parse_error; } static const std::string& get_error() { return error_info(); }
}; };
std::string json::var_generate(var& value) { std::string json::var_generate(var& value) {
@ -152,6 +158,11 @@ void json::next() {
while(ptr<text.length() && !check(text[ptr])) { while(ptr<text.length() && !check(text[ptr])) {
if (text[ptr]=='\n') { if (text[ptr]=='\n') {
++line; ++line;
} else if (text[ptr]!=' ' && text[ptr]!='\t') {
error_info() += "json::parse: line " + std::to_string(line);
error_info() += ": invalid character `";
error_info() += text[ptr];
error_info() += "`\n";
} }
++ptr; ++ptr;
} }
@ -216,10 +227,9 @@ void json::next() {
void json::match(token_type type) { void json::match(token_type type) {
if (this_token.type!=type) { if (this_token.type!=type) {
std::cerr << "json::parse: line " << line << ": expect "; error_info() += "json::parse: line " + std::to_string(line);
std::cerr << get_content(type) << " but get `"; error_info() += ": expect " + get_content(type) + " but get `";
std::cerr << this_token.content << "`.\n"; error_info() += this_token.content + "`.\n";
++parse_error;
} }
next(); next();
return; return;
@ -292,14 +302,28 @@ var json::hash_object_generate(gc* ngc) {
return hash_object; return hash_object;
} }
void json::check_eof() {
next();
if (this_token.type==token_type::tok_eof) {
return;
}
while (this_token.type!=token_type::tok_eof) {
error_info() += "json::parse: line " + std::to_string(line);
error_info() += ": expect " + get_content(token_type::tok_eof);
error_info() += " but get `" + this_token.content + "`.\n";
next();
}
}
var json::parse(const std::string& input, gc* ngc) { var json::parse(const std::string& input, gc* ngc) {
usize parse_error = 0; usize parse_error = 0;
usize line = 1; usize line = 1;
usize ptr = 0; usize ptr = 0;
this_token = {token_type::tok_eof, ""}; this_token = {token_type::tok_eof, ""};
error_info() = "";
if (input.empty()) { if (input.empty()) {
std::cerr << "json::parse: empty string.\n"; error_info() += "json::parse: empty string.\n";
++parse_error; ++parse_error;
return nil; return nil;
} }
@ -308,12 +332,14 @@ var json::parse(const std::string& input, gc* ngc) {
if (this_token.type==token_type::tok_lbrkt) { if (this_token.type==token_type::tok_lbrkt) {
ngc->temp = temp_stack = ngc->alloc(vm_type::vm_vec); ngc->temp = temp_stack = ngc->alloc(vm_type::vm_vec);
auto result = vector_object_generate(ngc); auto result = vector_object_generate(ngc);
check_eof();
ngc->temp = nil; ngc->temp = nil;
temp_stack = nil; temp_stack = nil;
return result; return result;
} else { } else {
ngc->temp = temp_stack = ngc->alloc(vm_type::vm_vec); ngc->temp = temp_stack = ngc->alloc(vm_type::vm_vec);
auto result = hash_object_generate(ngc); auto result = hash_object_generate(ngc);
check_eof();
ngc->temp = nil; ngc->temp = nil;
temp_stack = nil; temp_stack = nil;
return result; return result;
@ -334,17 +360,17 @@ var parse(var* args, usize size, gc* ngc) {
if (!input.is_str()) { if (!input.is_str()) {
return nas_err("json::parse", "must use string"); return nas_err("json::parse", "must use string");
} }
json instance; return json().parse(input.str(), ngc);
auto result = instance.parse(input.str(), ngc); }
if (instance.has_error()) {
return nas_err("json::parse", "parse error"); var get_error(var* args, usize size, gc* ngc) {
} return ngc->newstr(json::get_error());
return result;
} }
module_func_info func_tbl[] = { module_func_info func_tbl[] = {
{"stringify", stringify}, {"stringify", stringify},
{"parse", parse}, {"parse", parse},
{"get_error", get_error},
{nullptr, nullptr} {nullptr, nullptr}
}; };

View File

@ -6,6 +6,8 @@ use std.dylib;
var _dynamic_lib = dylib.dlopen("libjson."~(os.platform()=="windows"?"dll":"so")); var _dynamic_lib = dylib.dlopen("libjson."~(os.platform()=="windows"?"dll":"so"));
var _stringify = _dynamic_lib.stringify; var _stringify = _dynamic_lib.stringify;
var _parse = _dynamic_lib.parse; var _parse = _dynamic_lib.parse;
var _get_error = _dynamic_lib.get_error;
var _no_param_call = dylib.limitcall(0);
var _call = dylib.limitcall(1); var _call = dylib.limitcall(1);
var stringify = func(object) { var stringify = func(object) {
@ -15,3 +17,7 @@ var stringify = func(object) {
var parse = func(input_string) { var parse = func(input_string) {
return _call(_parse, input_string); return _call(_parse, input_string);
} }
var get_error = func() {
return _no_param_call(_get_error);
}

View File

@ -39,6 +39,36 @@ println(ss, "\n");
println(json.parse(ss), "\n"); println(json.parse(ss), "\n");
println(libjson.parse(ss), "\n"); println(libjson.parse(ss), "\n");
var test_func = func(input_string) {
var result = libjson.parse(input_string);
var errno = libjson.get_error();
if (!size(errno)) {
println("\e[92;1msuccess\e[0m:");
println(" ", result);
} else {
println("\e[91;1merror\e[0m:");
foreach(var err; split("\n", errno)) {
println(" |-> ", err);
}
println(" +-> generated with error:");
println(" +-> ", result);
}
}
test_func("[[]]");
test_func("{\"1\":1}");
test_func("[[[}]]]");
test_func("=-==_+_+_+");
test_func("123");
test_func(libjson.stringify({
a: 0,
b: nil,
c: "this is a string",
d: [{}, [[1, 2, 4, 8, 16]]]
}));
test_func("");
println();
var test_json = func(json) { var test_json = func(json) {
var bar = process_bar.high_resolution_bar(30); var bar = process_bar.high_resolution_bar(30);
var tmp = [ var tmp = [