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.cpp140
1 files changed, 80 insertions, 60 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 6ef3ab67ae..112569a8d6 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -3349,7 +3349,12 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
}
p_block->statements.push_back(expression);
if (!_end_statement()) {
- _set_error("Expected end of statement after expression.");
+ // Attempt to guess a better error message if the user "retypes" a variable
+ if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON && tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) {
+ _set_error("Unexpected ':=', use '=' instead. Expected end of statement after expression.");
+ } else {
+ _set_error(String() + "Expected end of statement after expression, got " + tokenizer->get_token_name(tokenizer->get_token()) + " instead");
+ }
return;
}
@@ -4040,7 +4045,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
- tokenizer->advance();
+#define _ADVANCE_AND_CONSUME_NEWLINES \
+ do { \
+ tokenizer->advance(); \
+ } while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE)
+
+ _ADVANCE_AND_CONSUME_NEWLINES;
+ parenthesis++;
String hint_prefix = "";
bool is_arrayed = false;
@@ -4070,11 +4081,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
current_export.type = type;
current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
// hint expected next!
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
switch (type) {
@@ -4082,7 +4093,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FLAGS") {
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
WARN_DEPRECATED_MSG("Exporting bit flags hint requires string constants.");
@@ -4094,7 +4105,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
current_export.hint = PROPERTY_HINT_FLAGS;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
bool first = true;
while (true) {
@@ -4113,7 +4124,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
current_export.hint_string += c.xml_escape();
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE)
break;
@@ -4122,7 +4133,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
_set_error("Expected \")\" or \",\" in the named bit flags hint.");
return;
}
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
}
break;
@@ -4130,7 +4141,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_2D_RENDER") {
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected \")\" in the layers 2D render hint.");
return;
@@ -4141,7 +4152,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_2D_PHYSICS") {
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected \")\" in the layers 2D physics hint.");
return;
@@ -4152,7 +4163,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_3D_RENDER") {
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected \")\" in the layers 3D render hint.");
return;
@@ -4163,7 +4174,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_3D_PHYSICS") {
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected \")\" in the layers 3D physics hint.");
return;
@@ -4193,7 +4204,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
current_export.hint_string += c.xml_escape();
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE)
break;
@@ -4203,7 +4214,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
}
break;
@@ -4215,7 +4226,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "EASE") {
current_export.hint = PROPERTY_HINT_EXP_EASING;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected \")\" in the hint.");
return;
@@ -4227,7 +4238,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "EXP") {
current_export.hint = PROPERTY_HINT_EXP_RANGE;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE)
break;
@@ -4235,7 +4246,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
_set_error("Expected \")\" or \",\" in the exponential range hint.");
return;
}
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
} else
current_export.hint = PROPERTY_HINT_RANGE;
@@ -4243,7 +4254,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_SUB) {
sign = -1;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) {
@@ -4253,7 +4264,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
current_export.hint_string = rtos(sign * double(tokenizer->get_token_constant()));
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
current_export.hint_string = "0," + current_export.hint_string;
@@ -4267,12 +4278,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
sign = 1.0;
if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_SUB) {
sign = -1;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) {
@@ -4283,7 +4294,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
current_export.hint_string += "," + rtos(sign * double(tokenizer->get_token_constant()));
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE)
break;
@@ -4295,11 +4306,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
sign = 1.0;
if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_SUB) {
sign = -1;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) {
@@ -4310,7 +4321,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
current_export.hint_string += "," + rtos(sign * double(tokenizer->get_token_constant()));
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
} break;
case Variant::STRING: {
@@ -4335,7 +4346,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
first = false;
current_export.hint_string += c.xml_escape();
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE)
break;
@@ -4344,7 +4355,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
_set_error("Expected \")\" or \",\" in the enumeration hint.");
return;
}
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
}
break;
@@ -4352,13 +4363,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "DIR") {
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE)
current_export.hint = PROPERTY_HINT_DIR;
else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() != GDScriptTokenizer::TK_IDENTIFIER || !(tokenizer->get_token_identifier() == "GLOBAL")) {
_set_error("Expected \"GLOBAL\" after comma in the directory hint.");
@@ -4369,7 +4380,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
current_export.hint = PROPERTY_HINT_GLOBAL_DIR;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected \")\" in the hint.");
@@ -4385,11 +4396,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FILE") {
current_export.hint = PROPERTY_HINT_FILE;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "GLOBAL") {
@@ -4398,12 +4409,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
current_export.hint = PROPERTY_HINT_GLOBAL_FILE;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE)
break;
else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA)
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
else {
_set_error("Expected \")\" or \",\" in the hint.");
return;
@@ -4419,7 +4430,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
current_export.hint_string = tokenizer->get_token_constant();
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
@@ -4432,7 +4443,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "MULTILINE") {
current_export.hint = PROPERTY_HINT_MULTILINE_TEXT;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected \")\" in the hint.");
return;
@@ -4459,7 +4470,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
_set_error("Color type hint expects RGB or RGBA as hints.");
return;
}
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
} break;
default: {
@@ -4510,11 +4521,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
bool is_flags = false;
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FLAGS") {
is_flags = true;
- tokenizer->advance();
+ _ADVANCE_AND_CONSUME_NEWLINES;
} else {
current_export = PropertyInfo();
_set_error("Expected \"FLAGS\" after comma.");
@@ -4558,6 +4569,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
+ tokenizer->advance();
+ parenthesis--;
+
if (is_arrayed) {
hint_prefix += itos(current_export.type);
if (current_export.hint) {
@@ -4567,8 +4581,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
current_export.hint = PROPERTY_HINT_TYPE_STRING;
current_export.type = Variant::ARRAY;
}
-
- tokenizer->advance();
+#undef _ADVANCE_AND_CONSUME_NEWLINES
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR && tokenizer->get_token() != GDScriptTokenizer::TK_PR_ONREADY && tokenizer->get_token() != GDScriptTokenizer::TK_PR_REMOTE && tokenizer->get_token() != GDScriptTokenizer::TK_PR_MASTER && tokenizer->get_token() != GDScriptTokenizer::TK_PR_PUPPET && tokenizer->get_token() != GDScriptTokenizer::TK_PR_SYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_REMOTESYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_MASTERSYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_PUPPETSYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_SLAVE) {
@@ -8180,7 +8193,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
}
#endif // DEBUG_ENABLED
+ bool type_match = check_types;
if (check_types && !_is_type_compatible(lh_type, rh_type)) {
+ type_match = false;
// Try supertype test
if (_is_type_compatible(rh_type, lh_type)) {
_mark_line_as_unsafe(op->line);
@@ -8192,23 +8207,27 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
op->line);
return;
}
- // Replace assignment with implicit conversion
- BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>();
- convert->line = op->line;
- convert->function = GDScriptFunctions::TYPE_CONVERT;
-
- ConstantNode *tgt_type = alloc_node<ConstantNode>();
- tgt_type->line = op->line;
- tgt_type->value = (int)lh_type.builtin_type;
-
- OperatorNode *convert_call = alloc_node<OperatorNode>();
- convert_call->line = op->line;
- convert_call->op = OperatorNode::OP_CALL;
- convert_call->arguments.push_back(convert);
- convert_call->arguments.push_back(op->arguments[1]);
- convert_call->arguments.push_back(tgt_type);
-
- op->arguments.write[1] = convert_call;
+ if (op->op == OperatorNode::OP_ASSIGN) {
+ // Replace assignment with implicit conversion
+ BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>();
+ convert->line = op->line;
+ convert->function = GDScriptFunctions::TYPE_CONVERT;
+
+ ConstantNode *tgt_type = alloc_node<ConstantNode>();
+ tgt_type->line = op->line;
+ tgt_type->value = (int)lh_type.builtin_type;
+
+ OperatorNode *convert_call = alloc_node<OperatorNode>();
+ convert_call->line = op->line;
+ convert_call->op = OperatorNode::OP_CALL;
+ convert_call->arguments.push_back(convert);
+ convert_call->arguments.push_back(op->arguments[1]);
+ convert_call->arguments.push_back(tgt_type);
+
+ op->arguments.write[1] = convert_call;
+
+ type_match = true; // Since we are converting, the type is matching
+ }
#ifdef DEBUG_ENABLED
if (lh_type.builtin_type == Variant::INT && rh_type.builtin_type == Variant::REAL) {
_add_warning(GDScriptWarning::NARROWING_CONVERSION, op->line);
@@ -8221,6 +8240,7 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
_mark_line_as_unsafe(op->line);
}
#endif // DEBUG_ENABLED
+ op->datatype.has_type = type_match;
} break;
case OperatorNode::OP_CALL:
case OperatorNode::OP_PARENT_CALL: {