Przeglądaj źródła

Merge pull request #73363 from dalexeev/gds-fix-min-int-not-representable

GDScript: Fix `MIN_INT` not representable as numeric literal
Rémi Verschelde 2 lat temu
rodzic
commit
1ce2425c0e

+ 31 - 0
modules/gdscript/gdscript_tokenizer.cpp

@@ -163,6 +163,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.
@@ -383,6 +401,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::make_token(Token::Type p_type) {
 		}
 	}
 
+	last_token = token;
 	return token;
 }
 
@@ -628,6 +647,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;
 	}
 
@@ -644,6 +664,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') {
@@ -1463,6 +1488,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);
 			}
@@ -1470,6 +1498,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);

+ 2 - 0
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<Token> error_stack;
 	bool pending_newline = false;
+	Token last_token;
 	Token last_newline;
 	int pending_indents = 0;
 	List<int> indent_stack;

+ 17 - 0
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))

+ 16 - 0
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