summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml2
-rw-r--r--modules/gdscript/doc_classes/GDScriptFunctionState.xml2
-rw-r--r--modules/gdscript/doc_classes/GDScriptNativeClass.xml2
-rw-r--r--modules/gdscript/gdscript.cpp9
-rw-r--r--modules/gdscript/gdscript.h6
-rw-r--r--modules/gdscript/gdscript_compiler.cpp23
-rw-r--r--modules/gdscript/gdscript_editor.cpp47
-rw-r--r--modules/gdscript/gdscript_functions.cpp39
-rw-r--r--modules/gdscript/gdscript_functions.h3
-rw-r--r--modules/gdscript/gdscript_parser.cpp121
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp13
11 files changed, 181 insertions, 86 deletions
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 46796c68eb..d606a41fab 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -10,8 +10,6 @@
<tutorials>
<link>https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/index.html</link>
</tutorials>
- <demos>
- </demos>
<methods>
<method name="get_as_byte_code" qualifiers="const">
<return type="PoolByteArray">
diff --git a/modules/gdscript/doc_classes/GDScriptFunctionState.xml b/modules/gdscript/doc_classes/GDScriptFunctionState.xml
index f38f39b612..690953108f 100644
--- a/modules/gdscript/doc_classes/GDScriptFunctionState.xml
+++ b/modules/gdscript/doc_classes/GDScriptFunctionState.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <demos>
- </demos>
<methods>
<method name="is_valid" qualifiers="const">
<return type="bool">
diff --git a/modules/gdscript/doc_classes/GDScriptNativeClass.xml b/modules/gdscript/doc_classes/GDScriptNativeClass.xml
index e86b69c31c..70583d47a7 100644
--- a/modules/gdscript/doc_classes/GDScriptNativeClass.xml
+++ b/modules/gdscript/doc_classes/GDScriptNativeClass.xml
@@ -6,8 +6,6 @@
</description>
<tutorials>
</tutorials>
- <demos>
- </demos>
<methods>
<method name="new">
<return type="Variant">
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 5e327bdd92..3fb9268702 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -227,7 +227,7 @@ void GDScript::get_script_method_list(List<MethodInfo> *p_list) const {
const GDScript *current = this;
while (current) {
- for (const Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
+ for (const Map<StringName, GDScriptFunction *>::Element *E = current->member_functions.front(); E; E = E->next()) {
GDScriptFunction *func = E->get();
MethodInfo mi;
mi.name = E->key();
@@ -1065,7 +1065,7 @@ Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool
}
void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
- // exported members, not doen yet!
+ // exported members, not done yet!
const GDScript *sptr = script.ptr();
List<PropertyInfo> props;
@@ -1967,6 +1967,10 @@ String GDScriptWarning::get_message() const {
CHECK_SYMBOLS(1);
return "The local variable '" + symbols[0] + "' is declared but never used in the block.";
} break;
+ case SHADOWED_VARIABLE: {
+ CHECK_SYMBOLS(2);
+ return "The local variable '" + symbols[0] + "' is shadowing an already defined variable at line " + symbols[1] + ".";
+ } break;
case UNUSED_CLASS_VARIABLE: {
CHECK_SYMBOLS(1);
return "The class variable '" + symbols[0] + "' is declared but never used in the script.";
@@ -2070,6 +2074,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"UNASSIGNED_VARIABLE",
"UNASSIGNED_VARIABLE_OP_ASSIGN",
"UNUSED_VARIABLE",
+ "SHADOWED_VARIABLE",
"UNUSED_CLASS_VARIABLE",
"UNUSED_ARGUMENT",
"UNREACHABLE_CODE",
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 7b6755e112..716f536e89 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -274,6 +274,7 @@ struct GDScriptWarning {
UNASSIGNED_VARIABLE, // Variable used but never assigned
UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc)
UNUSED_VARIABLE, // Local variable is declared but never used
+ SHADOWED_VARIABLE, // Variable name shadowed by other variable
UNUSED_CLASS_VARIABLE, // Class variable is declared but never used in the file
UNUSED_ARGUMENT, // Function argument is never used
UNREACHABLE_CODE, // Code after a return statement
@@ -407,9 +408,10 @@ public:
csi.resize(_debug_call_stack_pos);
for (int i = 0; i < _debug_call_stack_pos; i++) {
csi.write[_debug_call_stack_pos - i - 1].line = _call_stack[i].line ? *_call_stack[i].line : 0;
- if (_call_stack[i].function)
+ if (_call_stack[i].function) {
csi.write[_debug_call_stack_pos - i - 1].func = _call_stack[i].function->get_name();
- csi.write[_debug_call_stack_pos - i - 1].file = _call_stack[i].function->get_script()->get_path();
+ csi.write[_debug_call_stack_pos - i - 1].file = _call_stack[i].function->get_script()->get_path();
+ }
}
return csi;
}
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index ae67521749..f7be0ce37c 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -480,16 +480,16 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
switch (cast_type.kind) {
case GDScriptDataType::BUILTIN: {
codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_BUILTIN);
- codegen.opcodes.push_back(cn->cast_type.builtin_type);
+ codegen.opcodes.push_back(cast_type.builtin_type);
} break;
case GDScriptDataType::NATIVE: {
int class_idx;
- if (GDScriptLanguage::get_singleton()->get_global_map().has(cn->cast_type.native_type)) {
+ if (GDScriptLanguage::get_singleton()->get_global_map().has(cast_type.native_type)) {
- class_idx = GDScriptLanguage::get_singleton()->get_global_map()[cn->cast_type.native_type];
+ class_idx = GDScriptLanguage::get_singleton()->get_global_map()[cast_type.native_type];
class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root)
} else {
- _set_error("Invalid native class type '" + String(cn->cast_type.native_type) + "'.", cn);
+ _set_error("Invalid native class type '" + String(cast_type.native_type) + "'.", cn);
return -1;
}
codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_NATIVE); // perform operator
@@ -498,7 +498,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
case GDScriptDataType::SCRIPT:
case GDScriptDataType::GDSCRIPT: {
- Variant script = cn->cast_type.script_type;
+ Variant script = cast_type.script_type;
int idx = codegen.get_constant_pos(script);
idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access)
@@ -1863,6 +1863,19 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->base = base;
p_script->_base = base.ptr();
p_script->member_indices = base->member_indices;
+
+ if (p_class->base_type.kind == GDScriptParser::DataType::CLASS) {
+ if (!parsed_classes.has(p_script->_base)) {
+ if (parsing_classes.has(p_script->_base)) {
+ _set_error("Cyclic class reference for '" + String(p_class->name) + "'.", p_class);
+ return ERR_PARSE_ERROR;
+ }
+ Error err = _parse_class_level(p_script->_base, p_class->base_type.class_type, p_keep_state);
+ if (err) {
+ return err;
+ }
+ }
+ }
} break;
default: {
_set_error("Parser bug: invalid inheritance.", p_class);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index df8fc2267d..d91e32249e 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -511,8 +511,10 @@ struct GDScriptCompletionIdentifier {
static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Set<String> &r_list) {
+ const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
+
for (int i = 0; i < p_dir->get_file_count(); i++) {
- r_list.insert("\"" + p_dir->get_file_path(i) + "\"");
+ r_list.insert(quote_style + p_dir->get_file_path(i) + quote_style);
}
for (int i = 0; i < p_dir->get_subdir_count(); i++) {
@@ -1949,7 +1951,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
} else {
base_type.has_type = script->get_instance_base_type() != StringName();
base_type.kind = GDScriptParser::DataType::NATIVE;
- base_type.script_type = script->get_instance_base_type();
+ base_type.native_type = script->get_instance_base_type();
}
} else {
return;
@@ -2176,7 +2178,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Set<String> &r_result, String &r_arghint) {
Variant base = p_base.value;
GDScriptParser::DataType base_type = p_base.type;
- bool _static = false;
+
+ const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
while (base_type.has_type) {
switch (base_type.kind) {
@@ -2187,18 +2190,16 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
return;
}
}
- if (!_static) {
- for (int i = 0; i < base_type.class_type->functions.size(); i++) {
- if (base_type.class_type->functions[i]->name == p_method) {
- r_arghint = _make_arguments_hint(base_type.class_type->functions[i], p_argidx);
- return;
- }
+ for (int i = 0; i < base_type.class_type->functions.size(); i++) {
+ if (base_type.class_type->functions[i]->name == p_method) {
+ r_arghint = _make_arguments_hint(base_type.class_type->functions[i], p_argidx);
+ return;
}
}
if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) {
for (int i = 0; i < base_type.class_type->_signals.size(); i++) {
- r_result.insert("\"" + base_type.class_type->_signals[i].name.operator String() + "\"");
+ r_result.insert(quote_style + base_type.class_type->_signals[i].name.operator String() + quote_style);
}
}
@@ -2211,7 +2212,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
List<MethodInfo> signals;
gds->get_script_signal_list(&signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
- r_result.insert("\"" + E->get().name + "\"");
+ r_result.insert(quote_style + E->get().name + quote_style);
}
}
Ref<GDScript> base_script = gds->get_base_script();
@@ -2270,7 +2271,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
List<MethodInfo> signals;
ClassDB::get_signal_list(class_name, &signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
- r_result.insert("\"" + E->get().name + "\"");
+ r_result.insert(quote_style + E->get().name + quote_style);
}
}
@@ -2285,7 +2286,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
continue;
}
String name = s.get_slice("/", 1);
- r_result.insert("\"/root/" + name + "\"");
+ r_result.insert(quote_style + "/root/" + name + quote_style);
}
}
@@ -2299,7 +2300,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
continue;
}
String name = s.get_slice("/", 1);
- r_result.insert("\"" + name + "\"");
+ r_result.insert(quote_style + name + quote_style);
}
}
@@ -2334,6 +2335,8 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_node, int p_argidx, Set<String> &r_result, bool &r_forced, String &r_arghint) {
+ const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
+
if (!p_node || p_node->type != GDScriptParser::Node::TYPE_OPERATOR) {
return;
}
@@ -2451,7 +2454,7 @@ static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDS
Set<String> methods;
_find_identifiers_in_base(p_context, connect_base, true, methods);
for (Set<String>::Element *E = methods.front(); E; E = E->next()) {
- r_result.insert("\"" + E->get().replace("(", "").replace(")", "") + "\"");
+ r_result.insert(quote_style + E->get().replace("(", "").replace(")", "") + quote_style);
}
}
@@ -2460,6 +2463,8 @@ static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDS
Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) {
+ const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
+
GDScriptParser parser;
parser.parse(p_code, p_base_path, false, "", true);
@@ -2526,7 +2531,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
continue;
}
String name = s.get_slice("/", 1);
- options.insert("\"/root/" + name + "\"");
+ options.insert(quote_style + "/root/" + name + quote_style);
}
}
} break;
@@ -2666,7 +2671,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
switch (base_type.kind) {
case GDScriptParser::DataType::CLASS: {
for (int i = 0; i < base_type.class_type->_signals.size(); i++) {
- options.insert("\"" + base_type.class_type->_signals[i].name.operator String() + "\"");
+ options.insert(quote_style + base_type.class_type->_signals[i].name.operator String() + quote_style);
}
base_type = base_type.class_type->base_type;
} break;
@@ -2677,7 +2682,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
List<MethodInfo> signals;
scr->get_script_signal_list(&signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
- options.insert("\"" + E->get().name + "\"");
+ options.insert(quote_style + E->get().name + quote_style);
}
Ref<Script> base_script = scr->get_base_script();
if (base_script.is_valid()) {
@@ -2704,7 +2709,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
List<MethodInfo> signals;
ClassDB::get_signal_list(class_name, &signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
- options.insert("\"" + E->get().name + "\"");
+ options.insert(quote_style + E->get().name + quote_style);
}
} break;
default: {
@@ -2890,7 +2895,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
String GDScriptLanguage::_get_indentation() const {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", 0);
+ bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", false);
if (use_space_indentation) {
int indent_size = EDITOR_DEF("text_editor/indent/size", 4);
@@ -3008,8 +3013,8 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
}
}
+ base_type = base_type.class_type->base_type;
}
- base_type = base_type.class_type->base_type;
} break;
case GDScriptParser::DataType::SCRIPT:
case GDScriptParser::DataType::GDSCRIPT: {
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 4fd136d5cc..5ebcddfd7c 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -68,8 +68,11 @@ const char *GDScriptFunctions::get_func_name(Function p_func) {
"exp",
"is_nan",
"is_inf",
+ "is_equal_approx",
+ "is_zero_approx",
"ease",
"decimals",
+ "step_decimals",
"stepify",
"lerp",
"inverse_lerp",
@@ -316,6 +319,17 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
VALIDATE_ARG_NUM(0);
r_ret = Math::is_inf((double)*p_args[0]);
} break;
+ case MATH_ISEQUALAPPROX: {
+ VALIDATE_ARG_COUNT(2);
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ r_ret = Math::is_equal_approx((real_t)*p_args[0], (real_t)*p_args[1]);
+ } break;
+ case MATH_ISZEROAPPROX: {
+ VALIDATE_ARG_COUNT(1);
+ VALIDATE_ARG_NUM(0);
+ r_ret = Math::is_zero_approx((real_t)*p_args[0]);
+ } break;
case MATH_EASE: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
@@ -326,6 +340,13 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
r_ret = Math::step_decimals((double)*p_args[0]);
+ ERR_EXPLAIN("GDScript method 'decimals' is deprecated and has been renamed to 'step_decimals', please update your code accordingly.");
+ WARN_DEPRECATED
+ } break;
+ case MATH_STEP_DECIMALS: {
+ VALIDATE_ARG_COUNT(1);
+ VALIDATE_ARG_NUM(0);
+ r_ret = Math::step_decimals((double)*p_args[0]);
} break;
case MATH_STEPIFY: {
VALIDATE_ARG_COUNT(2);
@@ -1439,6 +1460,7 @@ bool GDScriptFunctions::is_deterministic(Function p_func) {
case MATH_ISINF:
case MATH_EASE:
case MATH_DECIMALS:
+ case MATH_STEP_DECIMALS:
case MATH_STEPIFY:
case MATH_LERP:
case MATH_INVERSE_LERP:
@@ -1596,6 +1618,16 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
mi.return_val.type = Variant::BOOL;
return mi;
} break;
+ case MATH_ISEQUALAPPROX: {
+ MethodInfo mi("is_equal_approx", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b"));
+ mi.return_val.type = Variant::BOOL;
+ return mi;
+ } break;
+ case MATH_ISZEROAPPROX: {
+ MethodInfo mi("is_zero_approx", PropertyInfo(Variant::REAL, "s"));
+ mi.return_val.type = Variant::BOOL;
+ return mi;
+ } break;
case MATH_EASE: {
MethodInfo mi("ease", PropertyInfo(Variant::REAL, "s"), PropertyInfo(Variant::REAL, "curve"));
mi.return_val.type = Variant::REAL;
@@ -1603,7 +1635,12 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
} break;
case MATH_DECIMALS: {
MethodInfo mi("decimals", PropertyInfo(Variant::REAL, "step"));
- mi.return_val.type = Variant::REAL;
+ mi.return_val.type = Variant::INT;
+ return mi;
+ } break;
+ case MATH_STEP_DECIMALS: {
+ MethodInfo mi("step_decimals", PropertyInfo(Variant::REAL, "step"));
+ mi.return_val.type = Variant::INT;
return mi;
} break;
case MATH_STEPIFY: {
diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h
index 14bf3d7560..c594480ff8 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/gdscript/gdscript_functions.h
@@ -59,8 +59,11 @@ public:
MATH_EXP,
MATH_ISNAN,
MATH_ISINF,
+ MATH_ISEQUALAPPROX,
+ MATH_ISZEROAPPROX,
MATH_EASE,
MATH_DECIMALS,
+ MATH_STEP_DECIMALS,
MATH_STEPIFY,
MATH_LERP,
MATH_INVERSE_LERP,
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index ddf880d36c..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;
@@ -2870,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;
@@ -3500,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>'");
@@ -3686,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) {
@@ -4630,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) {
@@ -4769,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);
@@ -4874,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) {
@@ -4944,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) {
@@ -5029,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;
@@ -6189,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
@@ -6901,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) {
@@ -7430,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;
@@ -7459,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
@@ -7621,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
}
@@ -7694,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) {
@@ -7802,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;
@@ -7933,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;
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index cc1f4333fc..b8048fb5dd 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -535,13 +535,14 @@ void GDScriptTokenizerText::_advance() {
}
}
#ifdef DEBUG_ENABLED
- if (comment.begins_with("#warning-ignore:")) {
- String code = comment.get_slice(":", 1);
+ String comment_content = comment.trim_prefix("#").trim_prefix(" ");
+ if (comment_content.begins_with("warning-ignore:")) {
+ String code = comment_content.get_slice(":", 1);
warning_skips.push_back(Pair<int, String>(line, code.strip_edges().to_lower()));
- } else if (comment.begins_with("#warning-ignore-all:")) {
- String code = comment.get_slice(":", 1);
+ } else if (comment_content.begins_with("warning-ignore-all:")) {
+ String code = comment_content.get_slice(":", 1);
warning_global_skips.insert(code.strip_edges().to_lower());
- } else if (comment.strip_edges() == "#warnings-disable") {
+ } else if (comment_content.strip_edges() == "warnings-disable") {
ignore_warnings = true;
}
#endif // DEBUG_ENABLED
@@ -895,7 +896,7 @@ void GDScriptTokenizerText::_advance() {
}
hexa_found = true;
} else if (!hexa_found && GETCHAR(i) == 'e') {
- if (hexa_found || exponent_found) {
+ if (exponent_found) {
_make_error("Invalid numeric constant at 'e'");
return;
}