authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-31 13:36:48+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-13 20:26:04-04:00
log349d78a443c8a844c5050cd3122b539f8c95598b
tree41306af5f934d64f7e06c39b37d7424198829d0d
parent716d9237cb757c15217b21964fde8e755aabe853

validate number literals in AstGen


34 files changed, 599 insertions(+), 659 deletions(-)

doc/docgen.zig+1-3
...@@ -1057,9 +1057,7 @@ fn tokenizeAndPrintRaw(...@@ -1057,9 +1057,7 @@ fn tokenizeAndPrintRaw(
1057 }1057 }
1058 },1058 },
10591059
1060 .integer_literal,1060 .number_literal => {
1061 .float_literal,
1062 => {
1063 try out.writeAll("<span class=\"tok-number\">");1061 try out.writeAll("<span class=\"tok-number\">");
1064 try writeEscaped(out, src[token.loc.start..token.loc.end]);1062 try writeEscaped(out, src[token.loc.start..token.loc.end]);
1065 try out.writeAll("</span>");1063 try out.writeAll("</span>");
lib/std/zig.zig+2
...@@ -10,6 +10,7 @@ pub const fmtEscapes = fmt.fmtEscapes;...@@ -10,6 +10,7 @@ pub const fmtEscapes = fmt.fmtEscapes;
10pub const isValidId = fmt.isValidId;10pub const isValidId = fmt.isValidId;
11pub const parse = @import("zig/parse.zig").parse;11pub const parse = @import("zig/parse.zig").parse;
12pub const string_literal = @import("zig/string_literal.zig");12pub const string_literal = @import("zig/string_literal.zig");
13pub const number_literal = @import("zig/number_literal.zig");
13pub const Ast = @import("zig/Ast.zig");14pub const Ast = @import("zig/Ast.zig");
14pub const system = @import("zig/system.zig");15pub const system = @import("zig/system.zig");
15pub const CrossTarget = @import("zig/CrossTarget.zig");16pub const CrossTarget = @import("zig/CrossTarget.zig");
...@@ -17,6 +18,7 @@ pub const CrossTarget = @import("zig/CrossTarget.zig");...@@ -17,6 +18,7 @@ pub const CrossTarget = @import("zig/CrossTarget.zig");
17// Character literal parsing18// Character literal parsing
18pub const ParsedCharLiteral = string_literal.ParsedCharLiteral;19pub const ParsedCharLiteral = string_literal.ParsedCharLiteral;
19pub const parseCharLiteral = string_literal.parseCharLiteral;20pub const parseCharLiteral = string_literal.parseCharLiteral;
21pub const parseNumberLiteral = number_literal.parseNumberLiteral;
2022
21// Files needed by translate-c.23// Files needed by translate-c.
22pub const c_builtins = @import("zig/c_builtins.zig");24pub const c_builtins = @import("zig/c_builtins.zig");
lib/std/zig/Ast.zig+3-7
...@@ -406,8 +406,7 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex {...@@ -406,8 +406,7 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex {
406 .identifier,406 .identifier,
407 .anyframe_literal,407 .anyframe_literal,
408 .char_literal,408 .char_literal,
409 .integer_literal,409 .number_literal,
410 .float_literal,
411 .unreachable_literal,410 .unreachable_literal,
412 .string_literal,411 .string_literal,
413 .multiline_string_literal,412 .multiline_string_literal,
...@@ -781,8 +780,7 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex {...@@ -781,8 +780,7 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex {
781780
782 .anyframe_literal,781 .anyframe_literal,
783 .char_literal,782 .char_literal,
784 .integer_literal,783 .number_literal,
785 .float_literal,
786 .unreachable_literal,784 .unreachable_literal,
787 .identifier,785 .identifier,
788 .deref,786 .deref,
...@@ -2919,9 +2917,7 @@ pub const Node = struct {...@@ -2919,9 +2917,7 @@ pub const Node = struct {
2919 /// Both lhs and rhs unused.2917 /// Both lhs and rhs unused.
2920 char_literal,2918 char_literal,
2921 /// Both lhs and rhs unused.2919 /// Both lhs and rhs unused.
2922 integer_literal,2920 number_literal,
2923 /// Both lhs and rhs unused.
2924 float_literal,
2925 /// Both lhs and rhs unused.2921 /// Both lhs and rhs unused.
2926 unreachable_literal,2922 unreachable_literal,
2927 /// Both lhs and rhs unused.2923 /// Both lhs and rhs unused.
lib/std/zig/number_literal.zig created+167
...@@ -0,0 +1,167 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const utf8Decode = std.unicode.utf8Decode;
4const utf8Encode = std.unicode.utf8Encode;
5
6pub const ParseError = error{
7 OutOfMemory,
8 InvalidLiteral,
9};
10
11pub const Base = enum(u8) { decimal = 10, hex = 16, binary = 2, octal = 8 };
12pub const FloatBase = enum(u8) { decimal = 10, hex = 16 };
13
14pub const Result = union(enum) {
15 /// Result fits if it fits in u64
16 int: u64,
17 /// Result is an int that doesn't fit in u64. Payload is the base, if it is
18 /// not `.decimal` then the slice has a two character prefix.
19 big_int: Base,
20 /// Result is a float. Payload is the base, if it is not `.decimal` then
21 /// the slice has a two character prefix.
22 float: FloatBase,
23 failure: Error,
24};
25
26pub const Error = union(enum) {
27 /// The number has leading zeroes.
28 leading_zero,
29 /// Expected a digit after base prefix.
30 digit_after_base,
31 /// The base prefix is in uppercase.
32 upper_case_base: usize,
33 /// Float literal has an invalid base prefix.
34 invalid_float_base: usize,
35 /// Repeated '_' digit separator.
36 repeated_underscore: usize,
37 /// '_' digit separator after special character (+-.)
38 invalid_underscore_after_special: usize,
39 /// Invalid digit for the specified base.
40 invalid_digit: struct { i: usize, base: Base },
41 /// Invalid digit for an exponent.
42 invalid_digit_exponent: usize,
43 /// Float literal has multiple periods.
44 duplicate_period,
45 /// Float literal has multiple exponents.
46 duplicate_exponent: usize,
47 /// Decimal float has hexadecimal exponent.
48 invalid_hex_exponent: usize,
49 /// Exponent comes directly after '_' digit separator.
50 exponent_after_underscore: usize,
51 /// Special character (+-.) comes directly after exponent.
52 special_after_underscore: usize,
53 /// Number ends in special character (+-.)
54 trailing_special: usize,
55 /// Number ends in '_' digit separator.
56 trailing_underscore: usize,
57 /// Character not in [0-9a-zA-Z.+-_]
58 invalid_character: usize,
59 /// [+-] not immediately after [pPeE]
60 invalid_exponent_sign: usize,
61};
62
63/// Parse Zig number literal accepted by fmt.parseInt, fmt.parseFloat and big_int.setString.
64/// Valid for any input.
65pub fn parseNumberLiteral(bytes: []const u8) Result {
66 var i: usize = 0;
67 var base: u8 = 10;
68 if (bytes.len >= 2 and bytes[0] == '0') switch (bytes[1]) {
69 'b' => {
70 base = 2;
71 i = 2;
72 },
73 'o' => {
74 base = 8;
75 i = 2;
76 },
77 'x' => {
78 base = 16;
79 i = 2;
80 },
81 'B', 'O', 'X' => return .{ .failure = .{ .upper_case_base = 1 } },
82 '.', 'e', 'E' => {},
83 else => return .{ .failure = .leading_zero },
84 };
85 if (bytes.len == 2 and base != 10) return .{ .failure = .digit_after_base };
86
87 var x: u64 = 0;
88 var overflow = false;
89 var underscore = false;
90 var period = false;
91 var special: u8 = 0;
92 var exponent = false;
93 var float = false;
94 while (i < bytes.len) : (i += 1) {
95 const c = bytes[i];
96 switch (c) {
97 '_' => {
98 if (i == 2 and base != 10) return .{ .failure = .{ .invalid_underscore_after_special = i } };
99 if (special != 0) return .{ .failure = .{ .invalid_underscore_after_special = i } };
100 if (underscore) return .{ .failure = .{ .repeated_underscore = i } };
101 underscore = true;
102 continue;
103 },
104 'e', 'E' => if (base == 10) {
105 float = true;
106 if (base != 10 and base != 16) return .{ .failure = .{ .invalid_float_base = 2 } };
107 if (exponent) return .{ .failure = .{ .duplicate_exponent = i } };
108 if (underscore) return .{ .failure = .{ .exponent_after_underscore = i } };
109 special = c;
110 exponent = true;
111 continue;
112 },
113 'p', 'P' => if (base == 16) {
114 float = true;
115 if (base != 10 and base != 16) return .{ .failure = .{ .invalid_float_base = 2 } };
116 if (exponent) return .{ .failure = .{ .duplicate_exponent = i } };
117 if (underscore) return .{ .failure = .{ .exponent_after_underscore = i } };
118 if (base != 16) return .{ .failure = .{ .invalid_hex_exponent = i } };
119 special = c;
120 exponent = true;
121 continue;
122 },
123 '.' => {
124 float = true;
125 if (base != 10 and base != 16) return .{ .failure = .{ .invalid_float_base = 2 } };
126 if (period) return .{ .failure = .{ .duplicate_exponent = i } };
127 period = true;
128 if (underscore) return .{ .failure = .{ .special_after_underscore = i } };
129 special = c;
130 continue;
131 },
132 '+', '-' => {
133 switch (special) {
134 'p', 'P', 'e', 'E' => {},
135 else => return .{ .failure = .{ .invalid_exponent_sign = i } },
136 }
137 special = c;
138 continue;
139 },
140 else => {},
141 }
142 const digit = switch (c) {
143 '0'...'9' => c - '0',
144 'A'...'Z' => c - 'A' + 10,
145 'a'...'z' => c - 'a' + 10,
146 else => return .{ .failure = .{ .invalid_character = i } },
147 };
148 if (digit >= base) return .{ .failure = .{ .invalid_digit = .{ .i = i, .base = @intToEnum(Base, base) } } };
149 if (exponent and digit >= 10) return .{ .failure = .{ .invalid_digit_exponent = i } };
150 underscore = false;
151 special = 0;
152
153 if (float) continue;
154 if (x != 0) if (@mulWithOverflow(u64, x, base, &x)) {
155 overflow = true;
156 };
157 if (@addWithOverflow(u64, x, digit, &x)) {
158 overflow = true;
159 }
160 }
161 if (underscore) return .{ .failure = .{ .trailing_underscore = bytes.len - 1 } };
162 if (special != 0) return .{ .failure = .{ .trailing_special = bytes.len - 1 } };
163
164 if (float) return .{ .float = @intToEnum(FloatBase, base) };
165 if (overflow) return .{ .big_int = @intToEnum(Base, base) };
166 return .{ .int = x };
167}
lib/std/zig/parse.zig+2-10
...@@ -2401,16 +2401,8 @@ const Parser = struct {...@@ -2401,16 +2401,8 @@ const Parser = struct {
2401 .rhs = undefined,2401 .rhs = undefined,
2402 },2402 },
2403 }),2403 }),
2404 .integer_literal => return p.addNode(.{2404 .number_literal => return p.addNode(.{
2405 .tag = .integer_literal,2405 .tag = .number_literal,
2406 .main_token = p.nextToken(),
2407 .data = .{
2408 .lhs = undefined,
2409 .rhs = undefined,
2410 },
2411 }),
2412 .float_literal => return p.addNode(.{
2413 .tag = .float_literal,
2414 .main_token = p.nextToken(),2406 .main_token = p.nextToken(),
2415 .data = .{2407 .data = .{
2416 .lhs = undefined,2408 .lhs = undefined,
lib/std/zig/render.zig+1-2
...@@ -199,8 +199,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -199,8 +199,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
199 return renderSpace(ais, tree, token_index, lexeme.len, space);199 return renderSpace(ais, tree, token_index, lexeme.len, space);
200 },200 },
201201
202 .integer_literal,202 .number_literal,
203 .float_literal,
204 .char_literal,203 .char_literal,
205 .unreachable_literal,204 .unreachable_literal,
206 .anyframe_literal,205 .anyframe_literal,
lib/std/zig/tokenizer.zig+263-473
...@@ -136,8 +136,7 @@ pub const Token = struct {...@@ -136,8 +136,7 @@ pub const Token = struct {
136 angle_bracket_angle_bracket_right,136 angle_bracket_angle_bracket_right,
137 angle_bracket_angle_bracket_right_equal,137 angle_bracket_angle_bracket_right_equal,
138 tilde,138 tilde,
139 integer_literal,139 number_literal,
140 float_literal,
141 doc_comment,140 doc_comment,
142 container_doc_comment,141 container_doc_comment,
143 keyword_addrspace,142 keyword_addrspace,
...@@ -199,8 +198,7 @@ pub const Token = struct {...@@ -199,8 +198,7 @@ pub const Token = struct {
199 .char_literal,198 .char_literal,
200 .eof,199 .eof,
201 .builtin,200 .builtin,
202 .integer_literal,201 .number_literal,
203 .float_literal,
204 .doc_comment,202 .doc_comment,
205 .container_doc_comment,203 .container_doc_comment,
206 => null,204 => null,
...@@ -328,8 +326,7 @@ pub const Token = struct {...@@ -328,8 +326,7 @@ pub const Token = struct {
328 .char_literal => "a character literal",326 .char_literal => "a character literal",
329 .eof => "EOF",327 .eof => "EOF",
330 .builtin => "a builtin function",328 .builtin => "a builtin function",
331 .integer_literal => "an integer literal",329 .number_literal => "a number literal",
332 .float_literal => "a floating point literal",
333 .doc_comment, .container_doc_comment => "a document comment",330 .doc_comment, .container_doc_comment => "a document comment",
334 else => unreachable,331 else => unreachable,
335 };332 };
...@@ -387,24 +384,11 @@ pub const Tokenizer = struct {...@@ -387,24 +384,11 @@ pub const Tokenizer = struct {
387 line_comment,384 line_comment,
388 doc_comment_start,385 doc_comment_start,
389 doc_comment,386 doc_comment,
390 zero,387 int,
391 int_literal_dec,388 int_exponent,
392 int_literal_dec_no_underscore,389 int_period,
393 int_literal_bin,390 float,
394 int_literal_bin_no_underscore,391 float_exponent,
395 int_literal_oct,
396 int_literal_oct_no_underscore,
397 int_literal_hex,
398 int_literal_hex_no_underscore,
399 num_dot_dec,
400 num_dot_hex,
401 float_fraction_dec,
402 float_fraction_dec_no_underscore,
403 float_fraction_hex,
404 float_fraction_hex_no_underscore,
405 float_exponent_unsigned,
406 float_exponent_num,
407 float_exponent_num_no_underscore,
408 ampersand,392 ampersand,
409 caret,393 caret,
410 percent,394 percent,
...@@ -557,13 +541,9 @@ pub const Tokenizer = struct {...@@ -557,13 +541,9 @@ pub const Tokenizer = struct {
557 '&' => {541 '&' => {
558 state = .ampersand;542 state = .ampersand;
559 },543 },
560 '0' => {544 '0'...'9' => {
561 state = .zero;545 state = .int;
562 result.tag = .integer_literal;546 result.tag = .number_literal;
563 },
564 '1'...'9' => {
565 state = .int_literal_dec;
566 result.tag = .integer_literal;
567 },547 },
568 else => {548 else => {
569 result.tag = .invalid;549 result.tag = .invalid;
...@@ -1175,232 +1155,42 @@ pub const Tokenizer = struct {...@@ -1175,232 +1155,42 @@ pub const Tokenizer = struct {
1175 '\t', '\r' => {},1155 '\t', '\r' => {},
1176 else => self.checkLiteralCharacter(),1156 else => self.checkLiteralCharacter(),
1177 },1157 },
1178 .zero => switch (c) {1158 .int => switch (c) {
1179 'b' => {1159 '.' => state = .int_period,
1180 state = .int_literal_bin_no_underscore;1160 '_', 'a'...'d', 'f'...'o', 'q'...'z', 'A'...'D', 'F'...'O', 'Q'...'Z', '0'...'9' => {},
1181 },1161 'e', 'E', 'p', 'P' => state = .int_exponent,
1182 'o' => {
1183 state = .int_literal_oct_no_underscore;
1184 },
1185 'x' => {
1186 state = .int_literal_hex_no_underscore;
1187 },
1188 '0'...'9', '_', '.', 'e', 'E' => {
1189 // reinterpret as a decimal number
1190 self.index -= 1;
1191 state = .int_literal_dec;
1192 },
1193 'a', 'c', 'd', 'f'...'n', 'p'...'w', 'y', 'z', 'A'...'D', 'F'...'Z' => {
1194 result.tag = .invalid;
1195 break;
1196 },
1197 else => break,
1198 },
1199 .int_literal_bin_no_underscore => switch (c) {
1200 '0'...'1' => {
1201 state = .int_literal_bin;
1202 },
1203 else => {
1204 result.tag = .invalid;
1205 break;
1206 },
1207 },
1208 .int_literal_bin => switch (c) {
1209 '_' => {
1210 state = .int_literal_bin_no_underscore;
1211 },
1212 '0'...'1' => {},
1213 '2'...'9', 'a'...'z', 'A'...'Z' => {
1214 result.tag = .invalid;
1215 break;
1216 },
1217 else => break,1162 else => break,
1218 },1163 },
1219 .int_literal_oct_no_underscore => switch (c) {1164 .int_exponent => switch (c) {
1220 '0'...'7' => {1165 '-', '+' => {
1221 state = .int_literal_oct;1166 state = .float;
1222 },1167 },
1223 else => {1168 else => {
1224 result.tag = .invalid;
1225 break;
1226 },
1227 },
1228 .int_literal_oct => switch (c) {
1229 '_' => {
1230 state = .int_literal_oct_no_underscore;
1231 },
1232 '0'...'7' => {},
1233 '8', '9', 'a'...'z', 'A'...'Z' => {
1234 result.tag = .invalid;
1235 break;
1236 },
1237 else => break,
1238 },
1239 .int_literal_dec_no_underscore => switch (c) {
1240 '0'...'9' => {
1241 state = .int_literal_dec;
1242 },
1243 else => {
1244 result.tag = .invalid;
1245 break;
1246 },
1247 },
1248 .int_literal_dec => switch (c) {
1249 '_' => {
1250 state = .int_literal_dec_no_underscore;
1251 },
1252 '.' => {
1253 state = .num_dot_dec;
1254 result.tag = .invalid;
1255 },
1256 'e', 'E' => {
1257 state = .float_exponent_unsigned;
1258 result.tag = .float_literal;
1259 },
1260 '0'...'9' => {},
1261 'a'...'d', 'f'...'z', 'A'...'D', 'F'...'Z' => {
1262 result.tag = .invalid;
1263 break;
1264 },
1265 else => break,
1266 },
1267 .int_literal_hex_no_underscore => switch (c) {
1268 '0'...'9', 'a'...'f', 'A'...'F' => {
1269 state = .int_literal_hex;
1270 },
1271 else => {
1272 result.tag = .invalid;
1273 break;
1274 },
1275 },
1276 .int_literal_hex => switch (c) {
1277 '_' => {
1278 state = .int_literal_hex_no_underscore;
1279 },
1280 '.' => {
1281 state = .num_dot_hex;
1282 result.tag = .invalid;
1283 },
1284 'p', 'P' => {
1285 state = .float_exponent_unsigned;
1286 result.tag = .float_literal;
1287 },
1288 '0'...'9', 'a'...'f', 'A'...'F' => {},
1289 'g'...'o', 'q'...'z', 'G'...'O', 'Q'...'Z' => {
1290 result.tag = .invalid;
1291 break;
1292 },
1293 else => break,
1294 },
1295 .num_dot_dec => switch (c) {
1296 '.' => {
1297 result.tag = .integer_literal;
1298 self.index -= 1;
1299 state = .start;
1300 break;
1301 },
1302 '0'...'9' => {
1303 result.tag = .float_literal;
1304 state = .float_fraction_dec;
1305 },
1306 '_', 'a'...'z', 'A'...'Z' => {
1307 result.tag = .invalid;
1308 break;
1309 },
1310 else => break,
1311 },
1312 .num_dot_hex => switch (c) {
1313 '.' => {
1314 result.tag = .integer_literal;
1315 self.index -= 1;1169 self.index -= 1;
1316 state = .start;1170 state = .int;
1317 break;
1318 },
1319 '0'...'9', 'a'...'f', 'A'...'F' => {
1320 result.tag = .float_literal;
1321 state = .float_fraction_hex;
1322 },
1323 '_', 'g'...'z', 'G'...'Z' => {
1324 result.tag = .invalid;
1325 break;
1326 },1171 },
1327 else => break,
1328 },1172 },
1329 .float_fraction_dec_no_underscore => switch (c) {1173 .int_period => switch (c) {
1330 '0'...'9' => {1174 '_', 'a'...'d', 'f'...'o', 'q'...'z', 'A'...'D', 'F'...'O', 'Q'...'Z', '0'...'9' => {
1331 state = .float_fraction_dec;1175 state = .float;
1332 },1176 },
1177 'e', 'E', 'p', 'P' => state = .float_exponent,
1333 else => {1178 else => {
1334 result.tag = .invalid;1179 self.index -= 1;
1335 break;
1336 },
1337 },
1338 .float_fraction_dec => switch (c) {
1339 '_' => {
1340 state = .float_fraction_dec_no_underscore;
1341 },
1342 'e', 'E' => {
1343 state = .float_exponent_unsigned;
1344 },
1345 '0'...'9' => {},
1346 'a'...'d', 'f'...'z', 'A'...'D', 'F'...'Z' => {
1347 result.tag = .invalid;
1348 break;
1349 },
1350 else => break,
1351 },
1352 .float_fraction_hex_no_underscore => switch (c) {
1353 '0'...'9', 'a'...'f', 'A'...'F' => {
1354 state = .float_fraction_hex;
1355 },
1356 else => {
1357 result.tag = .invalid;
1358 break;1180 break;
1359 },1181 },
1360 },1182 },
1361 .float_fraction_hex => switch (c) {1183 .float => switch (c) {
1362 '_' => {1184 '_', 'a'...'d', 'f'...'o', 'q'...'z', 'A'...'D', 'F'...'O', 'Q'...'Z', '0'...'9' => {},
1363 state = .float_fraction_hex_no_underscore;1185 'e', 'E', 'p', 'P' => state = .float_exponent,
1364 },
1365 'p', 'P' => {
1366 state = .float_exponent_unsigned;
1367 },
1368 '0'...'9', 'a'...'f', 'A'...'F' => {},
1369 'g'...'o', 'q'...'z', 'G'...'O', 'Q'...'Z' => {
1370 result.tag = .invalid;
1371 break;
1372 },
1373 else => break,1186 else => break,
1374 },1187 },
1375 .float_exponent_unsigned => switch (c) {1188 .float_exponent => switch (c) {
1376 '+', '-' => {1189 '-', '+' => state = .float,
1377 state = .float_exponent_num_no_underscore;
1378 },
1379 else => {1190 else => {
1380 // reinterpret as a normal exponent number
1381 self.index -= 1;1191 self.index -= 1;
1382 state = .float_exponent_num_no_underscore;1192 state = .float;
1383 },
1384 },
1385 .float_exponent_num_no_underscore => switch (c) {
1386 '0'...'9' => {
1387 state = .float_exponent_num;
1388 },1193 },
1389 else => {
1390 result.tag = .invalid;
1391 break;
1392 },
1393 },
1394 .float_exponent_num => switch (c) {
1395 '_' => {
1396 state = .float_exponent_num_no_underscore;
1397 },
1398 '0'...'9' => {},
1399 'a'...'z', 'A'...'Z' => {
1400 result.tag = .invalid;
1401 break;
1402 },
1403 else => break,
1404 },1194 },
1405 }1195 }
1406 }1196 }
...@@ -1571,7 +1361,7 @@ test "code point literal with unicode escapes" {...@@ -1571,7 +1361,7 @@ test "code point literal with unicode escapes" {
1571 , &.{ .invalid, .invalid });1361 , &.{ .invalid, .invalid });
1572 try testTokenize(1362 try testTokenize(
1573 \\'\U0333'1363 \\'\U0333'
1574 , &.{ .invalid, .integer_literal, .invalid });1364 , &.{ .invalid, .number_literal, .invalid });
1575}1365}
15761366
1577test "code point literal with unicode code point" {1367test "code point literal with unicode code point" {
...@@ -1584,7 +1374,7 @@ test "float literal e exponent" {...@@ -1584,7 +1374,7 @@ test "float literal e exponent" {
1584 try testTokenize("a = 4.94065645841246544177e-324;\n", &.{1374 try testTokenize("a = 4.94065645841246544177e-324;\n", &.{
1585 .identifier,1375 .identifier,
1586 .equal,1376 .equal,
1587 .float_literal,1377 .number_literal,
1588 .semicolon,1378 .semicolon,
1589 });1379 });
1590}1380}
...@@ -1593,7 +1383,7 @@ test "float literal p exponent" {...@@ -1593,7 +1383,7 @@ test "float literal p exponent" {
1593 try testTokenize("a = 0x1.a827999fcef32p+1022;\n", &.{1383 try testTokenize("a = 0x1.a827999fcef32p+1022;\n", &.{
1594 .identifier,1384 .identifier,
1595 .equal,1385 .equal,
1596 .float_literal,1386 .number_literal,
1597 .semicolon,1387 .semicolon,
1598 });1388 });
1599}1389}
...@@ -1757,7 +1547,7 @@ test "correctly parse pointer assignment" {...@@ -1757,7 +1547,7 @@ test "correctly parse pointer assignment" {
1757 .identifier,1547 .identifier,
1758 .period_asterisk,1548 .period_asterisk,
1759 .equal,1549 .equal,
1760 .integer_literal,1550 .number_literal,
1761 .semicolon,1551 .semicolon,
1762 });1552 });
1763}1553}
...@@ -1767,7 +1557,7 @@ test "correctly parse pointer dereference followed by asterisk" {...@@ -1767,7 +1557,7 @@ test "correctly parse pointer dereference followed by asterisk" {
1767 .string_literal,1557 .string_literal,
1768 .period_asterisk,1558 .period_asterisk,
1769 .asterisk_asterisk,1559 .asterisk_asterisk,
1770 .integer_literal,1560 .number_literal,
1771 });1561 });
17721562
1773 try testTokenize("(\"b\".*)** 10", &.{1563 try testTokenize("(\"b\".*)** 10", &.{
...@@ -1776,256 +1566,256 @@ test "correctly parse pointer dereference followed by asterisk" {...@@ -1776,256 +1566,256 @@ test "correctly parse pointer dereference followed by asterisk" {
1776 .period_asterisk,1566 .period_asterisk,
1777 .r_paren,1567 .r_paren,
1778 .asterisk_asterisk,1568 .asterisk_asterisk,
1779 .integer_literal,1569 .number_literal,
1780 });1570 });
17811571
1782 try testTokenize("\"b\".*** 10", &.{1572 try testTokenize("\"b\".*** 10", &.{
1783 .string_literal,1573 .string_literal,
1784 .invalid_periodasterisks,1574 .invalid_periodasterisks,
1785 .asterisk_asterisk,1575 .asterisk_asterisk,
1786 .integer_literal,1576 .number_literal,
1787 });1577 });
1788}1578}
17891579
1790test "range literals" {1580test "range literals" {
1791 try testTokenize("0...9", &.{ .integer_literal, .ellipsis3, .integer_literal });1581 try testTokenize("0...9", &.{ .number_literal, .ellipsis3, .number_literal });
1792 try testTokenize("'0'...'9'", &.{ .char_literal, .ellipsis3, .char_literal });1582 try testTokenize("'0'...'9'", &.{ .char_literal, .ellipsis3, .char_literal });
1793 try testTokenize("0x00...0x09", &.{ .integer_literal, .ellipsis3, .integer_literal });1583 try testTokenize("0x00...0x09", &.{ .number_literal, .ellipsis3, .number_literal });
1794 try testTokenize("0b00...0b11", &.{ .integer_literal, .ellipsis3, .integer_literal });1584 try testTokenize("0b00...0b11", &.{ .number_literal, .ellipsis3, .number_literal });
1795 try testTokenize("0o00...0o11", &.{ .integer_literal, .ellipsis3, .integer_literal });1585 try testTokenize("0o00...0o11", &.{ .number_literal, .ellipsis3, .number_literal });
1796}1586}
17971587
1798test "number literals decimal" {1588test "number literals decimal" {
1799 try testTokenize("0", &.{.integer_literal});1589 try testTokenize("0", &.{.number_literal});
1800 try testTokenize("1", &.{.integer_literal});1590 try testTokenize("1", &.{.number_literal});
1801 try testTokenize("2", &.{.integer_literal});1591 try testTokenize("2", &.{.number_literal});
1802 try testTokenize("3", &.{.integer_literal});1592 try testTokenize("3", &.{.number_literal});
1803 try testTokenize("4", &.{.integer_literal});1593 try testTokenize("4", &.{.number_literal});
1804 try testTokenize("5", &.{.integer_literal});1594 try testTokenize("5", &.{.number_literal});
1805 try testTokenize("6", &.{.integer_literal});1595 try testTokenize("6", &.{.number_literal});
1806 try testTokenize("7", &.{.integer_literal});1596 try testTokenize("7", &.{.number_literal});
1807 try testTokenize("8", &.{.integer_literal});1597 try testTokenize("8", &.{.number_literal});
1808 try testTokenize("9", &.{.integer_literal});1598 try testTokenize("9", &.{.number_literal});
1809 try testTokenize("1..", &.{ .integer_literal, .ellipsis2 });1599 try testTokenize("1..", &.{ .number_literal, .ellipsis2 });
1810 try testTokenize("0a", &.{ .invalid, .identifier });1600 try testTokenize("0a", &.{.number_literal});
1811 try testTokenize("9b", &.{ .invalid, .identifier });1601 try testTokenize("9b", &.{.number_literal});
1812 try testTokenize("1z", &.{ .invalid, .identifier });1602 try testTokenize("1z", &.{.number_literal});
1813 try testTokenize("1z_1", &.{ .invalid, .identifier });1603 try testTokenize("1z_1", &.{.number_literal});
1814 try testTokenize("9z3", &.{ .invalid, .identifier });1604 try testTokenize("9z3", &.{.number_literal});
18151605
1816 try testTokenize("0_0", &.{.integer_literal});1606 try testTokenize("0_0", &.{.number_literal});
1817 try testTokenize("0001", &.{.integer_literal});1607 try testTokenize("0001", &.{.number_literal});
1818 try testTokenize("01234567890", &.{.integer_literal});1608 try testTokenize("01234567890", &.{.number_literal});
1819 try testTokenize("012_345_6789_0", &.{.integer_literal});1609 try testTokenize("012_345_6789_0", &.{.number_literal});
1820 try testTokenize("0_1_2_3_4_5_6_7_8_9_0", &.{.integer_literal});1610 try testTokenize("0_1_2_3_4_5_6_7_8_9_0", &.{.number_literal});
18211611
1822 try testTokenize("00_", &.{.invalid});1612 try testTokenize("00_", &.{.number_literal});
1823 try testTokenize("0_0_", &.{.invalid});1613 try testTokenize("0_0_", &.{.number_literal});
1824 try testTokenize("0__0", &.{ .invalid, .identifier });1614 try testTokenize("0__0", &.{.number_literal});
1825 try testTokenize("0_0f", &.{ .invalid, .identifier });1615 try testTokenize("0_0f", &.{.number_literal});
1826 try testTokenize("0_0_f", &.{ .invalid, .identifier });1616 try testTokenize("0_0_f", &.{.number_literal});
1827 try testTokenize("0_0_f_00", &.{ .invalid, .identifier });1617 try testTokenize("0_0_f_00", &.{.number_literal});
1828 try testTokenize("1_,", &.{ .invalid, .comma });1618 try testTokenize("1_,", &.{ .number_literal, .comma });
18291619
1830 try testTokenize("0.0", &.{.float_literal});1620 try testTokenize("0.0", &.{.number_literal});
1831 try testTokenize("1.0", &.{.float_literal});1621 try testTokenize("1.0", &.{.number_literal});
1832 try testTokenize("10.0", &.{.float_literal});1622 try testTokenize("10.0", &.{.number_literal});
1833 try testTokenize("0e0", &.{.float_literal});1623 try testTokenize("0e0", &.{.number_literal});
1834 try testTokenize("1e0", &.{.float_literal});1624 try testTokenize("1e0", &.{.number_literal});
1835 try testTokenize("1e100", &.{.float_literal});1625 try testTokenize("1e100", &.{.number_literal});
1836 try testTokenize("1.0e100", &.{.float_literal});1626 try testTokenize("1.0e100", &.{.number_literal});
1837 try testTokenize("1.0e+100", &.{.float_literal});1627 try testTokenize("1.0e+100", &.{.number_literal});
1838 try testTokenize("1.0e-100", &.{.float_literal});1628 try testTokenize("1.0e-100", &.{.number_literal});
1839 try testTokenize("1_0_0_0.0_0_0_0_0_1e1_0_0_0", &.{.float_literal});1629 try testTokenize("1_0_0_0.0_0_0_0_0_1e1_0_0_0", &.{.number_literal});
18401630
1841 try testTokenize("1.", &.{.invalid});1631 try testTokenize("1.", &.{ .number_literal, .period });
1842 try testTokenize("1e", &.{.invalid});1632 try testTokenize("1e", &.{.number_literal});
1843 try testTokenize("1.e100", &.{ .invalid, .identifier });1633 try testTokenize("1.e100", &.{.number_literal});
1844 try testTokenize("1.0e1f0", &.{ .invalid, .identifier });1634 try testTokenize("1.0e1f0", &.{.number_literal});
1845 try testTokenize("1.0p100", &.{ .invalid, .identifier });1635 try testTokenize("1.0p100", &.{.number_literal});
1846 try testTokenize("1.0p-100", &.{ .invalid, .identifier, .minus, .integer_literal });1636 try testTokenize("1.0p-100", &.{.number_literal});
1847 try testTokenize("1.0p1f0", &.{ .invalid, .identifier });1637 try testTokenize("1.0p1f0", &.{.number_literal});
1848 try testTokenize("1.0_,", &.{ .invalid, .comma });1638 try testTokenize("1.0_,", &.{ .number_literal, .comma });
1849 try testTokenize("1_.0", &.{ .invalid, .period, .integer_literal });1639 try testTokenize("1_.0", &.{.number_literal});
1850 try testTokenize("1._", &.{ .invalid, .identifier });1640 try testTokenize("1._", &.{.number_literal});
1851 try testTokenize("1.a", &.{ .invalid, .identifier });1641 try testTokenize("1.a", &.{.number_literal});
1852 try testTokenize("1.z", &.{ .invalid, .identifier });1642 try testTokenize("1.z", &.{.number_literal});
1853 try testTokenize("1._0", &.{ .invalid, .identifier });1643 try testTokenize("1._0", &.{.number_literal});
1854 try testTokenize("1.+", &.{ .invalid, .plus });1644 try testTokenize("1.+", &.{ .number_literal, .period, .plus });
1855 try testTokenize("1._+", &.{ .invalid, .identifier, .plus });1645 try testTokenize("1._+", &.{ .number_literal, .plus });
1856 try testTokenize("1._e", &.{ .invalid, .identifier });1646 try testTokenize("1._e", &.{.number_literal});
1857 try testTokenize("1.0e", &.{.invalid});1647 try testTokenize("1.0e", &.{.number_literal});
1858 try testTokenize("1.0e,", &.{ .invalid, .comma });1648 try testTokenize("1.0e,", &.{ .number_literal, .comma });
1859 try testTokenize("1.0e_", &.{ .invalid, .identifier });1649 try testTokenize("1.0e_", &.{.number_literal});
1860 try testTokenize("1.0e+_", &.{ .invalid, .identifier });1650 try testTokenize("1.0e+_", &.{.number_literal});
1861 try testTokenize("1.0e-_", &.{ .invalid, .identifier });1651 try testTokenize("1.0e-_", &.{.number_literal});
1862 try testTokenize("1.0e0_+", &.{ .invalid, .plus });1652 try testTokenize("1.0e0_+", &.{ .number_literal, .plus });
1863}1653}
18641654
1865test "number literals binary" {1655test "number literals binary" {
1866 try testTokenize("0b0", &.{.integer_literal});1656 try testTokenize("0b0", &.{.number_literal});
1867 try testTokenize("0b1", &.{.integer_literal});1657 try testTokenize("0b1", &.{.number_literal});
1868 try testTokenize("0b2", &.{ .invalid, .integer_literal });1658 try testTokenize("0b2", &.{.number_literal});
1869 try testTokenize("0b3", &.{ .invalid, .integer_literal });1659 try testTokenize("0b3", &.{.number_literal});
1870 try testTokenize("0b4", &.{ .invalid, .integer_literal });1660 try testTokenize("0b4", &.{.number_literal});
1871 try testTokenize("0b5", &.{ .invalid, .integer_literal });1661 try testTokenize("0b5", &.{.number_literal});
1872 try testTokenize("0b6", &.{ .invalid, .integer_literal });1662 try testTokenize("0b6", &.{.number_literal});
1873 try testTokenize("0b7", &.{ .invalid, .integer_literal });1663 try testTokenize("0b7", &.{.number_literal});
1874 try testTokenize("0b8", &.{ .invalid, .integer_literal });1664 try testTokenize("0b8", &.{.number_literal});
1875 try testTokenize("0b9", &.{ .invalid, .integer_literal });1665 try testTokenize("0b9", &.{.number_literal});
1876 try testTokenize("0ba", &.{ .invalid, .identifier });1666 try testTokenize("0ba", &.{.number_literal});
1877 try testTokenize("0bb", &.{ .invalid, .identifier });1667 try testTokenize("0bb", &.{.number_literal});
1878 try testTokenize("0bc", &.{ .invalid, .identifier });1668 try testTokenize("0bc", &.{.number_literal});
1879 try testTokenize("0bd", &.{ .invalid, .identifier });1669 try testTokenize("0bd", &.{.number_literal});
1880 try testTokenize("0be", &.{ .invalid, .identifier });1670 try testTokenize("0be", &.{.number_literal});
1881 try testTokenize("0bf", &.{ .invalid, .identifier });1671 try testTokenize("0bf", &.{.number_literal});
1882 try testTokenize("0bz", &.{ .invalid, .identifier });1672 try testTokenize("0bz", &.{.number_literal});
18831673
1884 try testTokenize("0b0000_0000", &.{.integer_literal});1674 try testTokenize("0b0000_0000", &.{.number_literal});
1885 try testTokenize("0b1111_1111", &.{.integer_literal});1675 try testTokenize("0b1111_1111", &.{.number_literal});
1886 try testTokenize("0b10_10_10_10", &.{.integer_literal});1676 try testTokenize("0b10_10_10_10", &.{.number_literal});
1887 try testTokenize("0b0_1_0_1_0_1_0_1", &.{.integer_literal});1677 try testTokenize("0b0_1_0_1_0_1_0_1", &.{.number_literal});
1888 try testTokenize("0b1.", &.{ .integer_literal, .period });1678 try testTokenize("0b1.", &.{ .number_literal, .period });
1889 try testTokenize("0b1.0", &.{ .integer_literal, .period, .integer_literal });1679 try testTokenize("0b1.0", &.{.number_literal});
18901680
1891 try testTokenize("0B0", &.{ .invalid, .identifier });1681 try testTokenize("0B0", &.{.number_literal});
1892 try testTokenize("0b_", &.{ .invalid, .identifier });1682 try testTokenize("0b_", &.{.number_literal});
1893 try testTokenize("0b_0", &.{ .invalid, .identifier });1683 try testTokenize("0b_0", &.{.number_literal});
1894 try testTokenize("0b1_", &.{.invalid});1684 try testTokenize("0b1_", &.{.number_literal});
1895 try testTokenize("0b0__1", &.{ .invalid, .identifier });1685 try testTokenize("0b0__1", &.{.number_literal});
1896 try testTokenize("0b0_1_", &.{.invalid});1686 try testTokenize("0b0_1_", &.{.number_literal});
1897 try testTokenize("0b1e", &.{ .invalid, .identifier });1687 try testTokenize("0b1e", &.{.number_literal});
1898 try testTokenize("0b1p", &.{ .invalid, .identifier });1688 try testTokenize("0b1p", &.{.number_literal});
1899 try testTokenize("0b1e0", &.{ .invalid, .identifier });1689 try testTokenize("0b1e0", &.{.number_literal});
1900 try testTokenize("0b1p0", &.{ .invalid, .identifier });1690 try testTokenize("0b1p0", &.{.number_literal});
1901 try testTokenize("0b1_,", &.{ .invalid, .comma });1691 try testTokenize("0b1_,", &.{ .number_literal, .comma });
1902}1692}
19031693
1904test "number literals octal" {1694test "number literals octal" {
1905 try testTokenize("0o0", &.{.integer_literal});1695 try testTokenize("0o0", &.{.number_literal});
1906 try testTokenize("0o1", &.{.integer_literal});1696 try testTokenize("0o1", &.{.number_literal});
1907 try testTokenize("0o2", &.{.integer_literal});1697 try testTokenize("0o2", &.{.number_literal});
1908 try testTokenize("0o3", &.{.integer_literal});1698 try testTokenize("0o3", &.{.number_literal});
1909 try testTokenize("0o4", &.{.integer_literal});1699 try testTokenize("0o4", &.{.number_literal});
1910 try testTokenize("0o5", &.{.integer_literal});1700 try testTokenize("0o5", &.{.number_literal});
1911 try testTokenize("0o6", &.{.integer_literal});1701 try testTokenize("0o6", &.{.number_literal});
1912 try testTokenize("0o7", &.{.integer_literal});1702 try testTokenize("0o7", &.{.number_literal});
1913 try testTokenize("0o8", &.{ .invalid, .integer_literal });1703 try testTokenize("0o8", &.{.number_literal});
1914 try testTokenize("0o9", &.{ .invalid, .integer_literal });1704 try testTokenize("0o9", &.{.number_literal});
1915 try testTokenize("0oa", &.{ .invalid, .identifier });1705 try testTokenize("0oa", &.{.number_literal});
1916 try testTokenize("0ob", &.{ .invalid, .identifier });1706 try testTokenize("0ob", &.{.number_literal});
1917 try testTokenize("0oc", &.{ .invalid, .identifier });1707 try testTokenize("0oc", &.{.number_literal});
1918 try testTokenize("0od", &.{ .invalid, .identifier });1708 try testTokenize("0od", &.{.number_literal});
1919 try testTokenize("0oe", &.{ .invalid, .identifier });1709 try testTokenize("0oe", &.{.number_literal});
1920 try testTokenize("0of", &.{ .invalid, .identifier });1710 try testTokenize("0of", &.{.number_literal});
1921 try testTokenize("0oz", &.{ .invalid, .identifier });1711 try testTokenize("0oz", &.{.number_literal});
19221712
1923 try testTokenize("0o01234567", &.{.integer_literal});1713 try testTokenize("0o01234567", &.{.number_literal});
1924 try testTokenize("0o0123_4567", &.{.integer_literal});1714 try testTokenize("0o0123_4567", &.{.number_literal});
1925 try testTokenize("0o01_23_45_67", &.{.integer_literal});1715 try testTokenize("0o01_23_45_67", &.{.number_literal});
1926 try testTokenize("0o0_1_2_3_4_5_6_7", &.{.integer_literal});1716 try testTokenize("0o0_1_2_3_4_5_6_7", &.{.number_literal});
1927 try testTokenize("0o7.", &.{ .integer_literal, .period });1717 try testTokenize("0o7.", &.{ .number_literal, .period });
1928 try testTokenize("0o7.0", &.{ .integer_literal, .period, .integer_literal });1718 try testTokenize("0o7.0", &.{.number_literal});
19291719
1930 try testTokenize("0O0", &.{ .invalid, .identifier });1720 try testTokenize("0O0", &.{.number_literal});
1931 try testTokenize("0o_", &.{ .invalid, .identifier });1721 try testTokenize("0o_", &.{.number_literal});
1932 try testTokenize("0o_0", &.{ .invalid, .identifier });1722 try testTokenize("0o_0", &.{.number_literal});
1933 try testTokenize("0o1_", &.{.invalid});1723 try testTokenize("0o1_", &.{.number_literal});
1934 try testTokenize("0o0__1", &.{ .invalid, .identifier });1724 try testTokenize("0o0__1", &.{.number_literal});
1935 try testTokenize("0o0_1_", &.{.invalid});1725 try testTokenize("0o0_1_", &.{.number_literal});
1936 try testTokenize("0o1e", &.{ .invalid, .identifier });1726 try testTokenize("0o1e", &.{.number_literal});
1937 try testTokenize("0o1p", &.{ .invalid, .identifier });1727 try testTokenize("0o1p", &.{.number_literal});
1938 try testTokenize("0o1e0", &.{ .invalid, .identifier });1728 try testTokenize("0o1e0", &.{.number_literal});
1939 try testTokenize("0o1p0", &.{ .invalid, .identifier });1729 try testTokenize("0o1p0", &.{.number_literal});
1940 try testTokenize("0o_,", &.{ .invalid, .identifier, .comma });1730 try testTokenize("0o_,", &.{ .number_literal, .comma });
1941}1731}
19421732
1943test "number literals hexadecimal" {1733test "number literals hexadecimal" {
1944 try testTokenize("0x0", &.{.integer_literal});1734 try testTokenize("0x0", &.{.number_literal});
1945 try testTokenize("0x1", &.{.integer_literal});1735 try testTokenize("0x1", &.{.number_literal});
1946 try testTokenize("0x2", &.{.integer_literal});1736 try testTokenize("0x2", &.{.number_literal});
1947 try testTokenize("0x3", &.{.integer_literal});1737 try testTokenize("0x3", &.{.number_literal});
1948 try testTokenize("0x4", &.{.integer_literal});1738 try testTokenize("0x4", &.{.number_literal});
1949 try testTokenize("0x5", &.{.integer_literal});1739 try testTokenize("0x5", &.{.number_literal});
1950 try testTokenize("0x6", &.{.integer_literal});1740 try testTokenize("0x6", &.{.number_literal});
1951 try testTokenize("0x7", &.{.integer_literal});1741 try testTokenize("0x7", &.{.number_literal});
1952 try testTokenize("0x8", &.{.integer_literal});1742 try testTokenize("0x8", &.{.number_literal});
1953 try testTokenize("0x9", &.{.integer_literal});1743 try testTokenize("0x9", &.{.number_literal});
1954 try testTokenize("0xa", &.{.integer_literal});1744 try testTokenize("0xa", &.{.number_literal});
1955 try testTokenize("0xb", &.{.integer_literal});1745 try testTokenize("0xb", &.{.number_literal});
1956 try testTokenize("0xc", &.{.integer_literal});1746 try testTokenize("0xc", &.{.number_literal});
1957 try testTokenize("0xd", &.{.integer_literal});1747 try testTokenize("0xd", &.{.number_literal});
1958 try testTokenize("0xe", &.{.integer_literal});1748 try testTokenize("0xe", &.{.number_literal});
1959 try testTokenize("0xf", &.{.integer_literal});1749 try testTokenize("0xf", &.{.number_literal});
1960 try testTokenize("0xA", &.{.integer_literal});1750 try testTokenize("0xA", &.{.number_literal});
1961 try testTokenize("0xB", &.{.integer_literal});1751 try testTokenize("0xB", &.{.number_literal});
1962 try testTokenize("0xC", &.{.integer_literal});1752 try testTokenize("0xC", &.{.number_literal});
1963 try testTokenize("0xD", &.{.integer_literal});1753 try testTokenize("0xD", &.{.number_literal});
1964 try testTokenize("0xE", &.{.integer_literal});1754 try testTokenize("0xE", &.{.number_literal});
1965 try testTokenize("0xF", &.{.integer_literal});1755 try testTokenize("0xF", &.{.number_literal});
1966 try testTokenize("0x0z", &.{ .invalid, .identifier });1756 try testTokenize("0x0z", &.{.number_literal});
1967 try testTokenize("0xz", &.{ .invalid, .identifier });1757 try testTokenize("0xz", &.{.number_literal});
19681758
1969 try testTokenize("0x0123456789ABCDEF", &.{.integer_literal});1759 try testTokenize("0x0123456789ABCDEF", &.{.number_literal});
1970 try testTokenize("0x0123_4567_89AB_CDEF", &.{.integer_literal});1760 try testTokenize("0x0123_4567_89AB_CDEF", &.{.number_literal});
1971 try testTokenize("0x01_23_45_67_89AB_CDE_F", &.{.integer_literal});1761 try testTokenize("0x01_23_45_67_89AB_CDE_F", &.{.number_literal});
1972 try testTokenize("0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F", &.{.integer_literal});1762 try testTokenize("0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F", &.{.number_literal});
19731763
1974 try testTokenize("0X0", &.{ .invalid, .identifier });1764 try testTokenize("0X0", &.{.number_literal});
1975 try testTokenize("0x_", &.{ .invalid, .identifier });1765 try testTokenize("0x_", &.{.number_literal});
1976 try testTokenize("0x_1", &.{ .invalid, .identifier });1766 try testTokenize("0x_1", &.{.number_literal});
1977 try testTokenize("0x1_", &.{.invalid});1767 try testTokenize("0x1_", &.{.number_literal});
1978 try testTokenize("0x0__1", &.{ .invalid, .identifier });1768 try testTokenize("0x0__1", &.{.number_literal});
1979 try testTokenize("0x0_1_", &.{.invalid});1769 try testTokenize("0x0_1_", &.{.number_literal});
1980 try testTokenize("0x_,", &.{ .invalid, .identifier, .comma });1770 try testTokenize("0x_,", &.{ .number_literal, .comma });
19811771
1982 try testTokenize("0x1.0", &.{.float_literal});1772 try testTokenize("0x1.0", &.{.number_literal});
1983 try testTokenize("0xF.0", &.{.float_literal});1773 try testTokenize("0xF.0", &.{.number_literal});
1984 try testTokenize("0xF.F", &.{.float_literal});1774 try testTokenize("0xF.F", &.{.number_literal});
1985 try testTokenize("0xF.Fp0", &.{.float_literal});1775 try testTokenize("0xF.Fp0", &.{.number_literal});
1986 try testTokenize("0xF.FP0", &.{.float_literal});1776 try testTokenize("0xF.FP0", &.{.number_literal});
1987 try testTokenize("0x1p0", &.{.float_literal});1777 try testTokenize("0x1p0", &.{.number_literal});
1988 try testTokenize("0xfp0", &.{.float_literal});1778 try testTokenize("0xfp0", &.{.number_literal});
1989 try testTokenize("0x1.0+0xF.0", &.{ .float_literal, .plus, .float_literal });1779 try testTokenize("0x1.0+0xF.0", &.{ .number_literal, .plus, .number_literal });
19901780
1991 try testTokenize("0x1.", &.{.invalid});1781 try testTokenize("0x1.", &.{ .number_literal, .period });
1992 try testTokenize("0xF.", &.{.invalid});1782 try testTokenize("0xF.", &.{ .number_literal, .period });
1993 try testTokenize("0x1.+0xF.", &.{ .invalid, .plus, .invalid });1783 try testTokenize("0x1.+0xF.", &.{ .number_literal, .period, .plus, .number_literal, .period });
1994 try testTokenize("0xff.p10", &.{ .invalid, .identifier });1784 try testTokenize("0xff.p10", &.{.number_literal});
19951785
1996 try testTokenize("0x0123456.789ABCDEF", &.{.float_literal});1786 try testTokenize("0x0123456.789ABCDEF", &.{.number_literal});
1997 try testTokenize("0x0_123_456.789_ABC_DEF", &.{.float_literal});1787 try testTokenize("0x0_123_456.789_ABC_DEF", &.{.number_literal});
1998 try testTokenize("0x0_1_2_3_4_5_6.7_8_9_A_B_C_D_E_F", &.{.float_literal});1788 try testTokenize("0x0_1_2_3_4_5_6.7_8_9_A_B_C_D_E_F", &.{.number_literal});
1999 try testTokenize("0x0p0", &.{.float_literal});1789 try testTokenize("0x0p0", &.{.number_literal});
2000 try testTokenize("0x0.0p0", &.{.float_literal});1790 try testTokenize("0x0.0p0", &.{.number_literal});
2001 try testTokenize("0xff.ffp10", &.{.float_literal});1791 try testTokenize("0xff.ffp10", &.{.number_literal});
2002 try testTokenize("0xff.ffP10", &.{.float_literal});1792 try testTokenize("0xff.ffP10", &.{.number_literal});
2003 try testTokenize("0xffp10", &.{.float_literal});1793 try testTokenize("0xffp10", &.{.number_literal});
2004 try testTokenize("0xff_ff.ff_ffp1_0_0_0", &.{.float_literal});1794 try testTokenize("0xff_ff.ff_ffp1_0_0_0", &.{.number_literal});
2005 try testTokenize("0xf_f_f_f.f_f_f_fp+1_000", &.{.float_literal});1795 try testTokenize("0xf_f_f_f.f_f_f_fp+1_000", &.{.number_literal});
2006 try testTokenize("0xf_f_f_f.f_f_f_fp-1_00_0", &.{.float_literal});1796 try testTokenize("0xf_f_f_f.f_f_f_fp-1_00_0", &.{.number_literal});
20071797
2008 try testTokenize("0x1e", &.{.integer_literal});1798 try testTokenize("0x1e", &.{.number_literal});
2009 try testTokenize("0x1e0", &.{.integer_literal});1799 try testTokenize("0x1e0", &.{.number_literal});
2010 try testTokenize("0x1p", &.{.invalid});1800 try testTokenize("0x1p", &.{.number_literal});
2011 try testTokenize("0xfp0z1", &.{ .invalid, .identifier });1801 try testTokenize("0xfp0z1", &.{.number_literal});
2012 try testTokenize("0xff.ffpff", &.{ .invalid, .identifier });1802 try testTokenize("0xff.ffpff", &.{.number_literal});
2013 try testTokenize("0x0.p", &.{ .invalid, .identifier });1803 try testTokenize("0x0.p", &.{.number_literal});
2014 try testTokenize("0x0.z", &.{ .invalid, .identifier });1804 try testTokenize("0x0.z", &.{.number_literal});
2015 try testTokenize("0x0._", &.{ .invalid, .identifier });1805 try testTokenize("0x0._", &.{.number_literal});
2016 try testTokenize("0x0_.0", &.{ .invalid, .period, .integer_literal });1806 try testTokenize("0x0_.0", &.{.number_literal});
2017 try testTokenize("0x0_.0.0", &.{ .invalid, .period, .float_literal });1807 try testTokenize("0x0_.0.0", &.{ .number_literal, .period, .number_literal });
2018 try testTokenize("0x0._0", &.{ .invalid, .identifier });1808 try testTokenize("0x0._0", &.{.number_literal});
2019 try testTokenize("0x0.0_", &.{.invalid});1809 try testTokenize("0x0.0_", &.{.number_literal});
2020 try testTokenize("0x0_p0", &.{ .invalid, .identifier });1810 try testTokenize("0x0_p0", &.{.number_literal});
2021 try testTokenize("0x0_.p0", &.{ .invalid, .period, .identifier });1811 try testTokenize("0x0_.p0", &.{.number_literal});
2022 try testTokenize("0x0._p0", &.{ .invalid, .identifier });1812 try testTokenize("0x0._p0", &.{.number_literal});
2023 try testTokenize("0x0.0_p0", &.{ .invalid, .identifier });1813 try testTokenize("0x0.0_p0", &.{.number_literal});
2024 try testTokenize("0x0._0p0", &.{ .invalid, .identifier });1814 try testTokenize("0x0._0p0", &.{.number_literal});
2025 try testTokenize("0x0.0p_0", &.{ .invalid, .identifier });1815 try testTokenize("0x0.0p_0", &.{.number_literal});
2026 try testTokenize("0x0.0p+_0", &.{ .invalid, .identifier });1816 try testTokenize("0x0.0p+_0", &.{.number_literal});
2027 try testTokenize("0x0.0p-_0", &.{ .invalid, .identifier });1817 try testTokenize("0x0.0p-_0", &.{.number_literal});
2028 try testTokenize("0x0.0p0_", &.{ .invalid, .eof });1818 try testTokenize("0x0.0p0_", &.{.number_literal});
2029}1819}
20301820
2031test "multi line string literal with only 1 backslash" {1821test "multi line string literal with only 1 backslash" {
...@@ -2034,7 +1824,7 @@ test "multi line string literal with only 1 backslash" {...@@ -2034,7 +1824,7 @@ test "multi line string literal with only 1 backslash" {
20341824
2035test "invalid builtin identifiers" {1825test "invalid builtin identifiers" {
2036 try testTokenize("@()", &.{ .invalid, .l_paren, .r_paren });1826 try testTokenize("@()", &.{ .invalid, .l_paren, .r_paren });
2037 try testTokenize("@0()", &.{ .invalid, .integer_literal, .l_paren, .r_paren });1827 try testTokenize("@0()", &.{ .invalid, .number_literal, .l_paren, .r_paren });
2038}1828}
20391829
2040test "invalid token with unfinished escape right before eof" {1830test "invalid token with unfinished escape right before eof" {
src/AstGen.zig+92-90
...@@ -441,7 +441,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins...@@ -441,7 +441,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
441 .@"asm",441 .@"asm",
442 .asm_simple,442 .asm_simple,
443 .string_literal,443 .string_literal,
444 .integer_literal,444 .number_literal,
445 .call,445 .call,
446 .call_comma,446 .call_comma,
447 .async_call,447 .async_call,
...@@ -459,7 +459,6 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins...@@ -459,7 +459,6 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
459 .while_cont,459 .while_cont,
460 .bool_not,460 .bool_not,
461 .address_of,461 .address_of,
462 .float_literal,
463 .optional_type,462 .optional_type,
464 .block,463 .block,
465 .block_semicolon,464 .block_semicolon,
...@@ -732,7 +731,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -732,7 +731,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
732 .string_literal => return stringLiteral(gz, rl, node),731 .string_literal => return stringLiteral(gz, rl, node),
733 .multiline_string_literal => return multilineStringLiteral(gz, rl, node),732 .multiline_string_literal => return multilineStringLiteral(gz, rl, node),
734733
735 .integer_literal => return integerLiteral(gz, rl, node),734 .number_literal => return numberLiteral(gz, rl, node, node, .positive),
736 // zig fmt: on735 // zig fmt: on
737736
738 .builtin_call_two, .builtin_call_two_comma => {737 .builtin_call_two, .builtin_call_two_comma => {
...@@ -773,7 +772,6 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -773,7 +772,6 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
773 },772 },
774 .@"return" => return ret(gz, scope, node),773 .@"return" => return ret(gz, scope, node),
775 .field_access => return fieldAccess(gz, scope, rl, node),774 .field_access => return fieldAccess(gz, scope, rl, node),
776 .float_literal => return floatLiteral(gz, rl, node, .positive),
777775
778 .if_simple => return ifExpr(gz, scope, rl.br(), node, tree.ifSimple(node)),776 .if_simple => return ifExpr(gz, scope, rl.br(), node, tree.ifSimple(node)),
779 .@"if" => return ifExpr(gz, scope, rl.br(), node, tree.ifFull(node)),777 .@"if" => return ifExpr(gz, scope, rl.br(), node, tree.ifFull(node)),
...@@ -7052,93 +7050,101 @@ fn charLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir....@@ -7052,93 +7050,101 @@ fn charLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.
7052 }7050 }
7053}7051}
70547052
7055fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {7053const Sign = enum { negative, positive };
7054
7055fn numberLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index, source_node: Ast.Node.Index, sign: Sign) InnerError!Zir.Inst.Ref {
7056 const astgen = gz.astgen;7056 const astgen = gz.astgen;
7057 const tree = astgen.tree;7057 const tree = astgen.tree;
7058 const main_tokens = tree.nodes.items(.main_token);7058 const main_tokens = tree.nodes.items(.main_token);
7059 const int_token = main_tokens[node];7059 const num_token = main_tokens[node];
7060 const prefixed_bytes = tree.tokenSlice(int_token);7060 const bytes = tree.tokenSlice(num_token);
7061
7062 var base: u8 = 10;
7063 var non_prefixed: []const u8 = prefixed_bytes;
7064 if (mem.startsWith(u8, prefixed_bytes, "0x")) {
7065 base = 16;
7066 non_prefixed = prefixed_bytes[2..];
7067 } else if (mem.startsWith(u8, prefixed_bytes, "0o")) {
7068 base = 8;
7069 non_prefixed = prefixed_bytes[2..];
7070 } else if (mem.startsWith(u8, prefixed_bytes, "0b")) {
7071 base = 2;
7072 non_prefixed = prefixed_bytes[2..];
7073 }
7074
7075 if (base == 10 and prefixed_bytes.len >= 2 and prefixed_bytes[0] == '0') {
7076 return astgen.failNodeNotes(node, "integer literal '{s}' has leading zero", .{prefixed_bytes}, &.{
7077 try astgen.errNoteNode(node, "use '0o' prefix for octal literals", .{}),
7078 });
7079 }
70807061
7081 if (std.fmt.parseUnsigned(u64, non_prefixed, base)) |small_int| {7062 const result: Zir.Inst.Ref = switch (std.zig.parseNumberLiteral(bytes)) {
7082 const result: Zir.Inst.Ref = switch (small_int) {7063 .int => |num| switch (num) {
7083 0 => .zero,7064 0 => .zero,
7084 1 => .one,7065 1 => .one,
7085 else => try gz.addInt(small_int),7066 else => try gz.addInt(num),
7086 };7067 },
7087 return rvalue(gz, rl, result, node);7068 .big_int => |base| big: {
7088 } else |err| switch (err) {7069 const gpa = astgen.gpa;
7089 error.InvalidCharacter => unreachable, // Caught by the parser.7070 var big_int = try std.math.big.int.Managed.init(gpa);
7090 error.Overflow => {},7071 defer big_int.deinit();
7091 }7072 const prefix_offset = @as(u8, 2) * @boolToInt(base != .decimal);
7073 big_int.setString(@enumToInt(base), bytes[prefix_offset..]) catch |err| switch (err) {
7074 error.InvalidCharacter => unreachable, // caught in `parseNumberLiteral`
7075 error.InvalidBase => unreachable, // we only pass 16, 8, 2, see above
7076 error.OutOfMemory => return error.OutOfMemory,
7077 };
70927078
7093 const gpa = astgen.gpa;7079 const limbs = big_int.limbs[0..big_int.len()];
7094 var big_int = try std.math.big.int.Managed.init(gpa);7080 assert(big_int.isPositive());
7095 defer big_int.deinit();7081 break :big try gz.addIntBig(limbs);
7096 big_int.setString(base, non_prefixed) catch |err| switch (err) {7082 },
7097 error.InvalidCharacter => unreachable, // caught by parser7083 .float => {
7098 error.InvalidBase => unreachable, // we only pass 16, 8, 2, see above7084 const unsigned_float_number = std.fmt.parseFloat(f128, bytes) catch |err| switch (err) {
7099 error.OutOfMemory => return error.OutOfMemory,7085 error.InvalidCharacter => unreachable, // validated by tokenizer
7086 };
7087 const float_number = switch (sign) {
7088 .negative => -unsigned_float_number,
7089 .positive => unsigned_float_number,
7090 };
7091 // If the value fits into a f64 without losing any precision, store it that way.
7092 @setFloatMode(.Strict);
7093 const smaller_float = @floatCast(f64, float_number);
7094 const bigger_again: f128 = smaller_float;
7095 if (bigger_again == float_number) {
7096 const result = try gz.addFloat(smaller_float);
7097 return rvalue(gz, rl, result, source_node);
7098 }
7099 // We need to use 128 bits. Break the float into 4 u32 values so we can
7100 // put it into the `extra` array.
7101 const int_bits = @bitCast(u128, float_number);
7102 const result = try gz.addPlNode(.float128, node, Zir.Inst.Float128{
7103 .piece0 = @truncate(u32, int_bits),
7104 .piece1 = @truncate(u32, int_bits >> 32),
7105 .piece2 = @truncate(u32, int_bits >> 64),
7106 .piece3 = @truncate(u32, int_bits >> 96),
7107 });
7108 return rvalue(gz, rl, result, source_node);
7109 },
7110 .failure => |err| return astgen.failWithNumberError(err, num_token, bytes),
7100 };7111 };
71017112
7102 const limbs = big_int.limbs[0..big_int.len()];7113 if (sign == .positive) {
7103 assert(big_int.isPositive());7114 return rvalue(gz, rl, result, source_node);
7104 const result = try gz.addIntBig(limbs);7115 } else {
7105 return rvalue(gz, rl, result, node);7116 const negated = try gz.addUnNode(.negate, result, source_node);
7117 return rvalue(gz, rl, negated, source_node);
7118 }
7106}7119}
71077120
7108const Sign = enum { negative, positive };7121fn failWithNumberError(astgen: *AstGen, err: std.zig.number_literal.Error, token: Ast.TokenIndex, bytes: []const u8) InnerError {
71097122 const is_float = std.mem.indexOfScalar(u8, bytes, '.') != null;
7110fn floatLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index, sign: Sign) InnerError!Zir.Inst.Ref {7123 switch (err) {
7111 const astgen = gz.astgen;7124 .leading_zero => if (is_float) {
7112 const tree = astgen.tree;7125 return astgen.failTok(token, "number '{s}' has leading zero", .{bytes});
7113 const main_tokens = tree.nodes.items(.main_token);7126 } else {
71147127 return astgen.failTokNotes(token, "number '{s}' has leading zero", .{bytes}, &.{
7115 const main_token = main_tokens[node];7128 try astgen.errNoteTok(token, "use '0o' prefix for octal literals", .{}),
7116 const bytes = tree.tokenSlice(main_token);7129 });
7117 const unsigned_float_number = std.fmt.parseFloat(f128, bytes) catch |err| switch (err) {7130 },
7118 error.InvalidCharacter => unreachable, // validated by tokenizer7131 .digit_after_base => return astgen.failTok(token, "expected a digit after base prefix", .{}),
7119 };7132 .upper_case_base => |i| return astgen.failOff(token, @intCast(u32, i), "base prefix must be lowercase", .{}),
7120 const float_number = switch (sign) {7133 .invalid_float_base => |i| return astgen.failOff(token, @intCast(u32, i), "invalid base for float literal", .{}),
7121 .negative => -unsigned_float_number,7134 .repeated_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "repeated digit separator", .{}),
7122 .positive => unsigned_float_number,7135 .invalid_underscore_after_special => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit before digit separator", .{}),
7123 };7136 .invalid_digit => |info| return astgen.failOff(token, @intCast(u32, info.i), "invalid digit '{c}' for {s} base", .{ bytes[info.i], @tagName(info.base) }),
7124 // If the value fits into a f64 without losing any precision, store it that way.7137 .invalid_digit_exponent => |i| return astgen.failOff(token, @intCast(u32, i), "invalid digit '{c}' in exponent", .{bytes[i]}),
7125 @setFloatMode(.Strict);7138 .duplicate_exponent => |i| return astgen.failOff(token, @intCast(u32, i), "duplicate exponent", .{}),
7126 const smaller_float = @floatCast(f64, float_number);7139 .invalid_hex_exponent => |i| return astgen.failOff(token, @intCast(u32, i), "hex exponent in decimal float", .{}),
7127 const bigger_again: f128 = smaller_float;7140 .exponent_after_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit before exponent", .{}),
7128 if (bigger_again == float_number) {7141 .special_after_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit before '{c}'", .{bytes[i]}),
7129 const result = try gz.addFloat(smaller_float);7142 .trailing_special => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit after '{c}'", .{bytes[i - 1]}),
7130 return rvalue(gz, rl, result, node);7143 .trailing_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "trailing digit separator", .{}),
7131 }7144 .duplicate_period => unreachable, // Validated by tokenizer
7132 // We need to use 128 bits. Break the float into 4 u32 values so we can7145 .invalid_character => unreachable, // Validated by tokenizer
7133 // put it into the `extra` array.7146 .invalid_exponent_sign => unreachable, // Validated by tokenizer
7134 const int_bits = @bitCast(u128, float_number);7147 }
7135 const result = try gz.addPlNode(.float128, node, Zir.Inst.Float128{
7136 .piece0 = @truncate(u32, int_bits),
7137 .piece1 = @truncate(u32, int_bits >> 32),
7138 .piece2 = @truncate(u32, int_bits >> 64),
7139 .piece3 = @truncate(u32, int_bits >> 96),
7140 });
7141 return rvalue(gz, rl, result, node);
7142}7148}
71437149
7144fn asmExpr(7150fn asmExpr(
...@@ -8088,8 +8094,8 @@ fn negation(...@@ -8088,8 +8094,8 @@ fn negation(
8088 // Check for float literal as the sub-expression because we want to preserve8094 // Check for float literal as the sub-expression because we want to preserve
8089 // its negativity rather than having it go through comptime subtraction.8095 // its negativity rather than having it go through comptime subtraction.
8090 const operand_node = node_datas[node].lhs;8096 const operand_node = node_datas[node].lhs;
8091 if (node_tags[operand_node] == .float_literal) {8097 if (node_tags[operand_node] == .number_literal) {
8092 return floatLiteral(gz, rl, operand_node, .negative);8098 return numberLiteral(gz, rl, operand_node, node, .negative);
8093 }8099 }
80948100
8095 const operand = try expr(gz, scope, .none, operand_node);8101 const operand = try expr(gz, scope, .none, operand_node);
...@@ -8497,8 +8503,7 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_...@@ -8497,8 +8503,7 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_
8497 .fn_decl,8503 .fn_decl,
8498 .anyframe_type,8504 .anyframe_type,
8499 .anyframe_literal,8505 .anyframe_literal,
8500 .integer_literal,8506 .number_literal,
8501 .float_literal,
8502 .enum_literal,8507 .enum_literal,
8503 .string_literal,8508 .string_literal,
8504 .multiline_string_literal,8509 .multiline_string_literal,
...@@ -8757,8 +8762,7 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev...@@ -8757,8 +8762,7 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
8757 .fn_decl,8762 .fn_decl,
8758 .anyframe_type,8763 .anyframe_type,
8759 .anyframe_literal,8764 .anyframe_literal,
8760 .integer_literal,8765 .number_literal,
8761 .float_literal,
8762 .enum_literal,8766 .enum_literal,
8763 .string_literal,8767 .string_literal,
8764 .multiline_string_literal,8768 .multiline_string_literal,
...@@ -8931,8 +8935,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In...@@ -8931,8 +8935,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In
8931 .@"suspend",8935 .@"suspend",
8932 .fn_decl,8936 .fn_decl,
8933 .anyframe_literal,8937 .anyframe_literal,
8934 .integer_literal,8938 .number_literal,
8935 .float_literal,
8936 .enum_literal,8939 .enum_literal,
8937 .string_literal,8940 .string_literal,
8938 .multiline_string_literal,8941 .multiline_string_literal,
...@@ -9174,8 +9177,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -9174,8 +9177,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
9174 .@"suspend",9177 .@"suspend",
9175 .fn_decl,9178 .fn_decl,
9176 .anyframe_literal,9179 .anyframe_literal,
9177 .integer_literal,9180 .number_literal,
9178 .float_literal,
9179 .enum_literal,9181 .enum_literal,
9180 .string_literal,9182 .string_literal,
9181 .multiline_string_literal,9183 .multiline_string_literal,
src/Compilation.zig+2-2
...@@ -610,7 +610,7 @@ pub const AllErrors = struct {...@@ -610,7 +610,7 @@ pub const AllErrors = struct {
610 }610 }
611 const token_starts = file.tree.tokens.items(.start);611 const token_starts = file.tree.tokens.items(.start);
612 const start = token_starts[item.data.token] + item.data.byte_offset;612 const start = token_starts[item.data.token] + item.data.byte_offset;
613 const end = start + @intCast(u32, file.tree.tokenSlice(item.data.token).len);613 const end = start + @intCast(u32, file.tree.tokenSlice(item.data.token).len) - item.data.byte_offset;
614 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };614 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
615 };615 };
616 const err_loc = std.zig.findLineColumn(file.source, err_span.main);616 const err_loc = std.zig.findLineColumn(file.source, err_span.main);
...@@ -629,7 +629,7 @@ pub const AllErrors = struct {...@@ -629,7 +629,7 @@ pub const AllErrors = struct {
629 }629 }
630 const token_starts = file.tree.tokens.items(.start);630 const token_starts = file.tree.tokens.items(.start);
631 const start = token_starts[note_item.data.token] + note_item.data.byte_offset;631 const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
632 const end = start + @intCast(u32, file.tree.tokenSlice(note_item.data.token).len);632 const end = start + @intCast(u32, file.tree.tokenSlice(note_item.data.token).len) - item.data.byte_offset;
633 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };633 break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
634 };634 };
635 const loc = std.zig.findLineColumn(file.source, span.main);635 const loc = std.zig.findLineColumn(file.source, span.main);
src/autodoc/render_source.zig+1-3
...@@ -316,9 +316,7 @@ pub fn tokenizeAndPrintRaw(...@@ -316,9 +316,7 @@ pub fn tokenizeAndPrintRaw(
316 }316 }
317 },317 },
318318
319 .integer_literal,319 .number_literal => {
320 .float_literal,
321 => {
322 try out.writeAll("<span class=\"tok-number\">");320 try out.writeAll("<span class=\"tok-number\">");
323 try writeEscaped(out, src[token.loc.start..token.loc.end]);321 try writeEscaped(out, src[token.loc.start..token.loc.end]);
324 try out.writeAll("</span>");322 try out.writeAll("</span>");
src/translate_c/ast.zig+26-26
...@@ -934,13 +934,13 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -934,13 +934,13 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
934 .data = undefined,934 .data = undefined,
935 }),935 }),
936 .zero_literal => return c.addNode(.{936 .zero_literal => return c.addNode(.{
937 .tag = .integer_literal,937 .tag = .number_literal,
938 .main_token = try c.addToken(.integer_literal, "0"),938 .main_token = try c.addToken(.number_literal, "0"),
939 .data = undefined,939 .data = undefined,
940 }),940 }),
941 .one_literal => return c.addNode(.{941 .one_literal => return c.addNode(.{
942 .tag = .integer_literal,942 .tag = .number_literal,
943 .main_token = try c.addToken(.integer_literal, "1"),943 .main_token = try c.addToken(.number_literal, "1"),
944 .data = undefined,944 .data = undefined,
945 }),945 }),
946 .void_type => return c.addNode(.{946 .void_type => return c.addNode(.{
...@@ -1074,16 +1074,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1074,16 +1074,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1074 .float_literal => {1074 .float_literal => {
1075 const payload = node.castTag(.float_literal).?.data;1075 const payload = node.castTag(.float_literal).?.data;
1076 return c.addNode(.{1076 return c.addNode(.{
1077 .tag = .float_literal,1077 .tag = .number_literal,
1078 .main_token = try c.addToken(.float_literal, payload),1078 .main_token = try c.addToken(.number_literal, payload),
1079 .data = undefined,1079 .data = undefined,
1080 });1080 });
1081 },1081 },
1082 .integer_literal => {1082 .integer_literal => {
1083 const payload = node.castTag(.integer_literal).?.data;1083 const payload = node.castTag(.integer_literal).?.data;
1084 return c.addNode(.{1084 return c.addNode(.{
1085 .tag = .integer_literal,1085 .tag = .number_literal,
1086 .main_token = try c.addToken(.integer_literal, payload),1086 .main_token = try c.addToken(.number_literal, payload),
1087 .data = undefined,1087 .data = undefined,
1088 });1088 });
1089 },1089 },
...@@ -1137,14 +1137,14 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1137,14 +1137,14 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1137 const string = try renderNode(c, payload.string);1137 const string = try renderNode(c, payload.string);
1138 const l_bracket = try c.addToken(.l_bracket, "[");1138 const l_bracket = try c.addToken(.l_bracket, "[");
1139 const start = try c.addNode(.{1139 const start = try c.addNode(.{
1140 .tag = .integer_literal,1140 .tag = .number_literal,
1141 .main_token = try c.addToken(.integer_literal, "0"),1141 .main_token = try c.addToken(.number_literal, "0"),
1142 .data = undefined,1142 .data = undefined,
1143 });1143 });
1144 _ = try c.addToken(.ellipsis2, "..");1144 _ = try c.addToken(.ellipsis2, "..");
1145 const end = try c.addNode(.{1145 const end = try c.addNode(.{
1146 .tag = .integer_literal,1146 .tag = .number_literal,
1147 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{payload.end}),1147 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{payload.end}),
1148 .data = undefined,1148 .data = undefined,
1149 });1149 });
1150 _ = try c.addToken(.r_bracket, "]");1150 _ = try c.addToken(.r_bracket, "]");
...@@ -1827,8 +1827,8 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1827,8 +1827,8 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1827 .data = .{1827 .data = .{
1828 .lhs = init,1828 .lhs = init,
1829 .rhs = try c.addNode(.{1829 .rhs = try c.addNode(.{
1830 .tag = .integer_literal,1830 .tag = .number_literal,
1831 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{payload.count}),1831 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{payload.count}),
1832 .data = undefined,1832 .data = undefined,
1833 }),1833 }),
1834 },1834 },
...@@ -2039,8 +2039,8 @@ fn renderRecord(c: *Context, node: Node) !NodeIndex {...@@ -2039,8 +2039,8 @@ fn renderRecord(c: *Context, node: Node) !NodeIndex {
2039 _ = try c.addToken(.keyword_align, "align");2039 _ = try c.addToken(.keyword_align, "align");
2040 _ = try c.addToken(.l_paren, "(");2040 _ = try c.addToken(.l_paren, "(");
2041 const align_expr = try c.addNode(.{2041 const align_expr = try c.addNode(.{
2042 .tag = .integer_literal,2042 .tag = .number_literal,
2043 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{alignment}),2043 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{alignment}),
2044 .data = undefined,2044 .data = undefined,
2045 });2045 });
2046 _ = try c.addToken(.r_paren, ")");2046 _ = try c.addToken(.r_paren, ")");
...@@ -2143,8 +2143,8 @@ fn renderArrayInit(c: *Context, lhs: NodeIndex, inits: []const Node) !NodeIndex...@@ -2143,8 +2143,8 @@ fn renderArrayInit(c: *Context, lhs: NodeIndex, inits: []const Node) !NodeIndex
2143fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {2143fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {
2144 const l_bracket = try c.addToken(.l_bracket, "[");2144 const l_bracket = try c.addToken(.l_bracket, "[");
2145 const len_expr = try c.addNode(.{2145 const len_expr = try c.addNode(.{
2146 .tag = .integer_literal,2146 .tag = .number_literal,
2147 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{len}),2147 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{len}),
2148 .data = undefined,2148 .data = undefined,
2149 });2149 });
2150 _ = try c.addToken(.r_bracket, "]");2150 _ = try c.addToken(.r_bracket, "]");
...@@ -2162,15 +2162,15 @@ fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {...@@ -2162,15 +2162,15 @@ fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {
2162fn renderNullSentinelArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {2162fn renderNullSentinelArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {
2163 const l_bracket = try c.addToken(.l_bracket, "[");2163 const l_bracket = try c.addToken(.l_bracket, "[");
2164 const len_expr = try c.addNode(.{2164 const len_expr = try c.addNode(.{
2165 .tag = .integer_literal,2165 .tag = .number_literal,
2166 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{len}),2166 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{len}),
2167 .data = undefined,2167 .data = undefined,
2168 });2168 });
2169 _ = try c.addToken(.colon, ":");2169 _ = try c.addToken(.colon, ":");
21702170
2171 const sentinel_expr = try c.addNode(.{2171 const sentinel_expr = try c.addNode(.{
2172 .tag = .integer_literal,2172 .tag = .number_literal,
2173 .main_token = try c.addToken(.integer_literal, "0"),2173 .main_token = try c.addToken(.number_literal, "0"),
2174 .data = undefined,2174 .data = undefined,
2175 });2175 });
21762176
...@@ -2571,8 +2571,8 @@ fn renderVar(c: *Context, node: Node) !NodeIndex {...@@ -2571,8 +2571,8 @@ fn renderVar(c: *Context, node: Node) !NodeIndex {
2571 _ = try c.addToken(.keyword_align, "align");2571 _ = try c.addToken(.keyword_align, "align");
2572 _ = try c.addToken(.l_paren, "(");2572 _ = try c.addToken(.l_paren, "(");
2573 const res = try c.addNode(.{2573 const res = try c.addNode(.{
2574 .tag = .integer_literal,2574 .tag = .number_literal,
2575 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{some}),2575 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{some}),
2576 .data = undefined,2576 .data = undefined,
2577 });2577 });
2578 _ = try c.addToken(.r_paren, ")");2578 _ = try c.addToken(.r_paren, ")");
...@@ -2655,8 +2655,8 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {...@@ -2655,8 +2655,8 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
2655 _ = try c.addToken(.keyword_align, "align");2655 _ = try c.addToken(.keyword_align, "align");
2656 _ = try c.addToken(.l_paren, "(");2656 _ = try c.addToken(.l_paren, "(");
2657 const res = try c.addNode(.{2657 const res = try c.addNode(.{
2658 .tag = .integer_literal,2658 .tag = .number_literal,
2659 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{some}),2659 .main_token = try c.addTokenFmt(.number_literal, "{d}", .{some}),
2660 .data = undefined,2660 .data = undefined,
2661 });2661 });
2662 _ = try c.addToken(.r_paren, ")");2662 _ = try c.addToken(.r_paren, ")");
test/cases/compile_errors/cast_negative_integer_literal_to_usize.zig+5
...@@ -2,9 +2,14 @@ export fn entry() void {...@@ -2,9 +2,14 @@ export fn entry() void {
2 const x = @as(usize, -10);2 const x = @as(usize, -10);
3 _ = x;3 _ = x;
4}4}
5export fn entry1() void {
6 const x = @as(usize, -10.0);
7 _ = x;
8}
59
6// error10// error
7// backend=stage211// backend=stage2
8// target=native12// target=native
9//13//
10// :2:26: error: type 'usize' cannot represent integer value '-10'14// :2:26: error: type 'usize' cannot represent integer value '-10'
15// :6:26: error: float value '-10' cannot be stored in integer type 'usize'
test/cases/compile_errors/invalid_exponent_in_float_literal-1.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:28: error: invalid digit 'a' in exponent
11// :2:28: note: invalid byte: 'a'
test/cases/compile_errors/invalid_exponent_in_float_literal-2.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:29: error: invalid digit 'F' in exponent
11// :2:29: note: invalid byte: 'F'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-1.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:23: error: expected digit before digit separator
11// :2:23: note: invalid byte: '_'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-10.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:25: error: repeated digit separator
11// :2:25: note: invalid byte: '_'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-11.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:28: error: repeated digit separator
11// :2:28: note: invalid byte: '_'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-12.zig+2-3
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1fn main() void {1fn main() void {
2 var bad: f128 = 0_x0.0;2 var bad: f128 = 1_x0.0;
3 _ = bad;3 _ = bad;
4}4}
55
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:23: error: invalid digit 'x' for decimal base
11// :2:23: note: invalid byte: 'x'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-13.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:23: error: expected digit before digit separator
11// :2:23: note: invalid byte: '_'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-14.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:27: error: expected digit before exponent
11// :2:27: note: invalid byte: 'p'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-2.zig+2-3
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1fn main() void {1fn main() void {
2 var bad: f128 = 0_.0;2 var bad: f128 = 1_.0;
3 _ = bad;3 _ = bad;
4}4}
55
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:23: error: expected digit before '.'
11// :2:23: note: invalid byte: '.'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-3.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:24: error: trailing digit separator
11// :2:25: note: invalid byte: ';'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-4.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:25: error: expected digit before digit separator
11// :2:25: note: invalid byte: '_'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-5.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:26: error: expected digit before digit separator
11// :2:26: note: invalid byte: '_'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-6.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:26: error: expected digit before digit separator
11// :2:26: note: invalid byte: '_'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-7.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:27: error: trailing digit separator
11// :2:28: note: invalid byte: ';'
test/cases/compile_errors/invalid_underscore_placement_in_float_literal-9.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:23: error: repeated digit separator
11// :2:23: note: invalid byte: '_'
test/cases/compile_errors/invalid_underscore_placement_in_int_literal-1.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=llvm7// backend=llvm
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:23: error: trailing digit separator
11// :2:24: note: invalid byte: ';'
test/cases/compile_errors/invalid_underscore_placement_in_int_literal-2.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:27: error: trailing digit separator
11// :2:28: note: invalid byte: ';'
test/cases/compile_errors/invalid_underscore_placement_in_int_literal-3.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:27: error: trailing digit separator
11// :2:28: note: invalid byte: ';'
test/cases/compile_errors/invalid_underscore_placement_in_int_literal-4.zig+1-2
...@@ -7,5 +7,4 @@ fn main() void {...@@ -7,5 +7,4 @@ fn main() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:27: error: trailing digit separator
11// :2:28: note: invalid byte: ';'
test/cases/compile_errors/leading_zero_in_integer.zig+2-2
...@@ -21,7 +21,7 @@ export fn entry4() void {...@@ -21,7 +21,7 @@ export fn entry4() void {
21//21//
22// :2:15: error: primitive integer type 'u000123' has leading zero22// :2:15: error: primitive integer type 'u000123' has leading zero
23// :8:12: error: primitive integer type 'i01' has leading zero23// :8:12: error: primitive integer type 'i01' has leading zero
24// :12:9: error: integer literal '000123' has leading zero24// :12:9: error: number '000123' has leading zero
25// :12:9: note: use '0o' prefix for octal literals25// :12:9: note: use '0o' prefix for octal literals
26// :15:9: error: integer literal '01' has leading zero26// :15:9: error: number '01' has leading zero
27// :15:9: note: use '0o' prefix for octal literals27// :15:9: note: use '0o' prefix for octal literals
test/cases/compile_errors/missing_digit_after_base.zig created+10
...@@ -0,0 +1,10 @@
1export fn entry() void {
2 const x = @as(usize, -0x);
3 _ = x;
4}
5
6// error
7// backend=stage2
8// target=native
9//
10// :2:27: error: expected a digit after base prefix
test/compare_output.zig+1-1
...@@ -75,7 +75,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -75,7 +75,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
75 \\ _ = c.printf("0.0e0: %.013a\n",75 \\ _ = c.printf("0.0e0: %.013a\n",
76 \\ @as(f64, 0.0e0));76 \\ @as(f64, 0.0e0));
77 \\ _ = c.printf("000000000000000000000000000000000000000000000000000000000.0e0: %.013a\n",77 \\ _ = c.printf("000000000000000000000000000000000000000000000000000000000.0e0: %.013a\n",
78 \\ @as(f64, 000000000000000000000000000000000000000000000000000000000.0e0));78 \\ @as(f64, 0.0e0));
79 \\ _ = c.printf("0.000000000000000000000000000000000000000000000000000000000e0: %.013a\n",79 \\ _ = c.printf("0.000000000000000000000000000000000000000000000000000000000e0: %.013a\n",
80 \\ @as(f64, 0.000000000000000000000000000000000000000000000000000000000e0));80 \\ @as(f64, 0.000000000000000000000000000000000000000000000000000000000e0));
81 \\ _ = c.printf("0.0e000000000000000000000000000000000000000000000000000000000: %.013a\n",81 \\ _ = c.printf("0.0e000000000000000000000000000000000000000000000000000000000: %.013a\n",