diff options
Diffstat (limited to 'core/variant/variant_parser.cpp')
-rw-r--r-- | core/variant/variant_parser.cpp | 244 |
1 files changed, 227 insertions, 17 deletions
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index 9a0dd712ed..f5f96456d3 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -1140,6 +1140,146 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return ERR_PARSE_ERROR; } } + } else if (id == "Dictionary") { + Error err = OK; + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_BRACKET_OPEN) { + r_err_str = "Expected '['"; + return ERR_PARSE_ERROR; + } + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_IDENTIFIER) { + r_err_str = "Expected type identifier for key"; + return ERR_PARSE_ERROR; + } + + static HashMap<StringName, Variant::Type> builtin_types; + if (builtin_types.is_empty()) { + for (int i = 1; i < Variant::VARIANT_MAX; i++) { + builtin_types[Variant::get_type_name((Variant::Type)i)] = (Variant::Type)i; + } + } + + Dictionary dict; + Variant::Type key_type = Variant::NIL; + StringName key_class_name; + Variant key_script; + bool got_comma_token = false; + if (builtin_types.has(token.value)) { + key_type = builtin_types.get(token.value); + } else if (token.value == "Resource" || token.value == "SubResource" || token.value == "ExtResource") { + Variant resource; + err = parse_value(token, resource, p_stream, line, r_err_str, p_res_parser); + if (err) { + if (token.value == "Resource" && err == ERR_PARSE_ERROR && r_err_str == "Expected '('" && token.type == TK_COMMA) { + err = OK; + r_err_str = String(); + key_type = Variant::OBJECT; + key_class_name = token.value; + got_comma_token = true; + } else { + return err; + } + } else { + Ref<Script> script = resource; + if (script.is_valid() && script->is_valid()) { + key_type = Variant::OBJECT; + key_class_name = script->get_instance_base_type(); + key_script = script; + } + } + } else if (ClassDB::class_exists(token.value)) { + key_type = Variant::OBJECT; + key_class_name = token.value; + } + + if (!got_comma_token) { + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_COMMA) { + r_err_str = "Expected ',' after key type"; + return ERR_PARSE_ERROR; + } + } + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_IDENTIFIER) { + r_err_str = "Expected type identifier for value"; + return ERR_PARSE_ERROR; + } + + Variant::Type value_type = Variant::NIL; + StringName value_class_name; + Variant value_script; + bool got_bracket_token = false; + if (builtin_types.has(token.value)) { + value_type = builtin_types.get(token.value); + } else if (token.value == "Resource" || token.value == "SubResource" || token.value == "ExtResource") { + Variant resource; + err = parse_value(token, resource, p_stream, line, r_err_str, p_res_parser); + if (err) { + if (token.value == "Resource" && err == ERR_PARSE_ERROR && r_err_str == "Expected '('" && token.type == TK_BRACKET_CLOSE) { + err = OK; + r_err_str = String(); + value_type = Variant::OBJECT; + value_class_name = token.value; + got_comma_token = true; + } else { + return err; + } + } else { + Ref<Script> script = resource; + if (script.is_valid() && script->is_valid()) { + value_type = Variant::OBJECT; + value_class_name = script->get_instance_base_type(); + value_script = script; + } + } + } else if (ClassDB::class_exists(token.value)) { + value_type = Variant::OBJECT; + value_class_name = token.value; + } + + if (key_type != Variant::NIL || value_type != Variant::NIL) { + dict.set_typed(key_type, key_class_name, key_script, value_type, value_class_name, value_script); + } + + if (!got_bracket_token) { + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_BRACKET_CLOSE) { + r_err_str = "Expected ']'"; + return ERR_PARSE_ERROR; + } + } + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_PARENTHESIS_OPEN) { + r_err_str = "Expected '('"; + return ERR_PARSE_ERROR; + } + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_CURLY_BRACKET_OPEN) { + r_err_str = "Expected '{'"; + return ERR_PARSE_ERROR; + } + + Dictionary values; + err = _parse_dictionary(values, p_stream, line, r_err_str, p_res_parser); + if (err) { + return err; + } + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_PARENTHESIS_CLOSE) { + r_err_str = "Expected ')'"; + return ERR_PARSE_ERROR; + } + + dict.assign(values); + + value = dict; } else if (id == "Array") { Error err = OK; @@ -2036,40 +2176,109 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str case Variant::DICTIONARY: { Dictionary dict = p_variant; + + if (dict.is_typed()) { + p_store_string_func(p_store_string_ud, "Dictionary["); + + Variant::Type key_builtin_type = (Variant::Type)dict.get_typed_key_builtin(); + StringName key_class_name = dict.get_typed_key_class_name(); + Ref<Script> key_script = dict.get_typed_key_script(); + + if (key_script.is_valid()) { + String resource_text; + if (p_encode_res_func) { + resource_text = p_encode_res_func(p_encode_res_ud, key_script); + } + if (resource_text.is_empty() && key_script->get_path().is_resource_file()) { + resource_text = "Resource(\"" + key_script->get_path() + "\")"; + } + + if (!resource_text.is_empty()) { + p_store_string_func(p_store_string_ud, resource_text); + } else { + ERR_PRINT("Failed to encode a path to a custom script for a dictionary key type."); + p_store_string_func(p_store_string_ud, key_class_name); + } + } else if (key_class_name != StringName()) { + p_store_string_func(p_store_string_ud, key_class_name); + } else if (key_builtin_type == Variant::NIL) { + p_store_string_func(p_store_string_ud, "Variant"); + } else { + p_store_string_func(p_store_string_ud, Variant::get_type_name(key_builtin_type)); + } + + p_store_string_func(p_store_string_ud, ", "); + + Variant::Type value_builtin_type = (Variant::Type)dict.get_typed_value_builtin(); + StringName value_class_name = dict.get_typed_value_class_name(); + Ref<Script> value_script = dict.get_typed_value_script(); + + if (value_script.is_valid()) { + String resource_text; + if (p_encode_res_func) { + resource_text = p_encode_res_func(p_encode_res_ud, value_script); + } + if (resource_text.is_empty() && value_script->get_path().is_resource_file()) { + resource_text = "Resource(\"" + value_script->get_path() + "\")"; + } + + if (!resource_text.is_empty()) { + p_store_string_func(p_store_string_ud, resource_text); + } else { + ERR_PRINT("Failed to encode a path to a custom script for a dictionary value type."); + p_store_string_func(p_store_string_ud, value_class_name); + } + } else if (value_class_name != StringName()) { + p_store_string_func(p_store_string_ud, value_class_name); + } else if (value_builtin_type == Variant::NIL) { + p_store_string_func(p_store_string_ud, "Variant"); + } else { + p_store_string_func(p_store_string_ud, Variant::get_type_name(value_builtin_type)); + } + + p_store_string_func(p_store_string_ud, "]("); + } + if (unlikely(p_recursion_count > MAX_RECURSION)) { ERR_PRINT("Max recursion reached"); p_store_string_func(p_store_string_ud, "{}"); } else { - p_recursion_count++; - List<Variant> keys; dict.get_key_list(&keys); keys.sort(); - if (keys.is_empty()) { // Avoid unnecessary line break. + if (keys.is_empty()) { + // Avoid unnecessary line break. p_store_string_func(p_store_string_ud, "{}"); - break; - } + } else { + p_recursion_count++; - p_store_string_func(p_store_string_ud, "{\n"); - for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { - write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat); - p_store_string_func(p_store_string_ud, ": "); - write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat); - if (E->next()) { - p_store_string_func(p_store_string_ud, ",\n"); - } else { - p_store_string_func(p_store_string_ud, "\n"); + p_store_string_func(p_store_string_ud, "{\n"); + + for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { + write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat); + p_store_string_func(p_store_string_ud, ": "); + write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat); + if (E->next()) { + p_store_string_func(p_store_string_ud, ",\n"); + } else { + p_store_string_func(p_store_string_ud, "\n"); + } } + + p_store_string_func(p_store_string_ud, "}"); } + } - p_store_string_func(p_store_string_ud, "}"); + if (dict.is_typed()) { + p_store_string_func(p_store_string_ud, ")"); } } break; case Variant::ARRAY: { Array array = p_variant; - if (array.get_typed_builtin() != Variant::NIL) { + + if (array.is_typed()) { p_store_string_func(p_store_string_ud, "Array["); Variant::Type builtin_type = (Variant::Type)array.get_typed_builtin(); @@ -2107,6 +2316,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_recursion_count++; p_store_string_func(p_store_string_ud, "["); + bool first = true; for (const Variant &var : array) { if (first) { @@ -2120,7 +2330,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, "]"); } - if (array.get_typed_builtin() != Variant::NIL) { + if (array.is_typed()) { p_store_string_func(p_store_string_ud, ")"); } } break; |