summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author星外之神 <wszqkzqk@qq.com>2022-11-24 21:09:01 +0800
committerRico Tzschichholz <ricotz@ubuntu.com>2022-12-08 15:37:31 +0100
commitda406822256af058c246e48980e2c8f78f90353e (patch)
tree8c82e6d739aa4bae067f1dc5355941241e02a02d
parent865733142cad7f44f1c41a3e4bcd043048a3c756 (diff)
downloadvala-da406822256af058c246e48980e2c8f78f90353e.tar.gz
vala: Add support for binary/octal integer literal
-rw-r--r--tests/Makefile.am9
-rw-r--r--tests/basic-types/integer-signed-binary-erange.test5
-rw-r--r--tests/basic-types/integer-signed-erange2.test5
-rw-r--r--tests/basic-types/integer-signed-octal-erange.test5
-rw-r--r--tests/basic-types/integer-unsigned-binary-erange.test5
-rw-r--r--tests/basic-types/integer-unsigned-octal-erange.test5
-rw-r--r--tests/basic-types/integers-binary-invalid.test5
-rw-r--r--tests/basic-types/integers-binary.c-expected40
-rw-r--r--tests/basic-types/integers-binary.vala16
-rw-r--r--tests/basic-types/integers-octal-invalid.test5
-rw-r--r--tests/basic-types/integers-octal.c-expected40
-rw-r--r--tests/basic-types/integers-octal.vala16
-rw-r--r--tests/genie/literal-integer.c-expected12
-rw-r--r--tests/genie/literal-integer.gs12
-rw-r--r--vala/valageniescanner.vala82
-rw-r--r--vala/valaintegerliteral.vala53
-rw-r--r--vala/valascanner.vala32
17 files changed, 317 insertions, 30 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 458e56bd1..04029db88 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -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
index 000000000..1cf2021f0
--- /dev/null
+++ b/tests/basic-types/integer-signed-binary-erange.test
@@ -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
index 000000000..ac1d72e4a
--- /dev/null
+++ b/tests/basic-types/integer-signed-erange2.test
@@ -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
index 000000000..f76750771
--- /dev/null
+++ b/tests/basic-types/integer-signed-octal-erange.test
@@ -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
index 000000000..e04da67f8
--- /dev/null
+++ b/tests/basic-types/integer-unsigned-binary-erange.test
@@ -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
index 000000000..c0e1999d6
--- /dev/null
+++ b/tests/basic-types/integer-unsigned-octal-erange.test
@@ -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
index 000000000..89ed2c1d6
--- /dev/null
+++ b/tests/basic-types/integers-binary-invalid.test
@@ -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
index 000000000..9c03f1fb4
--- /dev/null
+++ b/tests/basic-types/integers-binary.c-expected
@@ -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
index 000000000..04529fb4c
--- /dev/null
+++ b/tests/basic-types/integers-binary.vala
@@ -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
index 000000000..f6c0a38f9
--- /dev/null
+++ b/tests/basic-types/integers-octal-invalid.test
@@ -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
index 000000000..f959f12a6
--- /dev/null
+++ b/tests/basic-types/integers-octal.c-expected
@@ -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
index 000000000..b75f6fc86
--- /dev/null
+++ b/tests/basic-types/integers-octal.vala
@@ -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);
+}
diff --git a/tests/genie/literal-integer.c-expected b/tests/genie/literal-integer.c-expected
index 1f9418103..7027e9d4d 100644
--- a/tests/genie/literal-integer.c-expected
+++ b/tests/genie/literal-integer.c-expected
@@ -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
diff --git a/tests/genie/literal-integer.gs b/tests/genie/literal-integer.gs
index eb1a20d0b..e29bf8082 100644
--- a/tests/genie/literal-integer.gs
+++ b/tests/genie/literal-integer.gs
@@ -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 )
diff --git a/vala/valageniescanner.vala b/vala/valageniescanner.vala
index 48088f3ee..da7199f93 100644
--- a/vala/valageniescanner.vala
+++ b/vala/valageniescanner.vala
@@ -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]) {
diff --git a/vala/valaintegerliteral.vala b/vala/valaintegerliteral.vala
index ec6146bc2..b84d54ea2 100644
--- a/vala/valaintegerliteral.vala
+++ b/vala/valaintegerliteral.vala
@@ -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;
diff --git a/vala/valascanner.vala b/vala/valascanner.vala
index 3c87115e1..f6f4cd7bf 100644
--- a/vala/valascanner.vala
+++ b/vala/valascanner.vala
@@ -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