From 004f2bb3ad6f3a022df7335bc102bd4472f992f6 Mon Sep 17 00:00:00 2001 From: Mahbub Alam Date: Fri, 13 Oct 2023 21:33:01 -0400 Subject: [PATCH] Support non-dictionary json objects (list, tuple, string, number, bool, null) --- .gitignore | 2 + 3rd/cjson/src/cJSONw.cpp | 182 +++++++++++++++++++++++---------------- tests/80_json.py | 2 +- tests/82_ldtk.py | 2 +- 4 files changed, 111 insertions(+), 77 deletions(-) diff --git a/.gitignore b/.gitignore index fee5b91b..70a3d99a 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ libpocketpy.dylib .xmake/ tests/res/WorldMap_Free_layout.ldtk tests/res/WorldMap_GridVania_layout.ldtk + +*.gcda diff --git a/3rd/cjson/src/cJSONw.cpp b/3rd/cjson/src/cJSONw.cpp index b640eb6b..59391c0b 100644 --- a/3rd/cjson/src/cJSONw.cpp +++ b/3rd/cjson/src/cJSONw.cpp @@ -2,90 +2,122 @@ namespace pkpy{ + +static std::string convert_python_object_to_string(PyObject* obj, VM* vm); +static PyObject* convert_cjson_to_python_object(const cJSON * const item, VM* vm); + + +static std::string convert_list_to_string(const List& list, VM* vm){ + bool extra_comma_flag = false; + std::string output = "["; + for(auto& element : list){ + output = output + convert_python_object_to_string(element, vm) + ", "; + extra_comma_flag = true; + } + if(extra_comma_flag){ + output.pop_back(); + output.pop_back(); + } + return output + "]"; +} + +static std::string convert_tuple_to_string(const Tuple& tuple, VM* vm){ + bool extra_comma_flag = false; + std::string output = "["; + + for(auto& element : tuple){ + output = output + convert_python_object_to_string(element, vm) + ", "; + extra_comma_flag = true; + } + if (extra_comma_flag){ + output.pop_back(); + output.pop_back(); + } + return output + "]"; +} + static std::string covert_dict_to_string(const Dict& dict, VM* vm){ std::string output = "{"; dict.apply([&](PyObject* key, PyObject* val){ output = output + "\"" + CAST(Str&, key).c_str() + "\":"; - try{ - Dict child_dict = CAST(Dict&, val); - std::string chilld_str = covert_dict_to_string(child_dict, vm); - output = output + chilld_str + ","; - } - catch(...) { - if (is_float(val)){ - output = output + std::to_string(CAST(f64, val)) + ","; - } - else if(is_int(val)){ - output = output + std::to_string(CAST(i64, val)) + ","; - } - else{ - output = output + "\"" + CAST(Str&, val).c_str() + "\","; - } - } - + output = output + convert_python_object_to_string(val, vm) + ","; }); output.pop_back(); return output + "}"; } -static Dict convert_cjson_to_dict(const cJSON * const item, VM* vm) -{ - - Dict output(vm); +static std::string convert_python_object_to_string(PyObject* obj, VM* vm){ + if (is_type(obj, vm->tp_int)){ + return std::to_string(CAST(i64, obj)); + } + else if (is_type(obj, vm->tp_float)){ + return std::to_string(CAST(f64, obj)); + } + else if (is_type(obj, vm->tp_bool)){ + if (obj == vm->True){ + return "true"; + } + else{ + return "false"; + } + } + else if (is_type(obj, vm->tp_str)){ + return std::string("\"") + CAST(Str&, obj).c_str() + std::string("\""); + } + else if (is_type(obj, vm->tp_dict)){ + return covert_dict_to_string(CAST(Dict&, obj), vm); + + } + else if (is_type(obj, vm->tp_list)){ + return convert_list_to_string(CAST(List&, obj), vm); + } + else if(is_type(obj, vm->tp_tuple)){ + return convert_tuple_to_string(CAST(Tuple&, obj), vm); + } + return "null"; +} +static PyObject* convert_cjson_to_list(const cJSON * const item, VM* vm){ List list; + cJSON *element = item->child; + while(element != NULL){ + list.push_back(convert_cjson_to_python_object(element, vm)); + element = element->next; + } + return VAR(list); +} - if ((item == NULL)) +static PyObject* convert_cjson_to_dict(const cJSON* const item, VM* vm){ + Dict output(vm); + cJSON *child = item->child; + while(child != NULL){ + const cJSON *child_value = cJSON_GetObjectItemCaseSensitive(item, child->string); + output.set(VAR(Str(child->string)), convert_cjson_to_python_object(child_value, vm)); + child = child->next; + } + return VAR(output); +} +static PyObject* convert_cjson_to_python_object(const cJSON * const item, VM* vm) +{ + if (cJSON_IsString(item)) { - return NULL; + return VAR(Str(item->valuestring)); } - - if (((item->type) & 0xFF) == cJSON_Object){ - cJSON *child = item->child; - while(child != NULL){ - const cJSON *child_value = cJSON_GetObjectItemCaseSensitive(item, child->string); - - if (cJSON_IsString(child_value)) - { - output.set(VAR(Str(child->string)), VAR(Str(child_value->valuestring))); - } - else if (cJSON_IsNumber(child_value)){ - output.set(VAR(Str(child->string)), VAR(child_value->valueint)); - } - else if (cJSON_IsBool(child_value)){ - output.set(VAR(Str(child->string)), child_value->valueint!=0 ? vm->True : vm->False); - } - else if (cJSON_IsNull(child_value)){ - output.set(VAR(Str(child->string)), vm->None); - } - else if (cJSON_IsArray(child_value)){ - cJSON *array_child = child_value->child; - while(array_child != NULL){ - if (cJSON_IsString(array_child)) - { - list.push_back(VAR(Str(array_child->valuestring))); - } - else if (cJSON_IsNumber(array_child)){ - list.push_back(VAR(array_child->valueint)); - } - else if (cJSON_IsBool(array_child)){ - list.push_back(child_value->valueint!=0 ? vm->True : vm->False); - } - else if (cJSON_IsNull(array_child)){ - list.push_back(vm->None); - } - array_child = array_child->next; - } - output.set(VAR(Str(child->string)), VAR(list)); - } - else if (cJSON_IsObject(child_value)){ - Dict child_object = convert_cjson_to_dict(child_value, vm); - output.set(VAR(Str(child->string)), VAR(child_object)); - } - child = child->next; - } - + else if (cJSON_IsNumber(item)){ + return VAR(item->valueint); } - return output; + else if (cJSON_IsBool(item)){ + return item->valueint!=0 ? vm->True : vm->False; + } + else if (cJSON_IsNull(item)){ + return vm->None; + } + else if (cJSON_IsArray(item)){ + return convert_cjson_to_list(item, vm); + } + else if (cJSON_IsObject(item)){ + return convert_cjson_to_dict(item, vm); + } + return vm->None; } void add_module_cjson(VM* vm){ @@ -93,17 +125,17 @@ void add_module_cjson(VM* vm){ vm->bind_func<1>(mod, "loads", [](VM* vm, ArgsView args) { const Str& expr = CAST(Str&, args[0]); + cJSON *json = cJSON_Parse(expr.c_str()); - Dict output = convert_cjson_to_dict(json, vm); - return VAR(output); + PyObject* output = convert_cjson_to_python_object(json, vm); + cJSON_Delete(json); + return output; }); vm->bind_func<1>(mod, "dumps", [](VM* vm, ArgsView args) { - - const Dict& dict = CAST(Dict&, args[0]); - std::string str = covert_dict_to_string(dict, vm); + std::string str = convert_python_object_to_string(args[0], vm); return VAR(str); }); diff --git a/tests/80_json.py b/tests/80_json.py index d821ab92..f6e467bb 100644 --- a/tests/80_json.py +++ b/tests/80_json.py @@ -14,7 +14,7 @@ a = { 'h': False } -import json +import cjson as json _j = json.dumps(a) _a = json.loads(_j) diff --git a/tests/82_ldtk.py b/tests/82_ldtk.py index f60d19ff..bfb064b5 100644 --- a/tests/82_ldtk.py +++ b/tests/82_ldtk.py @@ -1,4 +1,4 @@ -import json +import cjson as json _2489KB = 'WorldMap_GridVania_layout.ldtk' _1093KB = 'WorldMap_Free_layout.ldtk'