Parcourir la source

Merge pull request #28416 from JellyWX/binary-literals

Support for binary literals in GDScript
Rémi Verschelde il y a 6 ans
Parent
commit
36591b1ae8

+ 39 - 0
core/ustring.cpp

@@ -1725,6 +1725,45 @@ int64_t String::hex_to_int64(bool p_with_prefix) const {
 	return hex * sign;
 }
 
+int64_t String::bin_to_int64(bool p_with_prefix) const {
+
+	if (p_with_prefix && length() < 3)
+		return 0;
+
+	const CharType *s = ptr();
+
+	int64_t sign = s[0] == '-' ? -1 : 1;
+
+	if (sign < 0) {
+		s++;
+	}
+
+	if (p_with_prefix) {
+		if (s[0] != '0' || s[1] != 'b')
+			return 0;
+		s += 2;
+	}
+
+	int64_t binary = 0;
+
+	while (*s) {
+
+		CharType c = LOWERCASE(*s);
+		int64_t n;
+		if (c == '0' || c == '1') {
+			n = c - '0';
+		} else {
+			return 0;
+		}
+
+		binary *= 2;
+		binary += n;
+		s++;
+	}
+
+	return binary * sign;
+}
+
 int String::to_int() const {
 
 	if (length() == 0)

+ 1 - 0
core/ustring.h

@@ -251,6 +251,7 @@ public:
 	int to_int() const;
 
 	int64_t hex_to_int64(bool p_with_prefix = true) const;
+	int64_t bin_to_int64(bool p_with_prefix = true) const;
 	int64_t to_int64() const;
 	static int to_int(const char *p_str, int p_len = -1);
 	static double to_double(const char *p_str);

+ 18 - 1
modules/gdscript/editor/gdscript_highlighter.cpp

@@ -56,6 +56,10 @@ static bool _is_hex_symbol(CharType c) {
 	return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
 }
 
+static bool _is_bin_symbol(CharType c) {
+	return (c == '0' || c == '1');
+}
+
 Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) {
 	Map<int, TextEdit::HighlighterInfo> color_map;
 
@@ -76,6 +80,7 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
 	bool in_member_variable = false;
 	bool in_node_path = false;
 	bool is_hex_notation = false;
+	bool is_bin_notation = false;
 	bool expect_type = false;
 	Color keyword_color;
 	Color color;
@@ -118,14 +123,26 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
 			is_hex_notation = false;
 		}
 
+		// disallow anything not a 0 or 1
+		if (is_bin_notation && (_is_bin_symbol(str[j]))) {
+			is_number = true;
+		} else if (is_bin_notation) {
+			is_bin_notation = false;
+			is_number = false;
+		} else {
+			is_bin_notation = false;
+		}
+
 		// check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation
-		if ((str[j] == '.' || str[j] == 'x' || str[j] == '_' || str[j] == 'e') && !in_word && prev_is_number && !is_number) {
+		if ((str[j] == '.' || str[j] == 'x' || str[j] == 'b' || str[j] == '_' || str[j] == 'e') && !in_word && prev_is_number && !is_number) {
 			is_number = true;
 			is_symbol = false;
 			is_char = false;
 
 			if (str[j] == 'x' && str[j - 1] == '0') {
 				is_hex_notation = true;
+			} else if (str[j] == 'b' && str[j - 1] == '0') {
+				is_bin_notation = true;
 			}
 		}
 

+ 25 - 2
modules/gdscript/gdscript_tokenizer.cpp

@@ -376,6 +376,11 @@ static bool _is_hex(CharType c) {
 	return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
 }
 
+static bool _is_bin(CharType c) {
+
+	return (c == '0' || c == '1');
+}
+
 void GDScriptTokenizerText::_make_token(Token p_type) {
 
 	TokenData &tk = tk_rb[tk_rb_pos];
@@ -877,6 +882,7 @@ void GDScriptTokenizerText::_advance() {
 					bool period_found = false;
 					bool exponent_found = false;
 					bool hexa_found = false;
+					bool bin_found = false;
 					bool sign_found = false;
 
 					String str;
@@ -887,16 +893,28 @@ void GDScriptTokenizerText::_advance() {
 							if (period_found || exponent_found) {
 								_make_error("Invalid numeric constant at '.'");
 								return;
+							} else if (bin_found) {
+								_make_error("Invalid binary constant at '.'");
+								return;
+							} else if (hexa_found) {
+								_make_error("Invalid hexadecimal constant at '.'");
+								return;
 							}
 							period_found = true;
 						} else if (GETCHAR(i) == 'x') {
-							if (hexa_found || str.length() != 1 || !((i == 1 && str[0] == '0') || (i == 2 && str[1] == '0' && str[0] == '-'))) {
+							if (hexa_found || bin_found || str.length() != 1 || !((i == 1 && str[0] == '0') || (i == 2 && str[1] == '0' && str[0] == '-'))) {
 								_make_error("Invalid numeric constant at 'x'");
 								return;
 							}
 							hexa_found = true;
+						} else if (GETCHAR(i) == 'b') {
+							if (hexa_found || bin_found || str.length() != 1 || !((i == 1 && str[0] == '0') || (i == 2 && str[1] == '0' && str[0] == '-'))) {
+								_make_error("Invalid numeric constant at 'b'");
+								return;
+							}
+							bin_found = true;
 						} else if (!hexa_found && GETCHAR(i) == 'e') {
-							if (exponent_found) {
+							if (exponent_found || bin_found) {
 								_make_error("Invalid numeric constant at 'e'");
 								return;
 							}
@@ -905,6 +923,8 @@ void GDScriptTokenizerText::_advance() {
 							//all ok
 						} else if (hexa_found && _is_hex(GETCHAR(i))) {
 
+						} else if (bin_found && _is_bin(GETCHAR(i))) {
+
 						} else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) {
 							if (sign_found) {
 								_make_error("Invalid numeric constant at '-'");
@@ -930,6 +950,9 @@ void GDScriptTokenizerText::_advance() {
 					if (hexa_found) {
 						int64_t val = str.hex_to_int64();
 						_make_constant(val);
+					} else if (bin_found) {
+						int64_t val = str.bin_to_int64();
+						_make_constant(val);
 					} else if (period_found || exponent_found) {
 						double val = str.to_double();
 						_make_constant(val);