summaryrefslogtreecommitdiff
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.cpp166
1 files changed, 109 insertions, 57 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index f005f88d2e..de15f939ce 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -282,7 +282,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
switch (tokenizer->get_token()) {
case GDScriptTokenizer::TK_CURSOR: {
- completion_cursor = StringName();
completion_type = COMPLETION_GET_NODE;
completion_class = current_class;
completion_function = current_function;
@@ -777,7 +776,8 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
_add_warning(GDScriptWarning::UNASSIGNED_VARIABLE_OP_ASSIGN, -1, identifier.operator String());
}
- } // fallthrough
+ FALLTHROUGH;
+ }
case GDScriptTokenizer::TK_OP_ASSIGN: {
lv->assignments += 1;
lv->usages--; // Assignment is not really usage
@@ -887,7 +887,8 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
case GDScriptTokenizer::TK_OP_SUB: e.op = OperatorNode::OP_NEG; break;
case GDScriptTokenizer::TK_OP_NOT: e.op = OperatorNode::OP_NOT; break;
case GDScriptTokenizer::TK_OP_BIT_INVERT: e.op = OperatorNode::OP_BIT_INVERT; break;
- default: {}
+ default: {
+ }
}
tokenizer->advance();
@@ -1874,7 +1875,9 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to
}
} break;
- default: { break; }
+ default: {
+ break;
+ }
}
//now se if all are constants
if (!all_constants)
@@ -1987,7 +1990,9 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to
return op->arguments[2];
}
} break;
- default: { ERR_FAIL_V(op); }
+ default: {
+ ERR_FAIL_V(op);
+ }
}
ERR_FAIL_V(op);
@@ -2225,6 +2230,8 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode *> &p_branches, bool p_static) {
int indent_level = tab_level.back()->get();
+ p_block->has_return = true;
+
while (true) {
while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline())
@@ -2282,8 +2289,8 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran
current_block = p_block;
- if (catch_all && branch->body->has_return) {
- p_block->has_return = true;
+ if (!branch->body->has_return) {
+ p_block->has_return = false;
}
p_branches.push_back(branch);
@@ -2741,6 +2748,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
} break;
case GDScriptTokenizer::TK_NEWLINE: {
+ int line = tokenizer->get_token_line();
+
if (!_parse_newline()) {
if (!error_set) {
p_block->end_line = tokenizer->get_token_line();
@@ -2750,7 +2759,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
}
NewLineNode *nl2 = alloc_node<NewLineNode>();
- nl2->line = tokenizer->get_token_line();
+ nl2->line = line;
p_block->statements.push_back(nl2);
} break;
@@ -2860,8 +2869,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
lv->assign_op = op;
lv->assign = assigned;
- lv->assign_op = op;
-
if (!_end_statement()) {
_set_error("Expected end of statement (var)");
return;
@@ -3490,6 +3497,10 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
_set_error("'class_name' is only valid for the main class namespace.");
return;
}
+ if (self_path.empty()) {
+ _set_error("'class_name' not allowed in built-in scripts.");
+ return;
+ }
if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) {
_set_error("'class_name' syntax: 'class_name <UniqueName>'");
@@ -3632,7 +3643,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- }; //fallthrough to function
+ FALLTHROUGH;
+ }
case GDScriptTokenizer::TK_PR_FUNCTION: {
bool _static = false;
@@ -3675,6 +3687,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
_add_warning(GDScriptWarning::FUNCTION_CONFLICTS_VARIABLE, -1, name);
}
}
+ for (int i = 0; i < p_class->subclasses.size(); i++) {
+ if (p_class->subclasses[i]->name == name) {
+ _add_warning(GDScriptWarning::FUNCTION_CONFLICTS_CONSTANT, -1, name);
+ }
+ }
#endif // DEBUG_ENABLED
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
@@ -4082,7 +4099,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
break;
}
- }; //fallthrough to use the same
+ FALLTHROUGH;
+ }
case Variant::REAL: {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "EASE") {
@@ -4507,6 +4525,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
#ifdef DEBUG_ENABLED
_add_warning(GDScriptWarning::DEPRECATED_KEYWORD, tokenizer->get_token_line(), "slave", "puppet");
#endif
+ FALLTHROUGH;
case GDScriptTokenizer::TK_PR_PUPPET: {
//may be fallthrough from export, ignore if so
@@ -4574,7 +4593,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
continue;
} break;
case GDScriptTokenizer::TK_PR_VAR: {
- //variale declaration and (eventual) initialization
+ // variable declaration and (eventual) initialization
ClassNode::Member member;
@@ -4617,6 +4636,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
}
+
+ for (int i = 0; i < current_class->subclasses.size(); i++) {
+ if (current_class->subclasses[i]->name == member.identifier) {
+ _set_error("A class named '" + String(member.identifier) + "' already exists in this class (at line " + itos(current_class->subclasses[i]->line) + ").");
+ return;
+ }
+ }
#ifdef DEBUG_ENABLED
for (int i = 0; i < current_class->functions.size(); i++) {
if (current_class->functions[i]->name == member.identifier) {
@@ -4756,19 +4782,30 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- if (member._export.type != Variant::NIL) {
+ Variant::Type initial_type = member.data_type.has_type ? member.data_type.builtin_type : member._export.type;
+
+ if (initial_type != Variant::NIL && initial_type != Variant::OBJECT) {
IdentifierNode *id = alloc_node<IdentifierNode>();
id->name = member.identifier;
- ConstantNode *cn = alloc_node<ConstantNode>();
+ Node *expr;
- Variant::CallError ce2;
- cn->value = Variant::construct(member._export.type, NULL, 0, ce2);
+ // Make sure arrays and dictionaries are not shared
+ if (initial_type == Variant::ARRAY) {
+ expr = alloc_node<ArrayNode>();
+ } else if (initial_type == Variant::DICTIONARY) {
+ expr = alloc_node<DictionaryNode>();
+ } else {
+ ConstantNode *cn = alloc_node<ConstantNode>();
+ Variant::CallError ce2;
+ cn->value = Variant::construct(initial_type, NULL, 0, ce2);
+ expr = cn;
+ }
OperatorNode *op = alloc_node<OperatorNode>();
op->op = OperatorNode::OP_INIT_ASSIGN;
op->arguments.push_back(id);
- op->arguments.push_back(cn);
+ op->arguments.push_back(expr);
p_class->initializer->statements.push_back(op);
@@ -4861,6 +4898,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
}
+ for (int i = 0; i < current_class->subclasses.size(); i++) {
+ if (current_class->subclasses[i]->name == const_id) {
+ _set_error("A class named '" + String(const_id) + "' already exists in this class (at line " + itos(current_class->subclasses[i]->line) + ").");
+ return;
+ }
+ }
+
tokenizer->advance();
if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) {
@@ -4931,6 +4975,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
}
+ for (int i = 0; i < current_class->subclasses.size(); i++) {
+ if (current_class->subclasses[i]->name == enum_name) {
+ _set_error("A class named '" + String(enum_name) + "' already exists in this class (at line " + itos(current_class->subclasses[i]->line) + ").");
+ return;
+ }
+ }
+
tokenizer->advance();
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_CURLY_BRACKET_OPEN) {
@@ -5016,6 +5067,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
}
+ for (int i = 0; i < current_class->subclasses.size(); i++) {
+ if (current_class->subclasses[i]->name == const_id) {
+ _set_error("A class named '" + String(const_id) + "' already exists in this class (at line " + itos(current_class->subclasses[i]->line) + ").");
+ return;
+ }
+ }
+
ClassNode::Constant constant;
constant.type.has_type = true;
constant.type.kind = DataType::BUILTIN;
@@ -5286,7 +5344,8 @@ String GDScriptParser::DataType::to_string() const {
if (!gds_class.empty()) {
return gds_class;
}
- } // fallthrough
+ FALLTHROUGH;
+ }
case SCRIPT: {
if (is_meta_type) {
return script_type->get_class_name().operator String();
@@ -6175,8 +6234,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
return DataType();
}
#ifdef DEBUG_ENABLED
- if (var_op == Variant::OP_DIVIDE && argument_a_type.has_type && argument_a_type.kind == DataType::BUILTIN && argument_a_type.builtin_type == Variant::INT &&
- argument_b_type.has_type && argument_b_type.kind == DataType::BUILTIN && argument_b_type.builtin_type == Variant::INT) {
+ if (var_op == Variant::OP_DIVIDE && argument_a_type.kind == DataType::BUILTIN && argument_a_type.builtin_type == Variant::INT &&
+ argument_b_type.kind == DataType::BUILTIN && argument_b_type.builtin_type == Variant::INT) {
_add_warning(GDScriptWarning::INTEGER_DIVISION, op->line);
}
#endif // DEBUG_ENABLED
@@ -6342,7 +6401,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
case Variant::COLOR: {
error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::STRING;
} break;
- default: {}
+ default: {
+ }
}
}
if (error) {
@@ -6460,7 +6520,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
}
}
} break;
- default: {}
+ default: {
+ }
}
p_node->set_datatype(_resolve_type(node_type, p_node->line));
@@ -6885,10 +6946,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
#ifdef DEBUG_ENABLED
if (current_function && !for_completion && !is_static && p_call->arguments[0]->type == Node::TYPE_SELF && current_function->_static) {
- if (current_function && current_function->_static && p_call->arguments[0]->type == Node::TYPE_SELF) {
- _set_error("Can't call non-static function from a static function.", p_call->line);
- return DataType();
- }
+ _set_error("Can't call non-static function from a static function.", p_call->line);
+ return DataType();
}
if (check_types && !is_static && !is_initializer && base_type.is_meta_type) {
@@ -7414,7 +7473,7 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) {
return;
}
- // Replace assignment with implict conversion
+ // Replace assignment with implicit conversion
BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>();
convert->line = v.line;
convert->function = GDScriptFunctions::TYPE_CONVERT;
@@ -7443,30 +7502,6 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) {
v.data_type = expr_type;
v.data_type.is_constant = false;
}
- } else if (v.data_type.has_type && v.data_type.kind == DataType::BUILTIN) {
- // Create default value based on the type
- IdentifierNode *id = alloc_node<IdentifierNode>();
- id->line = v.line;
- id->name = v.identifier;
-
- ConstantNode *init = alloc_node<ConstantNode>();
- init->line = v.line;
- Variant::CallError err;
- init->value = Variant::construct(v.data_type.builtin_type, NULL, 0, err);
-
- OperatorNode *op = alloc_node<OperatorNode>();
- op->line = v.line;
- op->op = OperatorNode::OP_INIT_ASSIGN;
- op->arguments.push_back(id);
- op->arguments.push_back(init);
-
- p_class->initializer->statements.push_front(op);
- v.initial_assignment = op;
-#ifdef DEBUG_ENABLED
- NewLineNode *nl = alloc_node<NewLineNode>();
- nl->line = v.line - 1;
- p_class->initializer->statements.push_front(nl);
-#endif
}
// Check export hint
@@ -7605,6 +7640,11 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
if (p_function->arguments_usage[i] == 0 && !p_function->arguments[i].operator String().begins_with("_")) {
_add_warning(GDScriptWarning::UNUSED_ARGUMENT, p_function->line, p_function->name, p_function->arguments[i].operator String());
}
+ for (int j = 0; j < current_class->variables.size(); j++) {
+ if (current_class->variables[j].identifier == p_function->arguments[i]) {
+ _add_warning(GDScriptWarning::SHADOWED_VARIABLE, p_function->line, p_function->arguments[i], itos(current_class->variables[j].line));
+ }
+ }
#endif // DEBUG_ENABLED
}
@@ -7678,6 +7718,17 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
p_function->return_type.has_type = false;
p_function->return_type.may_yield = true;
}
+
+#ifdef DEBUG_ENABLED
+ for (Map<StringName, LocalVarNode *>::Element *E = p_function->body->variables.front(); E; E = E->next()) {
+ LocalVarNode *lv = E->get();
+ for (int i = 0; i < current_class->variables.size(); i++) {
+ if (current_class->variables[i].identifier == lv->name) {
+ _add_warning(GDScriptWarning::SHADOWED_VARIABLE, lv->line, lv->name, itos(current_class->variables[i].line));
+ }
+ }
+ }
+#endif // DEBUG_ENABLED
}
void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) {
@@ -7786,14 +7837,14 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
if (_is_type_compatible(assign_type, lv->datatype)) {
_mark_line_as_unsafe(lv->line);
} else {
- // Try implict conversion
+ // Try implicit conversion
if (lv->datatype.kind != DataType::BUILTIN || !_is_type_compatible(lv->datatype, assign_type, true)) {
_set_error("Assigned value type (" + assign_type.to_string() + ") doesn't match the variable's type (" +
lv->datatype.to_string() + ").",
lv->line);
return;
}
- // Replace assignment with implict conversion
+ // Replace assignment with implicit conversion
BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>();
convert->line = lv->line;
convert->function = GDScriptFunctions::TYPE_CONVERT;
@@ -7917,14 +7968,14 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
if (_is_type_compatible(rh_type, lh_type)) {
_mark_line_as_unsafe(op->line);
} else {
- // Try implict conversion
+ // Try implicit conversion
if (lh_type.kind != DataType::BUILTIN || !_is_type_compatible(lh_type, rh_type, true)) {
_set_error("Assigned value type (" + rh_type.to_string() + ") doesn't match the variable's type (" +
lh_type.to_string() + ").",
op->line);
return;
}
- // Replace assignment with implict conversion
+ // Replace assignment with implicit conversion
BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>();
convert->line = op->line;
convert->function = GDScriptFunctions::TYPE_CONVERT;
@@ -8042,7 +8093,8 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
if (cn->value.get_type() == Variant::STRING) {
break;
}
- } // falthrough
+ FALLTHROUGH;
+ }
default: {
_mark_line_as_safe(statement->line);
_reduce_node_type(statement); // Test for safety anyway