diff options
author | 星外之神 <wszqkzqk@qq.com> | 2022-11-24 21:09:01 +0800 |
---|---|---|
committer | Rico Tzschichholz <ricotz@ubuntu.com> | 2022-12-08 15:37:31 +0100 |
commit | da406822256af058c246e48980e2c8f78f90353e (patch) | |
tree | 8c82e6d739aa4bae067f1dc5355941241e02a02d | |
parent | 865733142cad7f44f1c41a3e4bcd043048a3c756 (diff) | |
download | vala-da406822256af058c246e48980e2c8f78f90353e.tar.gz |
vala: Add support for binary/octal integer literal
-rw-r--r-- | tests/Makefile.am | 9 | ||||
-rw-r--r-- | tests/basic-types/integer-signed-binary-erange.test | 5 | ||||
-rw-r--r-- | tests/basic-types/integer-signed-erange2.test | 5 | ||||
-rw-r--r-- | tests/basic-types/integer-signed-octal-erange.test | 5 | ||||
-rw-r--r-- | tests/basic-types/integer-unsigned-binary-erange.test | 5 | ||||
-rw-r--r-- | tests/basic-types/integer-unsigned-octal-erange.test | 5 | ||||
-rw-r--r-- | tests/basic-types/integers-binary-invalid.test | 5 | ||||
-rw-r--r-- | tests/basic-types/integers-binary.c-expected | 40 | ||||
-rw-r--r-- | tests/basic-types/integers-binary.vala | 16 | ||||
-rw-r--r-- | tests/basic-types/integers-octal-invalid.test | 5 | ||||
-rw-r--r-- | tests/basic-types/integers-octal.c-expected | 40 | ||||
-rw-r--r-- | tests/basic-types/integers-octal.vala | 16 | ||||
-rw-r--r-- | tests/genie/literal-integer.c-expected | 12 | ||||
-rw-r--r-- | tests/genie/literal-integer.gs | 12 | ||||
-rw-r--r-- | vala/valageniescanner.vala | 82 | ||||
-rw-r--r-- | vala/valaintegerliteral.vala | 53 | ||||
-rw-r--r-- | vala/valascanner.vala | 32 |
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 |