summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gdscript_parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript_parser.cpp')
-rw-r--r--modules/gdscript/gdscript_parser.cpp168
1 files changed, 130 insertions, 38 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 025accf4ba..48f58e51fe 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -582,9 +582,9 @@ void GDScriptParser::parse_program() {
parse_class_body(true);
#ifdef TOOLS_ENABLED
- for (Map<int, GDScriptTokenizer::CommentData>::Element *E = tokenizer.get_comments().front(); E; E = E->next()) {
- if (E->get().new_line && E->get().comment.begins_with("##")) {
- class_doc_line = MIN(class_doc_line, E->key());
+ for (const KeyValue<int, GDScriptTokenizer::CommentData> &E : tokenizer.get_comments()) {
+ if (E.value.new_line && E.value.comment.begins_with("##")) {
+ class_doc_line = MIN(class_doc_line, E.key);
}
}
if (has_comment(class_doc_line)) {
@@ -740,10 +740,26 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
#endif // TOOLS_ENABLED
if (member->identifier != nullptr) {
- // Enums may be unnamed.
- // TODO: Consider names in outer scope too, for constants and classes (and static functions?)
- if (current_class->members_indices.has(member->identifier->name)) {
- push_error(vformat(R"(%s "%s" has the same name as a previously declared %s.)", p_member_kind.capitalize(), member->identifier->name, current_class->get_member(member->identifier->name).get_type_name()), member->identifier);
+ if (!((String)member->identifier->name).is_empty()) { // Enums may be unnamed.
+
+#ifdef DEBUG_ENABLED
+ List<MethodInfo> gdscript_funcs;
+ GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
+ for (MethodInfo &info : gdscript_funcs) {
+ if (info.name == member->identifier->name) {
+ push_warning(member->identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_member_kind, member->identifier->name, "built-in function");
+ }
+ }
+ if (Variant::has_utility_function(member->identifier->name)) {
+ push_warning(member->identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_member_kind, member->identifier->name, "built-in function");
+ }
+#endif
+
+ if (current_class->members_indices.has(member->identifier->name)) {
+ push_error(vformat(R"(%s "%s" has the same name as a previously declared %s.)", p_member_kind.capitalize(), member->identifier->name, current_class->get_member(member->identifier->name).get_type_name()), member->identifier);
+ } else {
+ current_class->add_member(member);
+ }
} else {
current_class->add_member(member);
}
@@ -947,7 +963,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_property(VariableNode *p_var
void GDScriptParser::parse_property_setter(VariableNode *p_variable) {
switch (p_variable->property) {
- case VariableNode::PROP_INLINE:
+ case VariableNode::PROP_INLINE: {
consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected "(" after "set".)");
if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected parameter name after "(".)")) {
p_variable->setter_parameter = parse_identifier();
@@ -955,9 +971,32 @@ void GDScriptParser::parse_property_setter(VariableNode *p_variable) {
consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after parameter name.)*");
consume(GDScriptTokenizer::Token::COLON, R"*(Expected ":" after ")".)*");
- p_variable->setter = parse_suite("setter definition");
- break;
+ IdentifierNode *identifier = alloc_node<IdentifierNode>();
+ identifier->name = "@" + p_variable->identifier->name + "_setter";
+
+ FunctionNode *function = alloc_node<FunctionNode>();
+ function->identifier = identifier;
+
+ FunctionNode *previous_function = current_function;
+ current_function = function;
+ ParameterNode *parameter = alloc_node<ParameterNode>();
+ parameter->identifier = p_variable->setter_parameter;
+
+ if (parameter->identifier != nullptr) {
+ function->parameters_indices[parameter->identifier->name] = 0;
+ function->parameters.push_back(parameter);
+
+ SuiteNode *body = alloc_node<SuiteNode>();
+ body->add_local(parameter, function);
+
+ function->body = parse_suite("setter declaration", body);
+ p_variable->setter = function;
+ }
+
+ current_function = previous_function;
+ break;
+ }
case VariableNode::PROP_SETGET:
consume(GDScriptTokenizer::Token::EQUAL, R"(Expected "=" after "set")");
make_completion_context(COMPLETION_PROPERTY_METHOD, p_variable);
@@ -972,11 +1011,25 @@ void GDScriptParser::parse_property_setter(VariableNode *p_variable) {
void GDScriptParser::parse_property_getter(VariableNode *p_variable) {
switch (p_variable->property) {
- case VariableNode::PROP_INLINE:
+ case VariableNode::PROP_INLINE: {
consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "get".)");
- p_variable->getter = parse_suite("getter definition");
+ IdentifierNode *identifier = alloc_node<IdentifierNode>();
+ identifier->name = "@" + p_variable->identifier->name + "_getter";
+
+ FunctionNode *function = alloc_node<FunctionNode>();
+ function->identifier = identifier;
+
+ FunctionNode *previous_function = current_function;
+ current_function = function;
+
+ SuiteNode *body = alloc_node<SuiteNode>();
+ function->body = parse_suite("getter declaration", body);
+
+ p_variable->getter = function;
+ current_function = previous_function;
break;
+ }
case VariableNode::PROP_SETGET:
consume(GDScriptTokenizer::Token::EQUAL, R"(Expected "=" after "get")");
make_completion_context(COMPLETION_PROPERTY_METHOD, p_variable);
@@ -1108,13 +1161,31 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
HashMap<StringName, int> elements;
+#ifdef DEBUG_ENABLED
+ List<MethodInfo> gdscript_funcs;
+ GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
+#endif
+
do {
if (check(GDScriptTokenizer::Token::BRACE_CLOSE)) {
break; // Allow trailing comma.
}
if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier for enum key.)")) {
EnumNode::Value item;
- item.identifier = parse_identifier();
+ GDScriptParser::IdentifierNode *identifier = parse_identifier();
+#ifdef DEBUG_ENABLED
+ for (MethodInfo &info : gdscript_funcs) {
+ if (info.name == identifier->name) {
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "built-in function");
+ }
+ }
+ if (Variant::has_utility_function(identifier->name)) {
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "built-in function");
+ } else if (ClassDB::class_exists(identifier->name)) {
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "global class");
+ }
+#endif
+ item.identifier = identifier;
item.parent_enum = enum_node;
item.line = previous.start_line;
item.leftmost_column = previous.leftmost_column;
@@ -1620,6 +1691,10 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() {
n_for->list = parse_expression(false);
+ if (!n_for->list) {
+ push_error(R"(Expected a list or range after "in".)");
+ }
+
consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "for" condition.)");
// Save break/continue state.
@@ -2733,6 +2808,23 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p
get_node->chain.push_back(identifier);
} while (match(GDScriptTokenizer::Token::SLASH));
return get_node;
+ } else if (match(GDScriptTokenizer::Token::SLASH)) {
+ GetNodeNode *get_node = alloc_node<GetNodeNode>();
+ IdentifierNode *identifier_root = alloc_node<IdentifierNode>();
+ get_node->chain.push_back(identifier_root);
+ int chain_position = 0;
+ do {
+ make_completion_context(COMPLETION_GET_NODE, get_node, chain_position++);
+ if (!current.is_node_name()) {
+ push_error(R"(Expect node path after "/".)");
+ return nullptr;
+ }
+ advance();
+ IdentifierNode *identifier = alloc_node<IdentifierNode>();
+ identifier->name = previous.get_identifier();
+ get_node->chain.push_back(identifier);
+ } while (match(GDScriptTokenizer::Token::SLASH));
+ return get_node;
} else {
push_error(R"(Expect node path as string or identifier after "$".)");
return nullptr;
@@ -2977,7 +3069,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
if (!comments.has(p_line)) {
return;
}
- ERR_FAIL_COND(p_brief != "" || p_desc != "" || p_tutorials.size() != 0);
+ ERR_FAIL_COND(!p_brief.is_empty() || !p_desc.is_empty() || p_tutorials.size() != 0);
int line = p_line;
bool in_codeblock = false;
@@ -3009,7 +3101,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
String striped_line = doc_line.strip_edges();
// Set the read mode.
- if (striped_line.begins_with("@desc:") && p_desc == "") {
+ if (striped_line.begins_with("@desc:") && p_desc.is_empty()) {
mode = DESC;
striped_line = striped_line.trim_prefix("@desc:");
in_codeblock = _in_codeblock(doc_line, in_codeblock);
@@ -3027,9 +3119,9 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
} else {
/* Syntax:
- @tutorial ( The Title Here ) : https://the.url/
- ^ open ^ close ^ colon ^ url
- */
+ * @tutorial ( The Title Here ) : https://the.url/
+ * ^ open ^ close ^ colon ^ url
+ */
int open_bracket_pos = begin_scan, close_bracket_pos = 0;
while (open_bracket_pos < striped_line.length() && (striped_line[open_bracket_pos] == ' ' || striped_line[open_bracket_pos] == '\t')) {
open_bracket_pos++;
@@ -3290,8 +3382,8 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
Variant::construct(parameter.type, r, &(name), 1, error);
p_annotation->resolved_arguments.push_back(r);
if (error.error != Callable::CallError::CALL_OK) {
- push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
- p_annotation->resolved_arguments.remove(p_annotation->resolved_arguments.size() - 1);
+ push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
+ p_annotation->resolved_arguments.remove_at(p_annotation->resolved_arguments.size() - 1);
return false;
}
break;
@@ -3299,13 +3391,13 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
[[fallthrough]];
default: {
if (argument->type != Node::LITERAL) {
- push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
+ push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
return false;
}
Variant value = static_cast<LiteralNode *>(argument)->value;
if (!Variant::can_convert_strict(value.get_type(), parameter.type)) {
- push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
+ push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
return false;
}
Callable::CallError error;
@@ -3314,8 +3406,8 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
Variant::construct(parameter.type, r, &(args), 1, error);
p_annotation->resolved_arguments.push_back(r);
if (error.error != Callable::CallError::CALL_OK) {
- push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
- p_annotation->resolved_arguments.remove(p_annotation->resolved_arguments.size() - 1);
+ push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
+ p_annotation->resolved_arguments.remove_at(p_annotation->resolved_arguments.size() - 1);
return false;
}
break;
@@ -3419,7 +3511,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
String enum_hint_string;
for (const Map<StringName, int>::Element *E = export_type.enum_values.front(); E; E = E->next()) {
- enum_hint_string += E->key().operator String().camelcase_to_underscore(true).capitalize().xml_escape();
+ enum_hint_string += E->key().operator String().capitalize().xml_escape();
enum_hint_string += ":";
enum_hint_string += String::num_int64(E->get()).xml_escape();
@@ -3481,22 +3573,22 @@ 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") {
- rpc_config.rpc_mode = Multiplayer::RPC_MODE_ANY;
- } else if (mode == "auth") {
+ if (mode == "any_peer") {
+ rpc_config.rpc_mode = Multiplayer::RPC_MODE_ANY_PEER;
+ } else if (mode == "authority") {
rpc_config.rpc_mode = Multiplayer::RPC_MODE_AUTHORITY;
- } else if (mode == "sync") {
- rpc_config.sync = true;
- } else if (mode == "nosync") {
- rpc_config.sync = false;
+ } else if (mode == "call_local") {
+ rpc_config.call_local = true;
+ } else if (mode == "call_remote") {
+ rpc_config.call_local = false;
} else if (mode == "reliable") {
rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE;
} else if (mode == "unreliable") {
rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_UNRELIABLE;
- } else if (mode == "ordered") {
- rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_ORDERED;
+ } else if (mode == "unreliable_ordered") {
+ rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED;
} else {
- push_error(R"(Invalid RPC argument. Must be one of: 'sync'/'nosync' (local calls), 'any'/'auth' (permission), 'reliable'/'unreliable'/'ordered' (transfer mode).)", p_annotation);
+ 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);
}
}
}
@@ -4433,7 +4525,7 @@ void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) {
if (p_variable->property == VariableNode::PROP_INLINE) {
push_line(":");
increase_indent();
- print_suite(p_variable->getter);
+ print_suite(p_variable->getter->body);
decrease_indent();
} else {
push_line(" =");
@@ -4453,7 +4545,7 @@ void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) {
}
push_line("):");
increase_indent();
- print_suite(p_variable->setter);
+ print_suite(p_variable->setter->body);
decrease_indent();
} else {
push_line(" =");
@@ -4492,7 +4584,7 @@ void GDScriptParser::TreePrinter::print_tree(const GDScriptParser &p_parser) {
}
print_class(p_parser.get_tree());
- print_line(printed);
+ print_line(String(printed));
}
#endif // DEBUG_ENABLED