From d15511725acdfe90f9d5967119294b591becd8fa Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Wed, 15 Feb 2023 17:41:46 +0300 Subject: [PATCH] GDScript: Fix `MIN_INT` not representable as numeric literal --- modules/gdscript/gdscript_tokenizer.cpp | 31 +++++++++++++++++++ modules/gdscript/gdscript_tokenizer.h | 2 ++ .../features/number_literals_with_sign.gd | 17 ++++++++++ .../features/number_literals_with_sign.out | 16 ++++++++++ 4 files changed, 66 insertions(+) create mode 100644 modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.gd create mode 100644 modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index d586380c413..034d517f6ee 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -162,6 +162,24 @@ const char *GDScriptTokenizer::Token::get_name() const { return token_names[type]; } +bool GDScriptTokenizer::Token::can_precede_bin_op() const { + switch (type) { + case IDENTIFIER: + case LITERAL: + case SELF: + case BRACKET_CLOSE: + case BRACE_CLOSE: + case PARENTHESIS_CLOSE: + case CONST_PI: + case CONST_TAU: + case CONST_INF: + case CONST_NAN: + return true; + default: + return false; + } +} + bool GDScriptTokenizer::Token::is_identifier() const { // Note: Most keywords should not be recognized as identifiers. // These are only exceptions for stuff that already is on the engine's API. @@ -382,6 +400,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::make_token(Token::Type p_type) { } } + last_token = token; return token; } @@ -627,6 +646,7 @@ void GDScriptTokenizer::newline(bool p_make_token) { newline.leftmost_column = newline.start_column; newline.rightmost_column = newline.end_column; pending_newline = true; + last_token = newline; last_newline = newline; } @@ -643,6 +663,11 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { bool has_error = false; bool (*digit_check_func)(char32_t) = is_digit; + // Sign before hexadecimal or binary. + if ((_peek(-1) == '+' || _peek(-1) == '-') && _peek() == '0') { + _advance(); + } + if (_peek(-1) == '.') { has_decimal = true; } else if (_peek(-1) == '0') { @@ -1431,6 +1456,9 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() { if (_peek() == '=') { _advance(); return make_token(Token::PLUS_EQUAL); + } else if (is_digit(_peek()) && !last_token.can_precede_bin_op()) { + // Number starting with '+'. + return number(); } else { return make_token(Token::PLUS); } @@ -1438,6 +1466,9 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() { if (_peek() == '=') { _advance(); return make_token(Token::MINUS_EQUAL); + } else if (is_digit(_peek()) && !last_token.can_precede_bin_op()) { + // Number starting with '-'. + return number(); } else if (_peek() == '>') { _advance(); return make_token(Token::FORWARD_ARROW); diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index 608840d3f1d..068393cee97 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -171,6 +171,7 @@ public: String source; const char *get_name() const; + bool can_precede_bin_op() const; bool is_identifier() const; bool is_node_name() const; StringName get_identifier() const { return source; } @@ -216,6 +217,7 @@ private: bool multiline_mode = false; List error_stack; bool pending_newline = false; + Token last_token; Token last_newline; int pending_indents = 0; List indent_stack; diff --git a/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.gd b/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.gd new file mode 100644 index 00000000000..cf7fb1518c7 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.gd @@ -0,0 +1,17 @@ +func test(): + print(-9223372036854775808 == (1 << 63)) + print(-2) + print(- 2) + print(---2) + print(3 - 2) + print(3-2) + print(3---2) + print(-3 - 2) + print(-3 - -2) + print(-(3 - 2)-2) + print([1, 2, 3][0]-1) + var t = 1 + print(t-1) + print(-0xFF) + print(1--0xFF) + print(floor(PI-1)) diff --git a/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out b/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out new file mode 100644 index 00000000000..c5958365ec7 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out @@ -0,0 +1,16 @@ +GDTEST_OK +true +-2 +-2 +-2 +1 +1 +1 +-5 +-1 +-3 +0 +0 +-255 +256 +2