authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-16 14:08:31-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-08-16 14:08:31-04:00
log9d85335de9f89213ed0c3f6a1ba4be1e02d186a1
tree9d51e53da3b95d9d5943357e521d5cd2d9a4986b
parent6e794938b810384323ce332cf0cf3e41ecc6c4a9
parent83909651ea99eb45c67ead40b5fcb5773d1998d5
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12427 from r00ster91/nicelexer

tokenizer: cleanups

1 files changed, 39 insertions(+), 43 deletions(-)

lib/std/zig/tokenizer.zig+39-43
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const mem = std.mem;
32
4pub const Token = struct {3pub const Token = struct {
5 tag: Tag,4 tag: Tag,
...@@ -350,7 +349,7 @@ pub const Tokenizer = struct {...@@ -350,7 +349,7 @@ pub const Tokenizer = struct {
350349
351 pub fn init(buffer: [:0]const u8) Tokenizer {350 pub fn init(buffer: [:0]const u8) Tokenizer {
352 // Skip the UTF-8 BOM if present351 // Skip the UTF-8 BOM if present
353 const src_start = if (mem.startsWith(u8, buffer, "\xEF\xBB\xBF")) 3 else @as(usize, 0);352 const src_start: usize = if (std.mem.startsWith(u8, buffer, "\xEF\xBB\xBF")) 3 else 0;
354 return Tokenizer{353 return Tokenizer{
355 .buffer = buffer,354 .buffer = buffer,
356 .index = src_start,355 .index = src_start,
...@@ -1433,8 +1432,8 @@ pub const Tokenizer = struct {...@@ -1433,8 +1432,8 @@ pub const Tokenizer = struct {
14331432
1434 fn getInvalidCharacterLength(self: *Tokenizer) u3 {1433 fn getInvalidCharacterLength(self: *Tokenizer) u3 {
1435 const c0 = self.buffer[self.index];1434 const c0 = self.buffer[self.index];
1436 if (c0 < 0x80) {1435 if (std.ascii.isASCII(c0)) {
1437 if (c0 < 0x20 or c0 == 0x7f) {1436 if (std.ascii.isCntrl(c0)) {
1438 // ascii control codes are never allowed1437 // ascii control codes are never allowed
1439 // (note that \n was checked before we got here)1438 // (note that \n was checked before we got here)
1440 return 1;1439 return 1;
...@@ -1469,8 +1468,8 @@ pub const Tokenizer = struct {...@@ -1469,8 +1468,8 @@ pub const Tokenizer = struct {
1469 }1468 }
1470};1469};
14711470
1472test "tokenizer" {1471test "keywords" {
1473 try testTokenize("test", &.{.keyword_test});1472 try testTokenize("test const else", &.{ .keyword_test, .keyword_const, .keyword_else });
1474}1473}
14751474
1476test "line comment followed by top-level comptime" {1475test "line comment followed by top-level comptime" {
...@@ -1485,7 +1484,7 @@ test "line comment followed by top-level comptime" {...@@ -1485,7 +1484,7 @@ test "line comment followed by top-level comptime" {
1485 });1484 });
1486}1485}
14871486
1488test "tokenizer - unknown length pointer and then c pointer" {1487test "unknown length pointer and then c pointer" {
1489 try testTokenize(1488 try testTokenize(
1490 \\[*]u81489 \\[*]u8
1491 \\[*c]u81490 \\[*c]u8
...@@ -1502,7 +1501,7 @@ test "tokenizer - unknown length pointer and then c pointer" {...@@ -1502,7 +1501,7 @@ test "tokenizer - unknown length pointer and then c pointer" {
1502 });1501 });
1503}1502}
15041503
1505test "tokenizer - code point literal with hex escape" {1504test "code point literal with hex escape" {
1506 try testTokenize(1505 try testTokenize(
1507 \\'\x1b'1506 \\'\x1b'
1508 , &.{.char_literal});1507 , &.{.char_literal});
...@@ -1511,21 +1510,21 @@ test "tokenizer - code point literal with hex escape" {...@@ -1511,21 +1510,21 @@ test "tokenizer - code point literal with hex escape" {
1511 , &.{ .invalid, .invalid });1510 , &.{ .invalid, .invalid });
1512}1511}
15131512
1514test "tokenizer - newline in char literal" {1513test "newline in char literal" {
1515 try testTokenize(1514 try testTokenize(
1516 \\'1515 \\'
1517 \\'1516 \\'
1518 , &.{ .invalid, .invalid });1517 , &.{ .invalid, .invalid });
1519}1518}
15201519
1521test "tokenizer - newline in string literal" {1520test "newline in string literal" {
1522 try testTokenize(1521 try testTokenize(
1523 \\"1522 \\"
1524 \\"1523 \\"
1525 , &.{ .invalid, .string_literal });1524 , &.{ .invalid, .string_literal });
1526}1525}
15271526
1528test "tokenizer - code point literal with unicode escapes" {1527test "code point literal with unicode escapes" {
1529 // Valid unicode escapes1528 // Valid unicode escapes
1530 try testTokenize(1529 try testTokenize(
1531 \\'\u{3}'1530 \\'\u{3}'
...@@ -1575,13 +1574,13 @@ test "tokenizer - code point literal with unicode escapes" {...@@ -1575,13 +1574,13 @@ test "tokenizer - code point literal with unicode escapes" {
1575 , &.{ .invalid, .integer_literal, .invalid });1574 , &.{ .invalid, .integer_literal, .invalid });
1576}1575}
15771576
1578test "tokenizer - code point literal with unicode code point" {1577test "code point literal with unicode code point" {
1579 try testTokenize(1578 try testTokenize(
1580 \\'💩'1579 \\'💩'
1581 , &.{.char_literal});1580 , &.{.char_literal});
1582}1581}
15831582
1584test "tokenizer - float literal e exponent" {1583test "float literal e exponent" {
1585 try testTokenize("a = 4.94065645841246544177e-324;\n", &.{1584 try testTokenize("a = 4.94065645841246544177e-324;\n", &.{
1586 .identifier,1585 .identifier,
1587 .equal,1586 .equal,
...@@ -1590,7 +1589,7 @@ test "tokenizer - float literal e exponent" {...@@ -1590,7 +1589,7 @@ test "tokenizer - float literal e exponent" {
1590 });1589 });
1591}1590}
15921591
1593test "tokenizer - float literal p exponent" {1592test "float literal p exponent" {
1594 try testTokenize("a = 0x1.a827999fcef32p+1022;\n", &.{1593 try testTokenize("a = 0x1.a827999fcef32p+1022;\n", &.{
1595 .identifier,1594 .identifier,
1596 .equal,1595 .equal,
...@@ -1599,11 +1598,11 @@ test "tokenizer - float literal p exponent" {...@@ -1599,11 +1598,11 @@ test "tokenizer - float literal p exponent" {
1599 });1598 });
1600}1599}
16011600
1602test "tokenizer - chars" {1601test "chars" {
1603 try testTokenize("'c'", &.{.char_literal});1602 try testTokenize("'c'", &.{.char_literal});
1604}1603}
16051604
1606test "tokenizer - invalid token characters" {1605test "invalid token characters" {
1607 try testTokenize("#", &.{.invalid});1606 try testTokenize("#", &.{.invalid});
1608 try testTokenize("`", &.{.invalid});1607 try testTokenize("`", &.{.invalid});
1609 try testTokenize("'c", &.{.invalid});1608 try testTokenize("'c", &.{.invalid});
...@@ -1611,7 +1610,7 @@ test "tokenizer - invalid token characters" {...@@ -1611,7 +1610,7 @@ test "tokenizer - invalid token characters" {
1611 try testTokenize("''", &.{ .invalid, .invalid });1610 try testTokenize("''", &.{ .invalid, .invalid });
1612}1611}
16131612
1614test "tokenizer - invalid literal/comment characters" {1613test "invalid literal/comment characters" {
1615 try testTokenize("\"\x00\"", &.{1614 try testTokenize("\"\x00\"", &.{
1616 .string_literal,1615 .string_literal,
1617 .invalid,1616 .invalid,
...@@ -1627,12 +1626,12 @@ test "tokenizer - invalid literal/comment characters" {...@@ -1627,12 +1626,12 @@ test "tokenizer - invalid literal/comment characters" {
1627 });1626 });
1628}1627}
16291628
1630test "tokenizer - utf8" {1629test "utf8" {
1631 try testTokenize("//\xc2\x80", &.{});1630 try testTokenize("//\xc2\x80", &.{});
1632 try testTokenize("//\xf4\x8f\xbf\xbf", &.{});1631 try testTokenize("//\xf4\x8f\xbf\xbf", &.{});
1633}1632}
16341633
1635test "tokenizer - invalid utf8" {1634test "invalid utf8" {
1636 try testTokenize("//\x80", &.{1635 try testTokenize("//\x80", &.{
1637 .invalid,1636 .invalid,
1638 });1637 });
...@@ -1659,7 +1658,7 @@ test "tokenizer - invalid utf8" {...@@ -1659,7 +1658,7 @@ test "tokenizer - invalid utf8" {
1659 });1658 });
1660}1659}
16611660
1662test "tokenizer - illegal unicode codepoints" {1661test "illegal unicode codepoints" {
1663 // unicode newline characters.U+0085, U+2028, U+20291662 // unicode newline characters.U+0085, U+2028, U+2029
1664 try testTokenize("//\xc2\x84", &.{});1663 try testTokenize("//\xc2\x84", &.{});
1665 try testTokenize("//\xc2\x85", &.{1664 try testTokenize("//\xc2\x85", &.{
...@@ -1676,7 +1675,7 @@ test "tokenizer - illegal unicode codepoints" {...@@ -1676,7 +1675,7 @@ test "tokenizer - illegal unicode codepoints" {
1676 try testTokenize("//\xe2\x80\xaa", &.{});1675 try testTokenize("//\xe2\x80\xaa", &.{});
1677}1676}
16781677
1679test "tokenizer - string identifier and builtin fns" {1678test "string identifier and builtin fns" {
1680 try testTokenize(1679 try testTokenize(
1681 \\const @"if" = @import("std");1680 \\const @"if" = @import("std");
1682 , &.{1681 , &.{
...@@ -1691,7 +1690,7 @@ test "tokenizer - string identifier and builtin fns" {...@@ -1691,7 +1690,7 @@ test "tokenizer - string identifier and builtin fns" {
1691 });1690 });
1692}1691}
16931692
1694test "tokenizer - multiline string literal with literal tab" {1693test "multiline string literal with literal tab" {
1695 try testTokenize(1694 try testTokenize(
1696 \\\\foo bar1695 \\\\foo bar
1697 , &.{1696 , &.{
...@@ -1699,7 +1698,7 @@ test "tokenizer - multiline string literal with literal tab" {...@@ -1699,7 +1698,7 @@ test "tokenizer - multiline string literal with literal tab" {
1699 });1698 });
1700}1699}
17011700
1702test "tokenizer - comments with literal tab" {1701test "comments with literal tab" {
1703 try testTokenize(1702 try testTokenize(
1704 \\//foo bar1703 \\//foo bar
1705 \\//!foo bar1704 \\//!foo bar
...@@ -1715,14 +1714,14 @@ test "tokenizer - comments with literal tab" {...@@ -1715,14 +1714,14 @@ test "tokenizer - comments with literal tab" {
1715 });1714 });
1716}1715}
17171716
1718test "tokenizer - pipe and then invalid" {1717test "pipe and then invalid" {
1719 try testTokenize("||=", &.{1718 try testTokenize("||=", &.{
1720 .pipe_pipe,1719 .pipe_pipe,
1721 .equal,1720 .equal,
1722 });1721 });
1723}1722}
17241723
1725test "tokenizer - line comment and doc comment" {1724test "line comment and doc comment" {
1726 try testTokenize("//", &.{});1725 try testTokenize("//", &.{});
1727 try testTokenize("// a / b", &.{});1726 try testTokenize("// a / b", &.{});
1728 try testTokenize("// /", &.{});1727 try testTokenize("// /", &.{});
...@@ -1733,7 +1732,7 @@ test "tokenizer - line comment and doc comment" {...@@ -1733,7 +1732,7 @@ test "tokenizer - line comment and doc comment" {
1733 try testTokenize("//!!", &.{.container_doc_comment});1732 try testTokenize("//!!", &.{.container_doc_comment});
1734}1733}
17351734
1736test "tokenizer - line comment followed by identifier" {1735test "line comment followed by identifier" {
1737 try testTokenize(1736 try testTokenize(
1738 \\ Unexpected,1737 \\ Unexpected,
1739 \\ // another1738 \\ // another
...@@ -1746,7 +1745,7 @@ test "tokenizer - line comment followed by identifier" {...@@ -1746,7 +1745,7 @@ test "tokenizer - line comment followed by identifier" {
1746 });1745 });
1747}1746}
17481747
1749test "tokenizer - UTF-8 BOM is recognized and skipped" {1748test "UTF-8 BOM is recognized and skipped" {
1750 try testTokenize("\xEF\xBB\xBFa;\n", &.{1749 try testTokenize("\xEF\xBB\xBFa;\n", &.{
1751 .identifier,1750 .identifier,
1752 .semicolon,1751 .semicolon,
...@@ -1788,7 +1787,7 @@ test "correctly parse pointer dereference followed by asterisk" {...@@ -1788,7 +1787,7 @@ test "correctly parse pointer dereference followed by asterisk" {
1788 });1787 });
1789}1788}
17901789
1791test "tokenizer - range literals" {1790test "range literals" {
1792 try testTokenize("0...9", &.{ .integer_literal, .ellipsis3, .integer_literal });1791 try testTokenize("0...9", &.{ .integer_literal, .ellipsis3, .integer_literal });
1793 try testTokenize("'0'...'9'", &.{ .char_literal, .ellipsis3, .char_literal });1792 try testTokenize("'0'...'9'", &.{ .char_literal, .ellipsis3, .char_literal });
1794 try testTokenize("0x00...0x09", &.{ .integer_literal, .ellipsis3, .integer_literal });1793 try testTokenize("0x00...0x09", &.{ .integer_literal, .ellipsis3, .integer_literal });
...@@ -1796,7 +1795,7 @@ test "tokenizer - range literals" {...@@ -1796,7 +1795,7 @@ test "tokenizer - range literals" {
1796 try testTokenize("0o00...0o11", &.{ .integer_literal, .ellipsis3, .integer_literal });1795 try testTokenize("0o00...0o11", &.{ .integer_literal, .ellipsis3, .integer_literal });
1797}1796}
17981797
1799test "tokenizer - number literals decimal" {1798test "number literals decimal" {
1800 try testTokenize("0", &.{.integer_literal});1799 try testTokenize("0", &.{.integer_literal});
1801 try testTokenize("1", &.{.integer_literal});1800 try testTokenize("1", &.{.integer_literal});
1802 try testTokenize("2", &.{.integer_literal});1801 try testTokenize("2", &.{.integer_literal});
...@@ -1863,7 +1862,7 @@ test "tokenizer - number literals decimal" {...@@ -1863,7 +1862,7 @@ test "tokenizer - number literals decimal" {
1863 try testTokenize("1.0e0_+", &.{ .invalid, .plus });1862 try testTokenize("1.0e0_+", &.{ .invalid, .plus });
1864}1863}
18651864
1866test "tokenizer - number literals binary" {1865test "number literals binary" {
1867 try testTokenize("0b0", &.{.integer_literal});1866 try testTokenize("0b0", &.{.integer_literal});
1868 try testTokenize("0b1", &.{.integer_literal});1867 try testTokenize("0b1", &.{.integer_literal});
1869 try testTokenize("0b2", &.{ .invalid, .integer_literal });1868 try testTokenize("0b2", &.{ .invalid, .integer_literal });
...@@ -1902,7 +1901,7 @@ test "tokenizer - number literals binary" {...@@ -1902,7 +1901,7 @@ test "tokenizer - number literals binary" {
1902 try testTokenize("0b1_,", &.{ .invalid, .comma });1901 try testTokenize("0b1_,", &.{ .invalid, .comma });
1903}1902}
19041903
1905test "tokenizer - number literals octal" {1904test "number literals octal" {
1906 try testTokenize("0o0", &.{.integer_literal});1905 try testTokenize("0o0", &.{.integer_literal});
1907 try testTokenize("0o1", &.{.integer_literal});1906 try testTokenize("0o1", &.{.integer_literal});
1908 try testTokenize("0o2", &.{.integer_literal});1907 try testTokenize("0o2", &.{.integer_literal});
...@@ -1941,7 +1940,7 @@ test "tokenizer - number literals octal" {...@@ -1941,7 +1940,7 @@ test "tokenizer - number literals octal" {
1941 try testTokenize("0o_,", &.{ .invalid, .identifier, .comma });1940 try testTokenize("0o_,", &.{ .invalid, .identifier, .comma });
1942}1941}
19431942
1944test "tokenizer - number literals hexadecimal" {1943test "number literals hexadecimal" {
1945 try testTokenize("0x0", &.{.integer_literal});1944 try testTokenize("0x0", &.{.integer_literal});
1946 try testTokenize("0x1", &.{.integer_literal});1945 try testTokenize("0x1", &.{.integer_literal});
1947 try testTokenize("0x2", &.{.integer_literal});1946 try testTokenize("0x2", &.{.integer_literal});
...@@ -2029,22 +2028,22 @@ test "tokenizer - number literals hexadecimal" {...@@ -2029,22 +2028,22 @@ test "tokenizer - number literals hexadecimal" {
2029 try testTokenize("0x0.0p0_", &.{ .invalid, .eof });2028 try testTokenize("0x0.0p0_", &.{ .invalid, .eof });
2030}2029}
20312030
2032test "tokenizer - multi line string literal with only 1 backslash" {2031test "multi line string literal with only 1 backslash" {
2033 try testTokenize("x \\\n;", &.{ .identifier, .invalid, .semicolon });2032 try testTokenize("x \\\n;", &.{ .identifier, .invalid, .semicolon });
2034}2033}
20352034
2036test "tokenizer - invalid builtin identifiers" {2035test "invalid builtin identifiers" {
2037 try testTokenize("@()", &.{ .invalid, .l_paren, .r_paren });2036 try testTokenize("@()", &.{ .invalid, .l_paren, .r_paren });
2038 try testTokenize("@0()", &.{ .invalid, .integer_literal, .l_paren, .r_paren });2037 try testTokenize("@0()", &.{ .invalid, .integer_literal, .l_paren, .r_paren });
2039}2038}
20402039
2041test "tokenizer - invalid token with unfinished escape right before eof" {2040test "invalid token with unfinished escape right before eof" {
2042 try testTokenize("\"\\", &.{.invalid});2041 try testTokenize("\"\\", &.{.invalid});
2043 try testTokenize("'\\", &.{.invalid});2042 try testTokenize("'\\", &.{.invalid});
2044 try testTokenize("'\\u", &.{.invalid});2043 try testTokenize("'\\u", &.{.invalid});
2045}2044}
20462045
2047test "tokenizer - saturating" {2046test "saturating operators" {
2048 try testTokenize("<<", &.{.angle_bracket_angle_bracket_left});2047 try testTokenize("<<", &.{.angle_bracket_angle_bracket_left});
2049 try testTokenize("<<|", &.{.angle_bracket_angle_bracket_left_pipe});2048 try testTokenize("<<|", &.{.angle_bracket_angle_bracket_left_pipe});
2050 try testTokenize("<<|=", &.{.angle_bracket_angle_bracket_left_pipe_equal});2049 try testTokenize("<<|=", &.{.angle_bracket_angle_bracket_left_pipe_equal});
...@@ -2062,17 +2061,14 @@ test "tokenizer - saturating" {...@@ -2062,17 +2061,14 @@ test "tokenizer - saturating" {
2062 try testTokenize("-|=", &.{.minus_pipe_equal});2061 try testTokenize("-|=", &.{.minus_pipe_equal});
2063}2062}
20642063
2065fn testTokenize(source: [:0]const u8, expected_tokens: []const Token.Tag) !void {2064fn testTokenize(source: [:0]const u8, expected_token_tags: []const Token.Tag) !void {
2066 var tokenizer = Tokenizer.init(source);2065 var tokenizer = Tokenizer.init(source);
2067 for (expected_tokens) |expected_token_id| {2066 for (expected_token_tags) |expected_token_tag| {
2068 const token = tokenizer.next();2067 const token = tokenizer.next();
2069 if (token.tag != expected_token_id) {2068 try std.testing.expectEqual(expected_token_tag, token.tag);
2070 std.debug.panic("expected {s}, found {s}\n", .{
2071 @tagName(expected_token_id), @tagName(token.tag),
2072 });
2073 }
2074 }2069 }
2075 const last_token = tokenizer.next();2070 const last_token = tokenizer.next();
2076 try std.testing.expectEqual(Token.Tag.eof, last_token.tag);2071 try std.testing.expectEqual(Token.Tag.eof, last_token.tag);
2077 try std.testing.expectEqual(source.len, last_token.loc.start);2072 try std.testing.expectEqual(source.len, last_token.loc.start);
2073 try std.testing.expectEqual(source.len, last_token.loc.end);
2078}2074}