⚡ optimize error handling in json module
This commit is contained in:
parent
135665a5df
commit
bd3ae8c440
|
@ -37,6 +37,8 @@ std::string get_content(token_type type) {
|
|||
case token_type::tok_id: return "identifier";
|
||||
case token_type::tok_bool: return "boolean";
|
||||
}
|
||||
// unreachable
|
||||
return "";
|
||||
}
|
||||
|
||||
struct token {
|
||||
|
@ -46,7 +48,6 @@ struct token {
|
|||
|
||||
class json {
|
||||
private:
|
||||
usize parse_error = 0;
|
||||
std::string text = "";
|
||||
usize line = 1;
|
||||
usize ptr = 0;
|
||||
|
@ -77,11 +78,16 @@ private:
|
|||
var vector_object_generate(gc*);
|
||||
void hash_member(nas_hash&, gc*);
|
||||
var hash_object_generate(gc*);
|
||||
void check_eof();
|
||||
static std::string& error_info() {
|
||||
static std::string info = "";
|
||||
return info;
|
||||
}
|
||||
|
||||
public:
|
||||
std::string stringify(var&);
|
||||
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) {
|
||||
|
@ -152,6 +158,11 @@ void json::next() {
|
|||
while(ptr<text.length() && !check(text[ptr])) {
|
||||
if (text[ptr]=='\n') {
|
||||
++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;
|
||||
}
|
||||
|
@ -216,10 +227,9 @@ void json::next() {
|
|||
|
||||
void json::match(token_type type) {
|
||||
if (this_token.type!=type) {
|
||||
std::cerr << "json::parse: line " << line << ": expect ";
|
||||
std::cerr << get_content(type) << " but get `";
|
||||
std::cerr << this_token.content << "`.\n";
|
||||
++parse_error;
|
||||
error_info() += "json::parse: line " + std::to_string(line);
|
||||
error_info() += ": expect " + get_content(type) + " but get `";
|
||||
error_info() += this_token.content + "`.\n";
|
||||
}
|
||||
next();
|
||||
return;
|
||||
|
@ -292,14 +302,28 @@ var json::hash_object_generate(gc* ngc) {
|
|||
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) {
|
||||
usize parse_error = 0;
|
||||
usize line = 1;
|
||||
usize ptr = 0;
|
||||
this_token = {token_type::tok_eof, ""};
|
||||
error_info() = "";
|
||||
|
||||
if (input.empty()) {
|
||||
std::cerr << "json::parse: empty string.\n";
|
||||
error_info() += "json::parse: empty string.\n";
|
||||
++parse_error;
|
||||
return nil;
|
||||
}
|
||||
|
@ -308,12 +332,14 @@ var json::parse(const std::string& input, gc* ngc) {
|
|||
if (this_token.type==token_type::tok_lbrkt) {
|
||||
ngc->temp = temp_stack = ngc->alloc(vm_type::vm_vec);
|
||||
auto result = vector_object_generate(ngc);
|
||||
check_eof();
|
||||
ngc->temp = nil;
|
||||
temp_stack = nil;
|
||||
return result;
|
||||
} else {
|
||||
ngc->temp = temp_stack = ngc->alloc(vm_type::vm_vec);
|
||||
auto result = hash_object_generate(ngc);
|
||||
check_eof();
|
||||
ngc->temp = nil;
|
||||
temp_stack = nil;
|
||||
return result;
|
||||
|
@ -334,17 +360,17 @@ var parse(var* args, usize size, gc* ngc) {
|
|||
if (!input.is_str()) {
|
||||
return nas_err("json::parse", "must use string");
|
||||
}
|
||||
json instance;
|
||||
auto result = instance.parse(input.str(), ngc);
|
||||
if (instance.has_error()) {
|
||||
return nas_err("json::parse", "parse error");
|
||||
}
|
||||
return result;
|
||||
return json().parse(input.str(), ngc);
|
||||
}
|
||||
|
||||
var get_error(var* args, usize size, gc* ngc) {
|
||||
return ngc->newstr(json::get_error());
|
||||
}
|
||||
|
||||
module_func_info func_tbl[] = {
|
||||
{"stringify", stringify},
|
||||
{"parse", parse},
|
||||
{"get_error", get_error},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ use std.dylib;
|
|||
var _dynamic_lib = dylib.dlopen("libjson."~(os.platform()=="windows"?"dll":"so"));
|
||||
var _stringify = _dynamic_lib.stringify;
|
||||
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 stringify = func(object) {
|
||||
|
@ -14,4 +16,8 @@ var stringify = func(object) {
|
|||
|
||||
var parse = func(input_string) {
|
||||
return _call(_parse, input_string);
|
||||
}
|
||||
|
||||
var get_error = func() {
|
||||
return _no_param_call(_get_error);
|
||||
}
|
|
@ -39,6 +39,36 @@ println(ss, "\n");
|
|||
println(json.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 bar = process_bar.high_resolution_bar(30);
|
||||
var tmp = [
|
||||
|
|
Loading…
Reference in New Issue