diff options
Diffstat (limited to 'modules/gdscript/gdscript_parser.cpp')
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 120 |
1 files changed, 66 insertions, 54 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 01a672c330..bdf6fb35b6 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -35,6 +35,7 @@ #include "core/io/resource_loader.h" #include "core/math/math_defs.h" #include "gdscript.h" +#include "scene/main/multiplayer_api.h" #ifdef DEBUG_ENABLED #include "core/os/os.h" @@ -60,11 +61,14 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) { builtin_types["Transform2D"] = Variant::TRANSFORM2D; builtin_types["Vector3"] = Variant::VECTOR3; builtin_types["Vector3i"] = Variant::VECTOR3I; + builtin_types["Vector4"] = Variant::VECTOR4; + builtin_types["Vector4i"] = Variant::VECTOR4I; builtin_types["AABB"] = Variant::AABB; builtin_types["Plane"] = Variant::PLANE; builtin_types["Quaternion"] = Variant::QUATERNION; builtin_types["Basis"] = Variant::BASIS; builtin_types["Transform3D"] = Variant::TRANSFORM3D; + builtin_types["Projection"] = Variant::PROJECTION; builtin_types["Color"] = Variant::COLOR; builtin_types["RID"] = Variant::RID; builtin_types["Object"] = Variant::OBJECT; @@ -123,7 +127,7 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, varray(""), true); register_annotation(MethodInfo("@export_global_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_DIR, Variant::STRING>); register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>); - register_annotation(MethodInfo("@export_placeholder"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); + register_annotation(MethodInfo("@export_placeholder", PropertyInfo(Variant::STRING, "placeholder")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); register_annotation(MethodInfo("@export_range", PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"), PropertyInfo(Variant::FLOAT, "step"), PropertyInfo(Variant::STRING, "extra_hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, varray(1.0, ""), true); register_annotation(MethodInfo("@export_exp_easing", PropertyInfo(Variant::STRING, "hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, varray(""), true); register_annotation(MethodInfo("@export_color_no_alpha"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_COLOR_NO_ALPHA, Variant::COLOR>); @@ -142,7 +146,7 @@ GDScriptParser::GDScriptParser() { // Warning annotations. register_annotation(MethodInfo("@warning_ignore", PropertyInfo(Variant::STRING, "warning")), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, varray(), true); // Networking. - register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, varray("", "", "", 0), true); + register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::rpc_annotation, varray("", "", "", 0), true); } GDScriptParser::~GDScriptParser() { @@ -682,17 +686,6 @@ void GDScriptParser::parse_class_name() { current_class->identifier = parse_identifier(); } - // TODO: Move this to annotation - if (match(GDScriptTokenizer::Token::COMMA)) { - // Icon path. - if (consume(GDScriptTokenizer::Token::LITERAL, R"(Expected class icon path string after ",".)")) { - if (previous.literal.get_type() != Variant::STRING) { - push_error(vformat(R"(Only strings can be used for the class icon path, found "%s" instead.)", Variant::get_type_name(previous.literal.get_type()))); - } - current_class->icon_path = previous.literal; - } - } - if (match(GDScriptTokenizer::Token::EXTENDS)) { // Allow extends on the same line. parse_extends(); @@ -2939,11 +2932,16 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre // Allow for trailing comma. break; } + bool use_identifier_completion = current.cursor_place == GDScriptTokenizer::CURSOR_END || current.cursor_place == GDScriptTokenizer::CURSOR_MIDDLE; ExpressionNode *argument = parse_expression(false); if (argument == nullptr) { push_error(R"(Expected expression as the function argument.)"); } else { call->arguments.push_back(argument); + + if (argument->type == Node::IDENTIFIER && use_identifier_completion) { + completion_context.type = COMPLETION_IDENTIFIER; + } } ct = COMPLETION_CALL_ARGUMENTS; } while (match(GDScriptTokenizer::Token::COMMA)); @@ -3765,6 +3763,33 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node return false; } break; + case GDScriptParser::DataType::CLASS: + // Can assume type is a global GDScript class. + if (!ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) { + push_error(R"(Exported script type must extend Resource.)"); + return false; + } + variable->export_info.type = Variant::OBJECT; + variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; + variable->export_info.hint_string = export_type.class_type->identifier->name; + break; + case GDScriptParser::DataType::SCRIPT: { + StringName class_name; + if (export_type.script_type != nullptr && export_type.script_type.is_valid()) { + class_name = export_type.script_type->get_language()->get_global_class_name(export_type.script_type->get_path()); + } + if (class_name == StringName()) { + Ref<Script> script = ResourceLoader::load(export_type.script_path, SNAME("Script")); + if (script.is_valid()) { + class_name = script->get_language()->get_global_class_name(export_type.script_path); + } + } + if (class_name != StringName() && ClassDB::is_parent_class(ScriptServer::get_global_class_native_base(class_name), SNAME("Resource"))) { + variable->export_info.type = Variant::OBJECT; + variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; + variable->export_info.hint_string = class_name; + } + } break; case GDScriptParser::DataType::ENUM: { variable->export_info.type = Variant::INT; variable->export_info.hint = PROPERTY_HINT_ENUM; @@ -3864,16 +3889,21 @@ bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Nod #endif // DEBUG_ENABLED } -template <Multiplayer::RPCMode t_mode> -bool GDScriptParser::network_annotations(const AnnotationNode *p_annotation, Node *p_node) { - ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE && p_node->type != Node::FUNCTION, false, vformat(R"("%s" annotation can only be applied to variables and functions.)", p_annotation->name)); +bool GDScriptParser::rpc_annotation(const AnnotationNode *p_annotation, Node *p_node) { + ERR_FAIL_COND_V_MSG(p_node->type != Node::FUNCTION, false, vformat(R"("%s" annotation can only be applied to functions.)", p_annotation->name)); - Multiplayer::RPCConfig rpc_config; - rpc_config.rpc_mode = t_mode; + FunctionNode *function = static_cast<FunctionNode *>(p_node); + if (function->rpc_config.get_type() != Variant::NIL) { + push_error(R"(RPC annotations can only be used once per function.)", p_annotation); + return false; + } + + Dictionary rpc_config; + rpc_config["rpc_mode"] = MultiplayerAPI::RPC_MODE_AUTHORITY; if (p_annotation->resolved_arguments.size()) { int last = p_annotation->resolved_arguments.size() - 1; if (p_annotation->resolved_arguments[last].get_type() == Variant::INT) { - rpc_config.channel = p_annotation->resolved_arguments[last].operator int(); + rpc_config["channel"] = p_annotation->resolved_arguments[last].operator int(); last -= 1; } if (last > 3) { @@ -3883,37 +3913,25 @@ bool GDScriptParser::network_annotations(const AnnotationNode *p_annotation, Nod for (int i = last; i >= 0; i--) { String mode = p_annotation->resolved_arguments[i].operator String(); if (mode == "any_peer") { - rpc_config.rpc_mode = Multiplayer::RPC_MODE_ANY_PEER; + rpc_config["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER; } else if (mode == "authority") { - rpc_config.rpc_mode = Multiplayer::RPC_MODE_AUTHORITY; + rpc_config["rpc_mode"] = MultiplayerAPI::RPC_MODE_AUTHORITY; } else if (mode == "call_local") { - rpc_config.call_local = true; + rpc_config["call_local"] = true; } else if (mode == "call_remote") { - rpc_config.call_local = false; + rpc_config["call_local"] = false; } else if (mode == "reliable") { - rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; + rpc_config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_RELIABLE; } else if (mode == "unreliable") { - rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_UNRELIABLE; + rpc_config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE; } else if (mode == "unreliable_ordered") { - rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED; + rpc_config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE_ORDERED; } else { push_error(R"(Invalid RPC argument. Must be one of: 'call_local'/'call_remote' (local calls), 'any_peer'/'authority' (permission), 'reliable'/'unreliable'/'unreliable_ordered' (transfer mode).)", p_annotation); } } } - switch (p_node->type) { - case Node::FUNCTION: { - FunctionNode *function = static_cast<FunctionNode *>(p_node); - if (function->rpc_config.rpc_mode != Multiplayer::RPC_MODE_DISABLED) { - push_error(R"(RPC annotations can only be used once per function.)", p_annotation); - return false; - } - function->rpc_config = rpc_config; - break; - } - default: - return false; // Unreachable. - } + function->rpc_config = rpc_config; return true; } @@ -3935,28 +3953,22 @@ GDScriptParser::DataType GDScriptParser::SuiteNode::Local::get_datatype() const } String GDScriptParser::SuiteNode::Local::get_name() const { - String name; switch (type) { case SuiteNode::Local::PARAMETER: - name = "parameter"; - break; + return "parameter"; case SuiteNode::Local::CONSTANT: - name = "constant"; - break; + return "constant"; case SuiteNode::Local::VARIABLE: - name = "variable"; - break; + return "variable"; case SuiteNode::Local::FOR_VARIABLE: - name = "for loop iterator"; - break; + return "for loop iterator"; case SuiteNode::Local::PATTERN_BIND: - name = "pattern_bind"; - break; + return "pattern_bind"; case SuiteNode::Local::UNDEFINED: - name = "<undefined>"; - break; + return "<undefined>"; + default: + return String(); } - return name; } String GDScriptParser::DataType::to_string() const { @@ -3988,7 +4000,7 @@ String GDScriptParser::DataType::to_string() const { if (is_meta_type) { return script_type->get_class_name().operator String(); } - String name = script_type->get_name(); + String name = script_type != nullptr ? script_type->get_name() : ""; if (!name.is_empty()) { return name; } |