]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
vala: Add support for binary/octal integer literal
author星外之神 <wszqkzqk@qq.com>
Thu, 24 Nov 2022 13:09:01 +0000 (21:09 +0800)
committerRico Tzschichholz <ricotz@ubuntu.com>
Thu, 8 Dec 2022 14:37:31 +0000 (15:37 +0100)
17 files changed:
tests/Makefile.am
tests/basic-types/integer-signed-binary-erange.test [new file with mode: 0644]
tests/basic-types/integer-signed-erange2.test [new file with mode: 0644]
tests/basic-types/integer-signed-octal-erange.test [new file with mode: 0644]
tests/basic-types/integer-unsigned-binary-erange.test [new file with mode: 0644]
tests/basic-types/integer-unsigned-octal-erange.test [new file with mode: 0644]
tests/basic-types/integers-binary-invalid.test [new file with mode: 0644]
tests/basic-types/integers-binary.c-expected [new file with mode: 0644]
tests/basic-types/integers-binary.vala [new file with mode: 0644]
tests/basic-types/integers-octal-invalid.test [new file with mode: 0644]
tests/basic-types/integers-octal.c-expected [new file with mode: 0644]
tests/basic-types/integers-octal.vala [new file with mode: 0644]
tests/genie/literal-integer.c-expected
tests/genie/literal-integer.gs
vala/valageniescanner.vala
vala/valaintegerliteral.vala
vala/valascanner.vala

index 458e56bd17df14927a5b55c4a152ae2a5de8e87d..04029db88219b499b6c33e794fa280285638cc20 100644 (file)
@@ -42,11 +42,20 @@ AM_TESTS_ENVIRONMENT = \
 TESTS = \
        basic-types/gassert.vala \
        basic-types/integer-literals.vala \
+       basic-types/integer-signed-binary-erange.test \
        basic-types/integer-signed-erange.test \
+       basic-types/integer-signed-erange2.test \
+       basic-types/integer-signed-octal-erange.test \
+       basic-types/integer-unsigned-binary-erange.test \
        basic-types/integer-unsigned-erange.test \
        basic-types/integer-unsigned-invalid.test \
+       basic-types/integer-unsigned-octal-erange.test \
+       basic-types/integers-binary-invalid.test \
+       basic-types/integers-binary.vala \
        basic-types/integers.vala \
        basic-types/integers-boxed-cast.vala \
+       basic-types/integers-octal-invalid.test \
+       basic-types/integers-octal.vala \
        basic-types/escape-chars.vala \
        basic-types/float-literals.vala \
        basic-types/floats.vala \
diff --git a/tests/basic-types/integer-signed-binary-erange.test b/tests/basic-types/integer-signed-binary-erange.test
new file mode 100644 (file)
index 0000000..1cf2021
--- /dev/null
@@ -0,0 +1,5 @@
+Invalid Code
+
+void main () {
+       int64 foo = -0b1111111111111111111111111111111111111111111111111111111111111111;
+}
diff --git a/tests/basic-types/integer-signed-erange2.test b/tests/basic-types/integer-signed-erange2.test
new file mode 100644 (file)
index 0000000..ac1d72e
--- /dev/null
@@ -0,0 +1,5 @@
+Invalid Code
+
+void main () {
+       int64 foo = 9223372036854775808;
+}
diff --git a/tests/basic-types/integer-signed-octal-erange.test b/tests/basic-types/integer-signed-octal-erange.test
new file mode 100644 (file)
index 0000000..f767507
--- /dev/null
@@ -0,0 +1,5 @@
+Invalid Code
+
+void main () {
+       int64 foo = 0o1000000000000000000000;
+}
diff --git a/tests/basic-types/integer-unsigned-binary-erange.test b/tests/basic-types/integer-unsigned-binary-erange.test
new file mode 100644 (file)
index 0000000..e04da67
--- /dev/null
@@ -0,0 +1,5 @@
+Invalid Code
+
+void main () {
+       var foo = 0b111111111111111111111111111111111111111111111111111111111111111111;
+}
diff --git a/tests/basic-types/integer-unsigned-octal-erange.test b/tests/basic-types/integer-unsigned-octal-erange.test
new file mode 100644 (file)
index 0000000..c0e1999
--- /dev/null
@@ -0,0 +1,5 @@
+Invalid Code
+
+void main () {
+       var foo = 0o7777777777777777777777;
+}
diff --git a/tests/basic-types/integers-binary-invalid.test b/tests/basic-types/integers-binary-invalid.test
new file mode 100644 (file)
index 0000000..89ed2c1
--- /dev/null
@@ -0,0 +1,5 @@
+Invalid Code
+
+void main () {
+       var foo = 0b123;
+}
diff --git a/tests/basic-types/integers-binary.c-expected b/tests/basic-types/integers-binary.c-expected
new file mode 100644 (file)
index 0000000..9c03f1f
--- /dev/null
@@ -0,0 +1,40 @@
+/* basic_types_integers_binary.c generated by valac, the Vala compiler
+ * generated from basic_types_integers_binary.vala, do not modify */
+
+#include <glib.h>
+
+#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
+#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
+#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+
+static void _vala_main (void);
+
+static void
+_vala_main (void)
+{
+       gint a = 0;
+       guint b = 0U;
+       gint c = 0;
+       guint64 d = 0ULL;
+       gint64 e = 0LL;
+       a = 9;
+       _vala_assert (a == 9, "a == 9");
+       b = 314U;
+       _vala_assert (b == ((guint) 314), "b == 314");
+       c = -666;
+       _vala_assert (c == -666, "c == -666");
+       d = 18446744073709551615ULL;
+       _vala_assert (d == 0xffffffffffffffffULL, "d == 0xffffffffffffffff");
+       e = 3740122863LL;
+       _vala_assert (e == 0xdeedbeefLL, "e == 0xdeedbeef");
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
diff --git a/tests/basic-types/integers-binary.vala b/tests/basic-types/integers-binary.vala
new file mode 100644 (file)
index 0000000..04529fb
--- /dev/null
@@ -0,0 +1,16 @@
+void main () {
+       var a = 0b1001;
+       assert (a == 9);
+
+       var b = 0b100111010u;
+       assert (b == 314);
+
+       var c = -0b1010011010;
+       assert (c == -666);
+
+       uint64 d = 0b1111111111111111111111111111111111111111111111111111111111111111;
+       assert (d == 0xffffffffffffffff);
+
+       int64 e = 0b11011110111011011011111011101111;
+       assert (e == 0xdeedbeef);
+}
diff --git a/tests/basic-types/integers-octal-invalid.test b/tests/basic-types/integers-octal-invalid.test
new file mode 100644 (file)
index 0000000..f6c0a38
--- /dev/null
@@ -0,0 +1,5 @@
+Invalid Code
+
+void main () {
+       var foo = 0o987;
+}
diff --git a/tests/basic-types/integers-octal.c-expected b/tests/basic-types/integers-octal.c-expected
new file mode 100644 (file)
index 0000000..f959f12
--- /dev/null
@@ -0,0 +1,40 @@
+/* basic_types_integers_octal.c generated by valac, the Vala compiler
+ * generated from basic_types_integers_octal.vala, do not modify */
+
+#include <glib.h>
+
+#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
+#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
+#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+
+static void _vala_main (void);
+
+static void
+_vala_main (void)
+{
+       gint a = 0;
+       guint b = 0U;
+       gint c = 0;
+       guint64 d = 0ULL;
+       gint64 e = 0LL;
+       a = 0644;
+       _vala_assert (a == 420, "a == 420");
+       b = 0105264631U;
+       _vala_assert (b == 18180505U, "b == 18180505u");
+       c = -01322;
+       _vala_assert (c == -722, "c == -722");
+       d = 01777777777777777777777ULL;
+       _vala_assert (d == 0xffffffffffffffffULL, "d == 0xffffffffffffffff");
+       e = -033653337357LL;
+       _vala_assert (e == -0xdeadbeefLL, "e == -0xdeadbeef");
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
diff --git a/tests/basic-types/integers-octal.vala b/tests/basic-types/integers-octal.vala
new file mode 100644 (file)
index 0000000..b75f6fc
--- /dev/null
@@ -0,0 +1,16 @@
+void main () {
+       var a = 0o644;
+       assert (a == 420);
+
+       var b = 0o105264631u;
+       assert (b == 18180505u);
+
+       var c = -0o1322;
+       assert (c == -722);
+
+       var d = 0o1777777777777777777777ll;
+       assert (d == 0xffffffffffffffff);
+
+       var e = -0o33653337357;
+       assert (e == -0xdeadbeef);
+}
index 1f94181037ab13d62e67d41f3351d8a44d9cd31f..7027e9d4dfa8e3a15a33566d497f0c16f899cc58 100644 (file)
@@ -18,8 +18,20 @@ _vala_main (gchar** args,
             gint args_length1)
 {
        gint a = 0;
+       gint64 b = 0LL;
+       gint64 c = 0LL;
+       guint d = 0U;
+       gint e = 0;
        a = 101;
        _vala_assert (a == 101, "a == 101");
+       b = 0xdeadbeefLL;
+       _vala_assert (b == 3735928559LL, "b == 3735928559");
+       c = 2003LL;
+       _vala_assert (c == 2003LL, "c == 2003ll");
+       d = 01307U;
+       _vala_assert (d == 711U, "d == 711u");
+       e = -0110157032;
+       _vala_assert (e == (-18931226), "e == -18931226");
 }
 
 int
index eb1a20d0b6877ceaef3e88bdd8a0f1e3c0d0c516..e29bf808205a0c2c8e87f84df5c54518798da43c 100644 (file)
@@ -1,3 +1,15 @@
 init
        a:int = 101
        assert( a == 101 )
+
+       b:int64 = 0xdeadbeef
+       assert( b == 3735928559 )
+
+       var c = 0b11111010011ll
+       assert( c == 2003ll )
+
+       var d = 0o1307u
+       assert( d == 711u )
+
+       var e = -0o110157032
+       assert( e == -18931226 )
index 48088f3ee1c38d81b6f83d910f0d0f57ebdc6e5f..da7199f9357fd220d4a4465cffea37a9e7a1983a 100644 (file)
@@ -1003,20 +1003,7 @@ public class Vala.Genie.Scanner {
                                current++;
                        }
                        type = TokenType.INTEGER_LITERAL;
-                       if (current < end && current[0].tolower () == 'l') {
-                               current++;
-                               if (current < end && current[0].tolower () == 'l') {
-                                       current++;
-                               }
-                       } else if (current < end && current[0].tolower () == 'u') {
-                               current++;
-                               if (current < end && current[0].tolower () == 'l') {
-                                       current++;
-                                       if (current < end && current[0].tolower () == 'l') {
-                                               current++;
-                                       }
-                               }
-                       } else if (current < end - 1 && current[0] == '.' && current[1].isdigit ()) {
+                       if (current < end - 1 && current[0] == '.' && current[1].isdigit ()) {
                                current++;
                                while (current < end && current[0].isdigit ()) {
                                        current++;
@@ -1030,24 +1017,77 @@ public class Vala.Genie.Scanner {
                                                current++;
                                        }
                                }
-                               if (current < end && current[0].tolower () == 'f') {
+                               type = TokenType.REAL_LITERAL;
+                       } else if (current < end && current[0].tolower () == 'e') {
+                               current++;
+                               if (current < end && (current[0] == '+' || current[0] == '-')) {
+                                       current++;
+                               }
+                               while (current < end && current[0].isdigit ()) {
                                        current++;
                                }
                                type = TokenType.REAL_LITERAL;
                        } else if (current < end && current == begin + 1
-                                          && begin[0] == '0' && begin[1] == 'x' && begin[2].isxdigit ()) {
+                                          && begin[0] == '0'
+                                          && (begin[1] == 'x' || begin[1] == 'X')
+                                          && begin[2].isxdigit ()) {
                                // hexadecimal integer literal
                                current++;
                                while (current < end && current[0].isxdigit ()) {
                                        current++;
                                }
-                       } else if (current < end && is_ident_char (current[0])) {
-                               // allow identifiers to start with a digit
-                               // as long as they contain at least one char
-                               while (current < end && is_ident_char (current[0])) {
+                       } else if (current < end && current == begin + 1
+                                          && begin[0] == '0'
+                                          && (begin[1] == 'b' || begin[1] == 'B' || begin[1] == 'o' || begin[1] == 'O')
+                                          && begin[2].isdigit ()) {
+                               // binary or octal integer literal
+                               current++;
+                               while (current < end && current[0].isdigit ()) {
                                        current++;
                                }
-                               type = TokenType.IDENTIFIER;
+                       }
+                       if (current < end) {
+                               bool real_literal = (type == TokenType.REAL_LITERAL);
+
+                               switch (current[0]) {
+                               case 'l':
+                               case 'L':
+                                       if (type == TokenType.INTEGER_LITERAL) {
+                                               current++;
+                                               if (current < end && current[0].tolower () == 'l') {
+                                                       current++;
+                                               }
+                                       }
+                                       break;
+                               case 'u':
+                               case 'U':
+                                       if (type == TokenType.INTEGER_LITERAL) {
+                                               current++;
+                                               if (current < end && current[0].tolower () == 'l') {
+                                                       current++;
+                                                       if (current < end && current[0].tolower () == 'l') {
+                                                               current++;
+                                                       }
+                                               }
+                                       }
+                                       break;
+                               case 'f':
+                               case 'F':
+                               case 'd':
+                               case 'D':
+                                       type = TokenType.REAL_LITERAL;
+                                       current++;
+                                       break;
+                               }
+
+                               if (!real_literal && is_ident_char (current[0])) {
+                                       // allow identifiers to start with a digit
+                                       // as long as they contain at least one char
+                                       while (current < end && is_ident_char (current[0])) {
+                                               current++;
+                                       }
+                                       type = TokenType.IDENTIFIER;
+                               }
                        }
                } else {
                        switch (current[0]) {
index ec6146bc27295411568d38bb81ef1b2a2352949a..b84d54ea2f156436904625130672db24732831e7 100644 (file)
@@ -88,11 +88,58 @@ public class Vala.IntegerLiteral : Literal {
                uint64 un = 0ULL;
 
                errno = 0;
-               if (negative) {
-                       n = int64.parse (value);
+               if (value.has_prefix ("0b") || value.has_prefix ("0B")
+                   || value.has_prefix ("-0b") || value.has_prefix ("-0B")) {
+                       string v;
+                       if (negative) {
+                               v = "-" + value.substring (3);
+                       } else {
+                               v = value.substring (2);
+                       }
+                       string unparsed;
+                       if (negative) {
+                               int64.try_parse (v, out n, out unparsed, 2);
+                               value = n.to_string ();
+                       } else {
+                               uint64.try_parse (v, out un, out unparsed, 2);
+                               value = un.to_string ();
+                       }
+                       if (unparsed != "") {
+                               Report.error (source_reference, "invalid digit '%c' in binary literal", unparsed[0]);
+                               error = true;
+                       }
+               } else if ((value[0] == '0' && value.length > 1
+                   && (value[1] == 'o' || value[1] == 'O' || value[1].isdigit ()))
+                   || (value.has_prefix ("-0") && value.length > 3
+                   && (value[2] == 'o' || value[2] == 'O' || value[2].isdigit ()))) {
+                       if (negative) {
+                               if (!value[2].isdigit ()) {
+                                       value = "-0" + value.substring (3);
+                               }
+                       } else {
+                               if (!value[1].isdigit ()) {
+                                       value = "0" + value.substring (2);
+                               }
+                       }
+                       string unparsed;
+                       if (negative) {
+                               int64.try_parse (value, out n, out unparsed, 8);
+                       } else {
+                               uint64.try_parse (value, out un, out unparsed, 8);
+                       }
+                       if (unparsed != "") {
+                               Report.error (source_reference, "invalid digit '%c' in octal literal", unparsed[0]);
+                               error = true;
+                       }
                } else {
-                       un = uint64.parse (value);
+                       // hexademical and decimal literal
+                       if (negative) {
+                               n = int64.parse (value);
+                       } else {
+                               un = uint64.parse (value);
+                       }
                }
+
                if (errno == ERANGE) {
                        Report.error (source_reference, "integer literal is too large for its type");
                        error = true;
index 3c87115e17ae63ab6d13f6b64446b773773a5f9b..f6f4cd7bfc705b3978d823e462f6183f868c1660 100644 (file)
@@ -607,12 +607,32 @@ public class Vala.Scanner {
                var type = TokenType.INTEGER_LITERAL;
 
                // integer part
-               if (current < end - 2 && current[0] == '0'
-                   && current[1] == 'x' && current[2].isxdigit ()) {
-                       // hexadecimal integer literal
-                       current += 2;
-                       while (current < end && current[0].isxdigit ()) {
-                               current++;
+               if (current < end - 2 && current[0] == '0') {
+                       switch (current[1]) {
+                       case 'x':
+                       case 'X':
+                               // hexadecimal integer literal
+                               current += 2;
+                               while (current < end && current[0].isxdigit ()) {
+                                       current++;
+                               }
+                               break;
+                       case 'b':
+                       case 'B':
+                       case 'o':
+                       case 'O':
+                               // binary integer literal or octal integer literal
+                               current += 2;
+                               while (current < end && current[0].isdigit ()) {
+                                       current++;
+                               }
+                               break;
+                       default:
+                               // decimal number (also may be octal integer)
+                               while (current < end && current[0].isdigit ()) {
+                                       current++;
+                               }
+                               break;
                        }
                } else {
                        // decimal number