Consolidate JSON, JSONParseResults and JSONParser into JSON

Renames JSON.parse_string() to parse()
Renames JSON.decode_data() to stringify()
This commit is contained in:
Marcel Admiraal 2020-12-29 18:12:33 +00:00
parent df170c8af0
commit 2bafcd3422
25 changed files with 188 additions and 430 deletions

View file

@ -35,7 +35,6 @@
#include "core/debugger/engine_debugger.h"
#include "core/io/file_access_compressed.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/json.h"
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h"
@ -2137,80 +2136,6 @@ void _Engine::_bind_methods() {
_Engine *_Engine::singleton = nullptr;
////// _JSON //////
void JSONParseResult::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_error"), &JSONParseResult::get_error);
ClassDB::bind_method(D_METHOD("get_error_string"), &JSONParseResult::get_error_string);
ClassDB::bind_method(D_METHOD("get_error_line"), &JSONParseResult::get_error_line);
ClassDB::bind_method(D_METHOD("get_result"), &JSONParseResult::get_result);
ClassDB::bind_method(D_METHOD("set_error", "error"), &JSONParseResult::set_error);
ClassDB::bind_method(D_METHOD("set_error_string", "error_string"), &JSONParseResult::set_error_string);
ClassDB::bind_method(D_METHOD("set_error_line", "error_line"), &JSONParseResult::set_error_line);
ClassDB::bind_method(D_METHOD("set_result", "result"), &JSONParseResult::set_result);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "error", PROPERTY_HINT_NONE, "Error", PROPERTY_USAGE_CLASS_IS_ENUM), "set_error", "get_error");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "error_string"), "set_error_string", "get_error_string");
ADD_PROPERTY(PropertyInfo(Variant::INT, "error_line"), "set_error_line", "get_error_line");
ADD_PROPERTY(PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_result", "get_result");
}
void JSONParseResult::set_error(Error p_error) {
error = p_error;
}
Error JSONParseResult::get_error() const {
return error;
}
void JSONParseResult::set_error_string(const String &p_error_string) {
error_string = p_error_string;
}
String JSONParseResult::get_error_string() const {
return error_string;
}
void JSONParseResult::set_error_line(int p_error_line) {
error_line = p_error_line;
}
int JSONParseResult::get_error_line() const {
return error_line;
}
void JSONParseResult::set_result(const Variant &p_result) {
result = p_result;
}
Variant JSONParseResult::get_result() const {
return result;
}
void _JSON::_bind_methods() {
ClassDB::bind_method(D_METHOD("print", "value", "indent", "sort_keys", "full_precision"), &_JSON::print, DEFVAL(String()), DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("parse", "json"), &_JSON::parse);
}
String _JSON::print(const Variant &p_value, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
return JSON::print(p_value, p_indent, p_sort_keys, p_full_precision);
}
Ref<JSONParseResult> _JSON::parse(const String &p_json) {
Ref<JSONParseResult> result;
result.instance();
result->error = JSON::parse(p_json, result->result, result->error_string, result->error_line);
if (result->error != OK) {
ERR_PRINT(vformat("Error parsing JSON at line %s: %s", result->error_line, result->error_string));
}
return result;
}
_JSON *_JSON::singleton = nullptr;
////// _EngineDebugger //////
void _EngineDebugger::_bind_methods() {

View file

@ -656,54 +656,6 @@ public:
_Engine() { singleton = this; }
};
class _JSON;
class JSONParseResult : public RefCounted {
GDCLASS(JSONParseResult, RefCounted);
friend class _JSON;
Error error;
String error_string;
int error_line = -1;
Variant result;
protected:
static void _bind_methods();
public:
void set_error(Error p_error);
Error get_error() const;
void set_error_string(const String &p_error_string);
String get_error_string() const;
void set_error_line(int p_error_line);
int get_error_line() const;
void set_result(const Variant &p_result);
Variant get_result() const;
JSONParseResult() {}
};
class _JSON : public Object {
GDCLASS(_JSON, Object);
protected:
static void _bind_methods();
static _JSON *singleton;
public:
static _JSON *get_singleton() { return singleton; }
String print(const Variant &p_value, const String &p_indent = "", bool p_sort_keys = false, bool p_full_precision = false);
Ref<JSONParseResult> parse(const String &p_json);
_JSON() { singleton = this; }
};
class _EngineDebugger : public Object {
GDCLASS(_EngineDebugger, Object);

View file

@ -45,7 +45,7 @@ const char *JSON::tk_name[TK_MAX] = {
"EOF",
};
static String _make_indent(const String &p_indent, int p_size) {
String JSON::_make_indent(const String &p_indent, int p_size) {
String indent_text = "";
if (!p_indent.is_empty()) {
for (int i = 0; i < p_size; i++) {
@ -55,7 +55,7 @@ static String _make_indent(const String &p_indent, int p_size) {
return indent_text;
}
String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision) {
String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision) {
String colon = ":";
String end_statement = "";
@ -100,7 +100,7 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_
s += ",";
s += end_statement;
}
s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(a[i], p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
s += _make_indent(p_indent, p_cur_indent + 1) + _stringify(a[i], p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
}
s += end_statement + _make_indent(p_indent, p_cur_indent) + "]";
p_markers.erase(a.id());
@ -126,9 +126,9 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_
s += ",";
s += end_statement;
}
s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
s += _make_indent(p_indent, p_cur_indent + 1) + _stringify(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
s += colon;
s += _print_var(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
s += _stringify(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
}
s += end_statement + _make_indent(p_indent, p_cur_indent) + "}";
@ -140,11 +140,6 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_
}
}
String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
Set<const void *> markers;
return _print_var(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision);
}
Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) {
while (p_len > 0) {
switch (p_str[index]) {
@ -499,7 +494,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index,
return ERR_PARSE_ERROR;
}
Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {
Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {
const char32_t *str = p_json.ptr();
int idx = 0;
int len = p_json.length();
@ -530,34 +525,24 @@ Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int &
return err;
}
Error JSONParser::parse_string(const String &p_json_string) {
return JSON::parse(p_json_string, data, err_text, err_line);
}
String JSONParser::get_error_text() const {
return err_text;
}
int JSONParser::get_error_line() const {
return err_line;
}
Variant JSONParser::get_data() const {
return data;
String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
Set<const void *> markers;
return _stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision);
}
Error JSONParser::decode_data(const Variant &p_data, const String &p_indent, bool p_sort_keys) {
string = JSON::print(p_data, p_indent, p_sort_keys);
data = p_data;
return OK;
Error JSON::parse(const String &p_json_string) {
Error err = _parse_string(p_json_string, data, err_str, err_line);
if (err == Error::OK) {
err_line = 0;
}
return err;
}
String JSONParser::get_string() const {
return string;
}
void JSON::_bind_methods() {
ClassDB::bind_method(D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse);
void JSONParser::_bind_methods() {
ClassDB::bind_method(D_METHOD("parse_string", "json_string"), &JSONParser::parse_string);
ClassDB::bind_method(D_METHOD("get_error_text"), &JSONParser::get_error_text);
ClassDB::bind_method(D_METHOD("get_error_line"), &JSONParser::get_error_line);
ClassDB::bind_method(D_METHOD("get_data"), &JSONParser::get_data);
ClassDB::bind_method(D_METHOD("decode_data", "data", "indent", "sort_keys"), &JSONParser::decode_data, DEFVAL(""), DEFVAL(true));
ClassDB::bind_method(D_METHOD("get_string"), &JSONParser::get_string);
ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data);
ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line);
ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message);
}

View file

@ -33,7 +33,10 @@
#include "core/object/ref_counted.h"
#include "core/variant/variant.h"
class JSON {
class JSON : public RefCounted {
GDCLASS(JSON, RefCounted);
enum TokenType {
TK_CURLY_BRACKET_OPEN,
TK_CURLY_BRACKET_CLOSE,
@ -60,39 +63,30 @@ class JSON {
Variant value;
};
static const char *tk_name[TK_MAX];
Variant data;
String err_str;
int err_line = 0;
static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision = false);
static const char *tk_name[];
static String _make_indent(const String &p_indent, int p_size);
static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision = false);
static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
public:
static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false);
static Error parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line);
};
class JSONParser : public RefCounted {
GDCLASS(JSONParser, RefCounted);
Variant data;
String string;
String err_text;
int err_line = 0;
static Error _parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line);
protected:
static void _bind_methods();
public:
Error parse_string(const String &p_json_string);
String get_error_text() const;
int get_error_line() const;
Variant get_data() const;
String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false);
Error parse(const String &p_json_string);
Error decode_data(const Variant &p_data, const String &p_indent = "", bool p_sort_keys = true);
String get_string() const;
inline Variant get_data() const { return data; }
inline int get_error_line() const { return err_line; }
inline String get_error_message() const { return err_str; }
};
#endif // JSON_H

View file

@ -86,7 +86,6 @@ static _OS *_os = nullptr;
static _Engine *_engine = nullptr;
static _ClassDB *_classdb = nullptr;
static _Marshalls *_marshalls = nullptr;
static _JSON *_json = nullptr;
static _EngineDebugger *_engine_debugger = nullptr;
static IP *ip = nullptr;
@ -199,7 +198,7 @@ void register_core_types() {
ClassDB::register_class<_Semaphore>();
ClassDB::register_class<XMLParser>();
ClassDB::register_class<JSONParser>();
ClassDB::register_class<JSON>();
ClassDB::register_class<ConfigFile>();
@ -212,8 +211,6 @@ void register_core_types() {
ClassDB::register_class<EncodedObjectAsID>();
ClassDB::register_class<RandomNumberGenerator>();
ClassDB::register_class<JSONParseResult>();
ClassDB::register_virtual_class<ResourceImporter>();
ip = IP::create();
@ -227,7 +224,6 @@ void register_core_types() {
_engine = memnew(_Engine);
_classdb = memnew(_ClassDB);
_marshalls = memnew(_Marshalls);
_json = memnew(_JSON);
_engine_debugger = memnew(_EngineDebugger);
}
@ -256,7 +252,6 @@ void register_core_singletons() {
ClassDB::register_class<TranslationServer>();
ClassDB::register_virtual_class<Input>();
ClassDB::register_class<InputMap>();
ClassDB::register_class<_JSON>();
ClassDB::register_class<Expression>();
ClassDB::register_class<_EngineDebugger>();
ClassDB::register_class<Time>();
@ -274,7 +269,6 @@ void register_core_singletons() {
Engine::get_singleton()->add_singleton(Engine::Singleton("TranslationServer", TranslationServer::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("Input", Input::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("JSON", _JSON::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _EngineDebugger::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton()));
}
@ -286,7 +280,6 @@ void unregister_core_types() {
memdelete(_engine);
memdelete(_classdb);
memdelete(_marshalls);
memdelete(_json);
memdelete(_engine_debugger);
memdelete(_geometry_2d);

View file

@ -32,6 +32,7 @@
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/io/json.h"
#include "core/io/marshalls.h"
#include "core/io/resource.h"
#include "core/math/math_funcs.h"
@ -1838,6 +1839,11 @@ String Variant::stringify(List<const void *> &stack) const {
return "";
}
String Variant::to_json_string() const {
JSON json;
return json.stringify(*this);
}
Variant::operator Vector2() const {
if (type == VECTOR2) {
return *reinterpret_cast<const Vector2 *>(_data._mem);

View file

@ -645,6 +645,7 @@ public:
bool hash_compare(const Variant &p_variant) const;
bool booleanize() const;
String stringify(List<const void *> &stack) const;
String to_json_string() const;
void static_assign(const Variant &p_variant);
static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants);

View file

@ -1066,11 +1066,13 @@
<description>
Returns the internal type of the given Variant object, using the [enum Variant.Type] values.
[codeblock]
p = parse_json('["a", "b", "c"]')
if typeof(p) == TYPE_ARRAY:
print(p[0]) # Prints a
var json = JSON.new()
json.parse('["a", "b", "c"]')
var result = json.get_data()
if typeof(result) == TYPE_ARRAY:
print(result[0]) # Prints a
else:
print("unexpected results")
print("Unexpected result")
[/codeblock]
</description>
</method>
@ -1211,9 +1213,6 @@
<member name="InputMap" type="InputMap" setter="" getter="">
The [InputMap] singleton.
</member>
<member name="JSON" type="JSON" setter="" getter="">
The [JSON] singleton.
</member>
<member name="JavaClassWrapper" type="JavaClassWrapper" setter="" getter="">
The [JavaClassWrapper] singleton.
[b]Note:[/b] Only implemented on Android.

View file

@ -1,45 +1,88 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="JSON" inherits="Object" version="4.0">
<class name="JSON" inherits="RefCounted" version="4.0">
<brief_description>
Helper class for parsing JSON data.
Helper class for creating and parsing JSON data.
</brief_description>
<description>
Helper class for parsing JSON data. For usage example and other important hints, see [JSONParseResult].
The [JSON] enables all data types to be converted to and from a JSON string. This useful for serializing data to save to a file or send over the network.
[method stringify] is used to convert any data type into a JSON string.
[method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [method get_data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean.
[b]Example[/b]
[codeblock]
var data_to_send = ["a", "b", "c"]
var json = JSON.new()
var json_string = json.stringify(data_to_send)
# Save data
# ...
# Retrieve data
var error = json.parse(json_string)
if error == OK:
var data_received = json.get_data()
if typeof(data_received) == TYPE_ARRAY:
print(data_received) # Prints array
else:
print("Unexpected data")
else:
print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
[/codeblock]
</description>
<tutorials>
</tutorials>
<methods>
<method name="parse">
<return type="JSONParseResult">
<method name="get_data" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="json" type="String">
</argument>
<description>
Parses a JSON-encoded string and returns a [JSONParseResult] containing the result.
Returns the [Variant] containing the data of a successful [method parse].
[b]Note:[/b] It will return [code]Null[/code] if the last call to parse was unsuccessful or [method parse] has not yet been called.
</description>
</method>
<method name="print">
<method name="get_error_line" qualifiers="const">
<return type="int">
</return>
<description>
Returns [code]0[/code] if the last call to [method parse] was successful, or the line number where the parse failed.
</description>
</method>
<method name="get_error_message" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="value" type="Variant">
<description>
Returns an empty string if the last call to [method parse] was successful, or the error message if it failed.
</description>
</method>
<method name="parse">
<return type="int" enum="Error">
</return>
<argument index="0" name="json_string" type="String">
</argument>
<description>
Attempts to parse the [code]json_string[/code] provided.
Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [method get_data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure.
</description>
</method>
<method name="stringify">
<return type="String">
</return>
<argument index="0" name="data" type="Variant">
</argument>
<argument index="1" name="indent" type="String" default="&quot;&quot;">
</argument>
<argument index="2" name="sort_keys" type="bool" default="false">
<argument index="2" name="sort_keys" type="bool" default="true">
</argument>
<argument index="3" name="full_precision" type="bool" default="false">
</argument>
<description>
Converts a [Variant] var to JSON text and returns the result. Useful for serializing data to store or send over the network.
[b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a Variant to JSON text will convert all numerical values to [float] types.
[b]Note:[/b] If [code]full_precision[/code] is true, when printing floats, the unreliable digits are printed in addition to the reliable digits to guarantee exact decoding.
Use [code]indent[/code] parameter to pretty print the output.
[b]Note:[/b] If [code]full_precision[/code] is true, when stringifying floats, the unreliable digits are stringified in addition to the reliable digits to guarantee exact decoding.
Use [code]indent[/code] parameter to pretty stringify the output.
[b]Example output:[/b]
[codeblock]
## JSON.print(my_dictionary)
## JSON.stringify(my_dictionary)
{"name":"my_dictionary","version":"1.0.0","entities":[{"name":"entity_0","value":"value_0"},{"name":"entity_1","value":"value_1"}]}
## JSON.print(my_dictionary, "\t")
## JSON.stringify(my_dictionary, "\t")
{
"name": "my_dictionary",
"version": "1.0.0",

View file

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="JSONParseResult" inherits="RefCounted" version="4.0">
<brief_description>
Data class wrapper for decoded JSON.
</brief_description>
<description>
Returned by [method JSON.parse], [JSONParseResult] contains the decoded JSON or error information if the JSON source wasn't successfully parsed. You can check if the JSON source was successfully parsed with [code]if json_result.error == OK[/code].
</description>
<tutorials>
</tutorials>
<methods>
</methods>
<members>
<member name="error" type="int" setter="set_error" getter="get_error" enum="Error">
The error type if the JSON source was not successfully parsed. See the [enum Error] constants.
</member>
<member name="error_line" type="int" setter="set_error_line" getter="get_error_line" default="-1">
The line number where the error occurred if the JSON source was not successfully parsed.
</member>
<member name="error_string" type="String" setter="set_error_string" getter="get_error_string" default="&quot;&quot;">
The error message if the JSON source was not successfully parsed. See the [enum Error] constants.
</member>
<member name="result" type="Variant" setter="set_result" getter="get_result">
A [Variant] containing the parsed JSON. Use [method @GlobalScope.typeof] or the [code]is[/code] keyword to check if it is what you expect. For example, if the JSON source starts with curly braces ([code]{}[/code]), a [Dictionary] will be returned. If the JSON source starts with brackets ([code][][/code]), an [Array] will be returned.
[b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, parsing a JSON text will convert all numerical values to [float] types.
[b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, thus, you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements:
[codeblocks]
[gdscript]
var p = JSON.parse('["hello", "world", "!"]')
if typeof(p.result) == TYPE_ARRAY:
print(p.result[0]) # Prints "hello"
else:
push_error("Unexpected results.")
[/gdscript]
[csharp]
JSONParseResult p = JSON.Parse("[\"hello\"], \"world\", \"!\"]");
if (p.Result is Godot.Collections.Array)
{
GD.Print((p.Result as Godot.Collections.Array)[0]); // Prints "hello"
}
else
{
GD.PushError("Unexpected results.");
}
[/csharp]
[/codeblocks]
</member>
</members>
<constants>
</constants>
</class>

View file

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="JSONParser" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<methods>
<method name="decode_data">
<return type="int" enum="Error">
</return>
<argument index="0" name="data" type="Variant">
</argument>
<argument index="1" name="indent" type="String" default="&quot;&quot;">
</argument>
<argument index="2" name="sort_keys" type="bool" default="true">
</argument>
<description>
</description>
</method>
<method name="get_data" qualifiers="const">
<return type="Variant">
</return>
<description>
</description>
</method>
<method name="get_error_line" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
<method name="get_error_text" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
<method name="get_string" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
<method name="parse_string">
<return type="int" enum="Error">
</return>
<argument index="0" name="json_string" type="String">
</argument>
<description>
</description>
</method>
</methods>
<constants>
</constants>
</class>

View file

@ -161,21 +161,21 @@ String EditorFeatureProfile::get_feature_description(Feature p_feature) {
}
Error EditorFeatureProfile::save_to_file(const String &p_path) {
Dictionary json;
json["type"] = "feature_profile";
Dictionary data;
data["type"] = "feature_profile";
Array dis_classes;
for (Set<StringName>::Element *E = disabled_classes.front(); E; E = E->next()) {
dis_classes.push_back(String(E->get()));
}
dis_classes.sort();
json["disabled_classes"] = dis_classes;
data["disabled_classes"] = dis_classes;
Array dis_editors;
for (Set<StringName>::Element *E = disabled_editors.front(); E; E = E->next()) {
dis_editors.push_back(String(E->get()));
}
dis_editors.sort();
json["disabled_editors"] = dis_editors;
data["disabled_editors"] = dis_editors;
Array dis_props;
@ -185,7 +185,7 @@ Error EditorFeatureProfile::save_to_file(const String &p_path) {
}
}
json["disabled_properties"] = dis_props;
data["disabled_properties"] = dis_props;
Array dis_features;
for (int i = 0; i < FEATURE_MAX; i++) {
@ -194,12 +194,13 @@ Error EditorFeatureProfile::save_to_file(const String &p_path) {
}
}
json["disabled_features"] = dis_features;
data["disabled_features"] = dis_features;
FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
String text = JSON::print(json, "\t");
JSON json;
String text = json.stringify(data, "\t");
f->store_string(text);
f->close();
return OK;
@ -212,26 +213,24 @@ Error EditorFeatureProfile::load_from_file(const String &p_path) {
return err;
}
String err_str;
int err_line;
Variant v;
err = JSON::parse(text, v, err_str, err_line);
JSON json;
err = json.parse(text);
if (err != OK) {
ERR_PRINT("Error parsing '" + p_path + "' on line " + itos(err_line) + ": " + err_str);
ERR_PRINT("Error parsing '" + p_path + "' on line " + itos(json.get_error_line()) + ": " + json.get_error_message());
return ERR_PARSE_ERROR;
}
Dictionary json = v;
Dictionary data = json.get_data();
if (!json.has("type") || String(json["type"]) != "feature_profile") {
if (!data.has("type") || String(data["type"]) != "feature_profile") {
ERR_PRINT("Error parsing '" + p_path + "', it's not a feature profile.");
return ERR_PARSE_ERROR;
}
disabled_classes.clear();
if (json.has("disabled_classes")) {
Array disabled_classes_arr = json["disabled_classes"];
if (data.has("disabled_classes")) {
Array disabled_classes_arr = data["disabled_classes"];
for (int i = 0; i < disabled_classes_arr.size(); i++) {
disabled_classes.insert(disabled_classes_arr[i]);
}
@ -239,8 +238,8 @@ Error EditorFeatureProfile::load_from_file(const String &p_path) {
disabled_editors.clear();
if (json.has("disabled_editors")) {
Array disabled_editors_arr = json["disabled_editors"];
if (data.has("disabled_editors")) {
Array disabled_editors_arr = data["disabled_editors"];
for (int i = 0; i < disabled_editors_arr.size(); i++) {
disabled_editors.insert(disabled_editors_arr[i]);
}
@ -248,16 +247,16 @@ Error EditorFeatureProfile::load_from_file(const String &p_path) {
disabled_properties.clear();
if (json.has("disabled_properties")) {
Array disabled_properties_arr = json["disabled_properties"];
if (data.has("disabled_properties")) {
Array disabled_properties_arr = data["disabled_properties"];
for (int i = 0; i < disabled_properties_arr.size(); i++) {
String s = disabled_properties_arr[i];
set_disable_class_property(s.get_slice(":", 0), s.get_slice(":", 1), true);
}
}
if (json.has("disabled_features")) {
Array disabled_features_arr = json["disabled_features"];
if (data.has("disabled_features")) {
Array disabled_features_arr = data["disabled_features"];
for (int i = 0; i < FEATURE_MAX; i++) {
bool found = false;
String f = feature_identifiers[i];

View file

@ -242,10 +242,8 @@ void ExportTemplateManager::_refresh_mirrors_completed(int p_status, int p_code,
response_json.parse_utf8((const char *)r, p_data.size());
}
Variant response;
String errs;
int errline;
Error err = JSON::parse(response_json, response, errs, errline);
JSON json;
Error err = json.parse(response_json);
if (err != OK) {
EditorNode::get_singleton()->show_warning(TTR("Error parsing JSON with the list of mirrors. Please report this issue!"));
is_refreshing_mirrors = false;
@ -260,7 +258,7 @@ void ExportTemplateManager::_refresh_mirrors_completed(int p_status, int p_code,
mirrors_available = false;
Dictionary data = response;
Dictionary data = json.get_data();
if (data.has("mirrors")) {
Array mirrors = data["mirrors"];

View file

@ -1098,11 +1098,9 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
Dictionary d;
{
Variant js;
String errs;
int errl;
JSON::parse(str, js, errs, errl);
d = js;
JSON json;
json.parse(str);
d = json.get_data();
}
RequestType requested = requesting;

View file

@ -34,8 +34,7 @@
#ifdef TOOLS_ENABLED
#include "core/io/file_access.h"
#include "core/io/json.h"
#include "core/string/ustring.h"
#include "core/string/print_string.h"
#include "core/templates/local_vector.h"
#include "core/templates/map.h"

View file

@ -32,7 +32,6 @@
#include "../gdscript.h"
#include "../gdscript_analyzer.h"
#include "core/io/json.h"
#include "gdscript_language_protocol.h"
#include "gdscript_workspace.h"
@ -183,7 +182,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.detail += ": " + m.get_datatype().to_string();
}
if (m.variable->initializer != nullptr && m.variable->initializer->is_constant) {
symbol.detail += " = " + JSON::print(m.variable->initializer->reduced_value);
symbol.detail += " = " + m.variable->initializer->reduced_value.to_json_string();
}
symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.variable->start_line));
@ -224,10 +223,10 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
}
}
} else {
value_text = JSON::print(default_value);
value_text = default_value.to_json_string();
}
} else {
value_text = JSON::print(default_value);
value_text = default_value.to_json_string();
}
if (!value_text.is_empty()) {
symbol.detail += " = " + value_text;
@ -353,8 +352,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
parameters += ": " + parameter->get_datatype().to_string();
}
if (parameter->default_value != nullptr) {
String value = JSON::print(parameter->default_value->reduced_value);
parameters += " = " + value;
parameters += " = " + parameter->default_value->reduced_value.to_json_string();
}
}
r_symbol.detail += parameters + ")";

View file

@ -31,7 +31,6 @@
#include "gdscript_language_protocol.h"
#include "core/config/project_settings.h"
#include "core/io/json.h"
#include "editor/doc_tools.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
@ -194,7 +193,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
vformat("GDScriptLanguageProtocol: Can't initialize invalid peer '%d'.", latest_client_id));
Ref<LSPeer> peer = clients.get(latest_client_id);
if (peer != nullptr) {
String msg = JSON::print(request);
String msg = Variant(request).to_json_string();
msg = format_output(msg);
(*peer)->res_queue.push_back(msg.utf8());
}
@ -280,7 +279,7 @@ void GDScriptLanguageProtocol::notify_client(const String &p_method, const Varia
ERR_FAIL_COND(peer == nullptr);
Dictionary message = make_notification(p_method, p_params);
String msg = JSON::print(message);
String msg = Variant(message).to_json_string();
msg = format_output(msg);
peer->res_queue.push_back(msg.utf8());
}

View file

@ -30,7 +30,6 @@
#include "core/crypto/crypto_core.h"
#include "core/io/file_access.h"
#include "core/io/json.h"
#include "core/math/disjoint_set.h"
#include "core/math/math_defs.h"
#include "core/os/os.h"

View file

@ -32,7 +32,6 @@
#define EDITOR_SCENE_IMPORTER_GLTF_H
#include "core/config/project_settings.h"
#include "core/io/json.h"
#include "core/object/object.h"
#include "core/templates/vector.h"
#include "editor/import/resource_importer_scene.h"

View file

@ -238,15 +238,13 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
String text;
text.parse_utf8((const char *)array.ptr(), array.size());
String err_txt;
int err_line;
Variant v;
err = JSON::parse(text, v, err_txt, err_line);
JSON json;
err = json.parse(text);
if (err != OK) {
_err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT);
_err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), ERR_HANDLER_SCRIPT);
return err;
}
state->json = v;
state->json = json.get_data();
return OK;
}
@ -299,16 +297,14 @@ Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) {
String text;
text.parse_utf8((const char *)json_data.ptr(), json_data.size());
String err_txt;
int err_line;
Variant v;
err = JSON::parse(text, v, err_txt, err_line);
JSON json;
err = json.parse(text);
if (err != OK) {
_err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT);
_err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), ERR_HANDLER_SCRIPT);
return err;
}
state->json = v;
state->json = json.get_data();
//data?
@ -6584,7 +6580,7 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err);
ERR_FAIL_COND_V(!f, FAILED);
String json = JSON::print(state->json);
String json = Variant(state->json).to_json_string();
const uint32_t magic = 0x46546C67; // GLTF
const int32_t header_size = 12;
@ -6625,7 +6621,7 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
ERR_FAIL_COND_V(!f, FAILED);
f->create(FileAccess::ACCESS_RESOURCES);
String json = JSON::print(state->json);
String json = Variant(state->json).to_json_string();
f->store_string(json);
f->close();
}

View file

@ -29,6 +29,7 @@
/*************************************************************************/
#include "jsonrpc.h"
#include "core/io/json.h"
JSONRPC::JSONRPC() {
@ -156,19 +157,17 @@ String JSONRPC::process_string(const String &p_input) {
}
Variant ret;
Variant input;
String err_message;
int err_line;
if (OK != JSON::parse(p_input, input, err_message, err_line)) {
ret = make_response_error(JSONRPC::PARSE_ERROR, "Parse error");
JSON json;
if (json.parse(p_input) == OK) {
ret = process_action(json.get_data(), true);
} else {
ret = process_action(input, true);
ret = make_response_error(JSONRPC::PARSE_ERROR, "Parse error");
}
if (ret.get_type() == Variant::NIL) {
return "";
}
return JSON::print(ret);
return ret.to_json_string();
}
void JSONRPC::set_scope(const String &p_scope, Object *p_obj) {

View file

@ -240,7 +240,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
FileAccessRef f = FileAccess::open(p_output_file, FileAccess::WRITE);
ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_output_file + "'.");
f->store_string(JSON::print(classes_dict, /*indent: */ "\t"));
JSON json;
f->store_string(json.stringify(classes_dict, "\t"));
f->close();
print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file));

View file

@ -38,7 +38,6 @@
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
#include "core/io/file_access.h"
#include "core/io/json.h"
#include "core/os/mutex.h"
#include "core/os/os.h"
#include "core/os/thread.h"

View file

@ -29,7 +29,6 @@
/*************************************************************************/
#include "core/io/image_loader.h"
#include "core/io/json.h"
#include "core/io/stream_peer_ssl.h"
#include "core/io/tcp_server.h"
#include "core/io/zip_io.h"
@ -465,7 +464,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
}
// Replaces HTML string
const String str_config = JSON::print(config);
const String str_config = Variant(config).to_json_string();
const String custom_head_include = p_preset->get("html/head_include");
Map<String, String> replaces;
replaces["$GODOT_URL"] = p_name + ".js";
@ -518,7 +517,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
replaces["@GODOT_NAME@"] = name;
replaces["@GODOT_OFFLINE_PAGE@"] = name + ".offline.html";
Array files;
replaces["@GODOT_OPT_CACHE@"] = JSON::print(files);
replaces["@GODOT_OPT_CACHE@"] = Variant(files).to_json_string();
files.push_back(name + ".html");
files.push_back(name + ".js");
files.push_back(name + ".wasm");
@ -537,7 +536,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
files.push_back(p_shared_objects[i].path.get_file());
}
}
replaces["@GODOT_CACHE@"] = JSON::print(files);
replaces["@GODOT_CACHE@"] = Variant(files).to_json_string();
const String sw_path = dir.plus_file(name + ".service.worker.js");
Vector<uint8_t> sw;
@ -605,7 +604,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
}
manifest["icons"] = icons_arr;
CharString cs = JSON::print(manifest).utf8();
CharString cs = Variant(manifest).to_json_string().utf8();
err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.plus_file(name + ".manifest.json"));
if (err != OK) {
return err;

View file

@ -45,75 +45,65 @@ TEST_CASE("[JSON] Parsing single data types") {
// Parsing a single data type as JSON is valid per the JSON specification.
JSON json;
Variant result;
String err_str;
int err_line;
json.parse("null", result, err_str, err_line);
json.parse("null");
CHECK_MESSAGE(
err_line == 0,
json.get_error_line() == 0,
"Parsing `null` as JSON should parse successfully.");
CHECK_MESSAGE(
result == Variant(),
json.get_data() == Variant(),
"Parsing a double quoted string as JSON should return the expected value.");
json.parse("true", result, err_str, err_line);
json.parse("true");
CHECK_MESSAGE(
err_line == 0,
json.get_error_line() == 0,
"Parsing boolean `true` as JSON should parse successfully.");
CHECK_MESSAGE(
result,
json.get_data(),
"Parsing boolean `true` as JSON should return the expected value.");
json.parse("false", result, err_str, err_line);
json.parse("false");
CHECK_MESSAGE(
err_line == 0,
json.get_error_line() == 0,
"Parsing boolean `false` as JSON should parse successfully.");
CHECK_MESSAGE(
!result,
!json.get_data(),
"Parsing boolean `false` as JSON should return the expected value.");
// JSON only has a floating-point number type, no integer type.
// This is why we use `is_equal_approx()` for the comparison.
json.parse("123456", result, err_str, err_line);
json.parse("123456");
CHECK_MESSAGE(
err_line == 0,
json.get_error_line() == 0,
"Parsing an integer number as JSON should parse successfully.");
CHECK_MESSAGE(
(int)result == 123'456,
(int)(json.get_data()) == 123456,
"Parsing an integer number as JSON should return the expected value.");
json.parse("0.123456", result, err_str, err_line);
json.parse("0.123456");
CHECK_MESSAGE(
err_line == 0,
json.get_error_line() == 0,
"Parsing a floating-point number as JSON should parse successfully.");
CHECK_MESSAGE(
Math::is_equal_approx(result, 0.123456),
Math::is_equal_approx(json.get_data(), 0.123456),
"Parsing a floating-point number as JSON should return the expected value.");
json.parse("\"hello\"", result, err_str, err_line);
json.parse("\"hello\"");
CHECK_MESSAGE(
err_line == 0,
json.get_error_line() == 0,
"Parsing a double quoted string as JSON should parse successfully.");
CHECK_MESSAGE(
result == "hello",
json.get_data() == "hello",
"Parsing a double quoted string as JSON should return the expected value.");
}
TEST_CASE("[JSON] Parsing arrays") {
JSON json;
Variant result;
String err_str;
int err_line;
// JSON parsing fails if it's split over several lines (even if leading indentation is removed).
json.parse(
R"(["Hello", "world.", "This is",["a","json","array.",[]], "Empty arrays ahoy:", [[["Gotcha!"]]]])",
result, err_str, err_line);
json.parse(R"(["Hello", "world.", "This is",["a","json","array.",[]], "Empty arrays ahoy:", [[["Gotcha!"]]]])");
const Array array = result;
const Array array = json.get_data();
CHECK_MESSAGE(
err_line == 0,
json.get_error_line() == 0,
"Parsing a JSON array should parse successfully.");
CHECK_MESSAGE(
array[0] == "Hello",
@ -136,15 +126,10 @@ TEST_CASE("[JSON] Parsing arrays") {
TEST_CASE("[JSON] Parsing objects (dictionaries)") {
JSON json;
Variant result;
String err_str;
int err_line;
json.parse(
R"({"name": "Godot Engine", "is_free": true, "bugs": null, "apples": {"red": 500, "green": 0, "blue": -20}, "empty_object": {}})",
result, err_str, err_line);
json.parse(R"({"name": "Godot Engine", "is_free": true, "bugs": null, "apples": {"red": 500, "green": 0, "blue": -20}, "empty_object": {}})");
const Dictionary dictionary = result;
const Dictionary dictionary = json.get_data();
CHECK_MESSAGE(
dictionary["name"] == "Godot Engine",
"The parsed JSON should contain the expected values.");