| author | |
| committer | |
| log | ca9e1760e8e33d17f44835d93103b940873417cf |
| tree | d4d91760c89558bbb3ee3bcd6f49238dcb80d3bd |
| parent | d6d4f2481d590eaca6372b1ded00cea2d869aabc |
9 files changed, 731 insertions(+), 91 deletions(-)
lib/std/zig.zig+1| ... | ... | @@ -11,6 +11,7 @@ pub const isValidId = fmt.isValidId; |
| 11 | 11 | pub const parse = @import("zig/parse.zig").parse; |
| 12 | 12 | pub const string_literal = @import("zig/string_literal.zig"); |
| 13 | 13 | pub const number_literal = @import("zig/number_literal.zig"); |
| 14 | pub const primitives = @import("zig/primitives.zig"); | |
| 14 | 15 | pub const Ast = @import("zig/Ast.zig"); |
| 15 | 16 | pub const system = @import("zig/system.zig"); |
| 16 | 17 | pub const CrossTarget = @import("zig/CrossTarget.zig"); |
lib/std/zig/parser_test.zig+376| ... | ... | @@ -5198,6 +5198,382 @@ test "zig fmt: while continue expr" { |
| 5198 | 5198 | }); |
| 5199 | 5199 | } |
| 5200 | 5200 | |
| 5201 | test "zig fmt: canonicalize symbols (simple)" { | |
| 5202 | try testTransform( | |
| 5203 | \\const val_normal: Normal = .{}; | |
| 5204 | \\const @"val_unesc_me": @"UnescMe" = .{}; | |
| 5205 | \\const @"val_esc!": @"Esc!" = .{}; | |
| 5206 | \\ | |
| 5207 | \\fn fnNormal() void {} | |
| 5208 | \\fn @"fnUnescMe"() void {} | |
| 5209 | \\fn @"fnEsc!"() void {} | |
| 5210 | \\ | |
| 5211 | \\extern fn protoNormal() void; | |
| 5212 | \\extern fn @"protoUnescMe"() void; | |
| 5213 | \\extern fn @"protoEsc!"() void; | |
| 5214 | \\ | |
| 5215 | \\fn fnWithArgs(normal: Normal, @"unesc_me": @"UnescMe", @"esc!": @"Esc!") void { | |
| 5216 | \\ _ = normal; | |
| 5217 | \\ _ = @"unesc_me"; | |
| 5218 | \\ _ = @"esc!"; | |
| 5219 | \\} | |
| 5220 | \\ | |
| 5221 | \\const Normal = struct {}; | |
| 5222 | \\const @"UnescMe" = struct { | |
| 5223 | \\ @"x": @"X", | |
| 5224 | \\ const X = union(@"EnumUnesc") { | |
| 5225 | \\ normal, | |
| 5226 | \\ @"unesc_me", | |
| 5227 | \\ @"esc!", | |
| 5228 | \\ }; | |
| 5229 | \\ const @"EnumUnesc" = enum { | |
| 5230 | \\ normal, | |
| 5231 | \\ @"unesc_me", | |
| 5232 | \\ @"esc!", | |
| 5233 | \\ }; | |
| 5234 | \\}; | |
| 5235 | \\const @"Esc!" = struct { | |
| 5236 | \\ normal: bool = false, | |
| 5237 | \\ @"unesc_me": bool = false, | |
| 5238 | \\ @"esc!": bool = false, | |
| 5239 | \\}; | |
| 5240 | \\ | |
| 5241 | \\pub fn main() void { | |
| 5242 | \\ _ = val_normal; | |
| 5243 | \\ _ = @"val_normal"; | |
| 5244 | \\ _ = val_unesc_me; | |
| 5245 | \\ _ = @"val_unesc_me"; | |
| 5246 | \\ _ = @"val_esc!"; | |
| 5247 | \\ | |
| 5248 | \\ fnNormal(); | |
| 5249 | \\ @"fnNormal"(); | |
| 5250 | \\ fnUnescMe(); | |
| 5251 | \\ @"fnUnescMe"(); | |
| 5252 | \\ @"fnEsc!"(); | |
| 5253 | \\ | |
| 5254 | \\ fnWithArgs(1, Normal{}, UnescMe{}, @"Esc!"{}); | |
| 5255 | \\ fnWithArgs(1, @"Normal"{}, @"UnescMe"{}, @"Esc!"{}); | |
| 5256 | \\ fnWithArgs(1, @"Normal"{}, @"Normal"{}, @"Esc!"{}); | |
| 5257 | \\ | |
| 5258 | \\ const local_val1: @"Normal" = .{}; | |
| 5259 | \\ const @"local_val2": UnescMe = .{ | |
| 5260 | \\ .@"x" = .@"unesc_me", | |
| 5261 | \\ }; | |
| 5262 | \\ fnWithArgs(@"local_val1", @"local_val2", .{ .@"normal" = true, .@"unesc_me" = true, .@"esc!" = true }); | |
| 5263 | \\ fnWithArgs(local_val1, local_val2, .{ .normal = true, .unesc_me = true, .@"esc!" = true }); | |
| 5264 | \\ | |
| 5265 | \\ var x: u8 = 'x'; | |
| 5266 | \\ switch (@"x") { | |
| 5267 | \\ @"x" => {}, | |
| 5268 | \\ } | |
| 5269 | \\ | |
| 5270 | \\ _ = @import("std"); // Don't mess with @builtins | |
| 5271 | \\ // @"comment" | |
| 5272 | \\} | |
| 5273 | \\ | |
| 5274 | , | |
| 5275 | \\const val_normal: Normal = .{}; | |
| 5276 | \\const val_unesc_me: UnescMe = .{}; | |
| 5277 | \\const @"val_esc!": @"Esc!" = .{}; | |
| 5278 | \\ | |
| 5279 | \\fn fnNormal() void {} | |
| 5280 | \\fn fnUnescMe() void {} | |
| 5281 | \\fn @"fnEsc!"() void {} | |
| 5282 | \\ | |
| 5283 | \\extern fn protoNormal() void; | |
| 5284 | \\extern fn protoUnescMe() void; | |
| 5285 | \\extern fn @"protoEsc!"() void; | |
| 5286 | \\ | |
| 5287 | \\fn fnWithArgs(normal: Normal, unesc_me: UnescMe, @"esc!": @"Esc!") void { | |
| 5288 | \\ _ = normal; | |
| 5289 | \\ _ = unesc_me; | |
| 5290 | \\ _ = @"esc!"; | |
| 5291 | \\} | |
| 5292 | \\ | |
| 5293 | \\const Normal = struct {}; | |
| 5294 | \\const UnescMe = struct { | |
| 5295 | \\ x: X, | |
| 5296 | \\ const X = union(EnumUnesc) { | |
| 5297 | \\ normal, | |
| 5298 | \\ unesc_me, | |
| 5299 | \\ @"esc!", | |
| 5300 | \\ }; | |
| 5301 | \\ const EnumUnesc = enum { | |
| 5302 | \\ normal, | |
| 5303 | \\ unesc_me, | |
| 5304 | \\ @"esc!", | |
| 5305 | \\ }; | |
| 5306 | \\}; | |
| 5307 | \\const @"Esc!" = struct { | |
| 5308 | \\ normal: bool = false, | |
| 5309 | \\ unesc_me: bool = false, | |
| 5310 | \\ @"esc!": bool = false, | |
| 5311 | \\}; | |
| 5312 | \\ | |
| 5313 | \\pub fn main() void { | |
| 5314 | \\ _ = val_normal; | |
| 5315 | \\ _ = val_normal; | |
| 5316 | \\ _ = val_unesc_me; | |
| 5317 | \\ _ = val_unesc_me; | |
| 5318 | \\ _ = @"val_esc!"; | |
| 5319 | \\ | |
| 5320 | \\ fnNormal(); | |
| 5321 | \\ fnNormal(); | |
| 5322 | \\ fnUnescMe(); | |
| 5323 | \\ fnUnescMe(); | |
| 5324 | \\ @"fnEsc!"(); | |
| 5325 | \\ | |
| 5326 | \\ fnWithArgs(1, Normal{}, UnescMe{}, @"Esc!"{}); | |
| 5327 | \\ fnWithArgs(1, Normal{}, UnescMe{}, @"Esc!"{}); | |
| 5328 | \\ fnWithArgs(1, Normal{}, Normal{}, @"Esc!"{}); | |
| 5329 | \\ | |
| 5330 | \\ const local_val1: Normal = .{}; | |
| 5331 | \\ const local_val2: UnescMe = .{ | |
| 5332 | \\ .x = .unesc_me, | |
| 5333 | \\ }; | |
| 5334 | \\ fnWithArgs(local_val1, local_val2, .{ .normal = true, .unesc_me = true, .@"esc!" = true }); | |
| 5335 | \\ fnWithArgs(local_val1, local_val2, .{ .normal = true, .unesc_me = true, .@"esc!" = true }); | |
| 5336 | \\ | |
| 5337 | \\ var x: u8 = 'x'; | |
| 5338 | \\ switch (x) { | |
| 5339 | \\ x => {}, | |
| 5340 | \\ } | |
| 5341 | \\ | |
| 5342 | \\ _ = @import("std"); // Don't mess with @builtins | |
| 5343 | \\ // @"comment" | |
| 5344 | \\} | |
| 5345 | \\ | |
| 5346 | ); | |
| 5347 | } | |
| 5348 | ||
| 5349 | // Contextually unescape when shadowing primitive types and values. | |
| 5350 | test "zig fmt: canonicalize symbols (primitive types)" { | |
| 5351 | try testTransform( | |
| 5352 | \\const @"anyopaque" = struct { | |
| 5353 | \\ @"u8": @"type" = true, | |
| 5354 | \\ @"_": @"false" = @"true", | |
| 5355 | \\ const @"type" = bool; | |
| 5356 | \\ const @"false" = bool; | |
| 5357 | \\ const @"true" = false; | |
| 5358 | \\}; | |
| 5359 | \\ | |
| 5360 | \\const U = union(@"null") { | |
| 5361 | \\ @"type", | |
| 5362 | \\ const @"null" = enum { | |
| 5363 | \\ @"type", | |
| 5364 | \\ }; | |
| 5365 | \\}; | |
| 5366 | \\ | |
| 5367 | \\test { | |
| 5368 | \\ const E = enum { @"anyopaque" }; | |
| 5369 | \\ _ = U{ .@"type" = {} }; | |
| 5370 | \\ _ = U.@"type"; | |
| 5371 | \\ _ = E.@"anyopaque"; | |
| 5372 | \\} | |
| 5373 | \\ | |
| 5374 | \\fn @"i10"(@"void": @"anyopaque", @"type": @"anyopaque".@"type") error{@"null"}!void { | |
| 5375 | \\ var @"f32" = @"void"; | |
| 5376 | \\ @"f32".@"u8" = false; | |
| 5377 | \\ _ = @"type"; | |
| 5378 | \\ _ = type; | |
| 5379 | \\ if (@"f32".@"u8") { | |
| 5380 | \\ return @"i10"(.{ .@"u8" = true, .@"_" = false }, false); | |
| 5381 | \\ } else { | |
| 5382 | \\ return error.@"null"; | |
| 5383 | \\ } | |
| 5384 | \\} | |
| 5385 | \\ | |
| 5386 | \\test @"i10" { | |
| 5387 | \\ try @"i10"(.{}, true); | |
| 5388 | \\ _ = @"void": while (null) |@"u3"| { | |
| 5389 | \\ break :@"void" @"u3"; | |
| 5390 | \\ }; | |
| 5391 | \\ _ = @"void": { | |
| 5392 | \\ break :@"void"; | |
| 5393 | \\ }; | |
| 5394 | \\ for ("hi") |@"u3", @"i4"| { | |
| 5395 | \\ _ = @"u3"; | |
| 5396 | \\ _ = @"i4"; | |
| 5397 | \\ } | |
| 5398 | \\ if (false) {} else |@"bool"| { | |
| 5399 | \\ _ = @"bool"; | |
| 5400 | \\ } | |
| 5401 | \\} | |
| 5402 | \\ | |
| 5403 | , | |
| 5404 | \\const @"anyopaque" = struct { | |
| 5405 | \\ u8: @"type" = true, | |
| 5406 | \\ _: @"false" = @"true", | |
| 5407 | \\ const @"type" = bool; | |
| 5408 | \\ const @"false" = bool; | |
| 5409 | \\ const @"true" = false; | |
| 5410 | \\}; | |
| 5411 | \\ | |
| 5412 | \\const U = union(@"null") { | |
| 5413 | \\ type, | |
| 5414 | \\ const @"null" = enum { | |
| 5415 | \\ type, | |
| 5416 | \\ }; | |
| 5417 | \\}; | |
| 5418 | \\ | |
| 5419 | \\test { | |
| 5420 | \\ const E = enum { anyopaque }; | |
| 5421 | \\ _ = U{ .type = {} }; | |
| 5422 | \\ _ = U.type; | |
| 5423 | \\ _ = E.anyopaque; | |
| 5424 | \\} | |
| 5425 | \\ | |
| 5426 | \\fn @"i10"(@"void": @"anyopaque", @"type": @"anyopaque".type) error{null}!void { | |
| 5427 | \\ var @"f32" = @"void"; | |
| 5428 | \\ @"f32".u8 = false; | |
| 5429 | \\ _ = @"type"; | |
| 5430 | \\ _ = type; | |
| 5431 | \\ if (@"f32".u8) { | |
| 5432 | \\ return @"i10"(.{ .u8 = true, ._ = false }, false); | |
| 5433 | \\ } else { | |
| 5434 | \\ return error.null; | |
| 5435 | \\ } | |
| 5436 | \\} | |
| 5437 | \\ | |
| 5438 | \\test @"i10" { | |
| 5439 | \\ try @"i10"(.{}, true); | |
| 5440 | \\ _ = void: while (null) |@"u3"| { | |
| 5441 | \\ break :void @"u3"; | |
| 5442 | \\ }; | |
| 5443 | \\ _ = void: { | |
| 5444 | \\ break :void; | |
| 5445 | \\ }; | |
| 5446 | \\ for ("hi") |@"u3", @"i4"| { | |
| 5447 | \\ _ = @"u3"; | |
| 5448 | \\ _ = @"i4"; | |
| 5449 | \\ } | |
| 5450 | \\ if (false) {} else |@"bool"| { | |
| 5451 | \\ _ = @"bool"; | |
| 5452 | \\ } | |
| 5453 | \\} | |
| 5454 | \\ | |
| 5455 | ); | |
| 5456 | } | |
| 5457 | ||
| 5458 | // Never unescape names spelled like keywords. | |
| 5459 | test "zig fmt: canonicalize symbols (keywords)" { | |
| 5460 | try testCanonical( | |
| 5461 | \\const @"enum" = struct { | |
| 5462 | \\ @"error": @"struct" = true, | |
| 5463 | \\ const @"struct" = bool; | |
| 5464 | \\}; | |
| 5465 | \\ | |
| 5466 | \\fn @"usingnamespace"(@"union": @"enum") error{@"try"}!void { | |
| 5467 | \\ var @"struct" = @"union"; | |
| 5468 | \\ @"struct".@"error" = false; | |
| 5469 | \\ if (@"struct".@"error") { | |
| 5470 | \\ return @"usingnamespace"(.{ .@"error" = false }); | |
| 5471 | \\ } else { | |
| 5472 | \\ return error.@"try"; | |
| 5473 | \\ } | |
| 5474 | \\} | |
| 5475 | \\ | |
| 5476 | \\test @"usingnamespace" { | |
| 5477 | \\ try @"usingnamespace"(.{}); | |
| 5478 | \\ _ = @"return": { | |
| 5479 | \\ break :@"return" 4; | |
| 5480 | \\ }; | |
| 5481 | \\} | |
| 5482 | \\ | |
| 5483 | ); | |
| 5484 | } | |
| 5485 | ||
| 5486 | // Normalize \xNN and \u{NN} escapes and unicode inside @"" escapes. | |
| 5487 | test "zig fmt: canonicalize symbols (character escapes)" { | |
| 5488 | try testTransform( | |
| 5489 | \\const @"\x46\x6f\x6f\x64" = struct { | |
| 5490 | \\ @"\x62\x61\x72\x6E": @"\x43\x72\x61\x62" = false, | |
| 5491 | \\ @"\u{67}\u{6C}o\u{70}\xFF": @"Cra\x62" = false, | |
| 5492 | \\ @"\x65\x72\x72\x6F\x72": Crab = true, | |
| 5493 | \\ @"\x74\x72\x79": Crab = true, | |
| 5494 | \\ @"\u{74}\u{79}\u{70}\u{65}": @"any\u{6F}\u{70}\u{61}\u{71}\u{75}\u{65}", | |
| 5495 | \\ | |
| 5496 | \\ const @"\x43\x72\x61\x62" = bool; | |
| 5497 | \\ const @"\x61\x6E\x79\x6F\x70\x61que" = void; | |
| 5498 | \\}; | |
| 5499 | \\ | |
| 5500 | \\test "unicode" { | |
| 5501 | \\ const @"cąbbäge ⚡" = 2; | |
| 5502 | \\ _ = @"cąbbäge ⚡"; | |
| 5503 | \\ const @"\u{01f422} friend\u{f6}" = 4; | |
| 5504 | \\ _ = @"🐢 friendö"; | |
| 5505 | \\} | |
| 5506 | \\ | |
| 5507 | , | |
| 5508 | \\const Food = struct { | |
| 5509 | \\ barn: Crab = false, | |
| 5510 | \\ @"glop\xFF": Crab = false, | |
| 5511 | \\ @"error": Crab = true, | |
| 5512 | \\ @"try": Crab = true, | |
| 5513 | \\ type: @"anyopaque", | |
| 5514 | \\ | |
| 5515 | \\ const Crab = bool; | |
| 5516 | \\ const @"anyopaque" = void; | |
| 5517 | \\}; | |
| 5518 | \\ | |
| 5519 | \\test "unicode" { | |
| 5520 | \\ const @"cąbbäge ⚡" = 2; | |
| 5521 | \\ _ = @"cąbbäge ⚡"; | |
| 5522 | \\ const @"\u{01f422} friend\u{f6}" = 4; | |
| 5523 | \\ _ = @"🐢 friendö"; | |
| 5524 | \\} | |
| 5525 | \\ | |
| 5526 | ); | |
| 5527 | } | |
| 5528 | ||
| 5529 | test "zig fmt: canonicalize symbols (asm)" { | |
| 5530 | try testTransform( | |
| 5531 | \\test "asm" { | |
| 5532 | \\ const @"null" = usize; | |
| 5533 | \\ const @"try": usize = 808; | |
| 5534 | \\ const arg: usize = 2; | |
| 5535 | \\ _ = asm volatile ("syscall" | |
| 5536 | \\ : [@"void"] "={rax}" (-> @"null"), | |
| 5537 | \\ : [@"error"] "{rax}" (@"try"), | |
| 5538 | \\ [@"arg1"] "{rdi}" (arg), | |
| 5539 | \\ [arg2] "{rsi}" (arg), | |
| 5540 | \\ [arg3] "{rdx}" (arg), | |
| 5541 | \\ : "rcx", "r11" | |
| 5542 | \\ ); | |
| 5543 | \\ | |
| 5544 | \\ const @"false": usize = 10; | |
| 5545 | \\ const @"true" = "explode"; | |
| 5546 | \\ _ = asm volatile (@"true" | |
| 5547 | \\ : [one] "={rax}" (@"false"), | |
| 5548 | \\ : [two] "{rax}" (@"false"), | |
| 5549 | \\ ); | |
| 5550 | \\} | |
| 5551 | \\ | |
| 5552 | , | |
| 5553 | \\test "asm" { | |
| 5554 | \\ const @"null" = usize; | |
| 5555 | \\ const @"try": usize = 808; | |
| 5556 | \\ const arg: usize = 2; | |
| 5557 | \\ _ = asm volatile ("syscall" | |
| 5558 | \\ : [void] "={rax}" (-> @"null"), | |
| 5559 | \\ : [@"error"] "{rax}" (@"try"), | |
| 5560 | \\ [arg1] "{rdi}" (arg), | |
| 5561 | \\ [arg2] "{rsi}" (arg), | |
| 5562 | \\ [arg3] "{rdx}" (arg), | |
| 5563 | \\ : "rcx", "r11" | |
| 5564 | \\ ); | |
| 5565 | \\ | |
| 5566 | \\ const @"false": usize = 10; | |
| 5567 | \\ const @"true" = "explode"; | |
| 5568 | \\ _ = asm volatile (@"true" | |
| 5569 | \\ : [one] "={rax}" (false), | |
| 5570 | \\ : [two] "{rax}" (@"false"), | |
| 5571 | \\ ); | |
| 5572 | \\} | |
| 5573 | \\ | |
| 5574 | ); | |
| 5575 | } | |
| 5576 | ||
| 5201 | 5577 | test "zig fmt: error for missing sentinel value in sentinel slice" { |
| 5202 | 5578 | try testError( |
| 5203 | 5579 | \\const foo = foo[0..:]; |
lib/std/zig/primitives.zig created+63| ... | ... | @@ -0,0 +1,63 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | /// Set of primitive type and value names. | |
| 4 | /// Does not include `_` or integer type names. | |
| 5 | pub const names = std.ComptimeStringMap(void, .{ | |
| 6 | .{"anyerror"}, | |
| 7 | .{"anyframe"}, | |
| 8 | .{"anyopaque"}, | |
| 9 | .{"bool"}, | |
| 10 | .{"c_int"}, | |
| 11 | .{"c_long"}, | |
| 12 | .{"c_longdouble"}, | |
| 13 | .{"c_longlong"}, | |
| 14 | .{"c_short"}, | |
| 15 | .{"c_uint"}, | |
| 16 | .{"c_ulong"}, | |
| 17 | .{"c_ulonglong"}, | |
| 18 | .{"c_ushort"}, | |
| 19 | .{"comptime_float"}, | |
| 20 | .{"comptime_int"}, | |
| 21 | .{"f128"}, | |
| 22 | .{"f16"}, | |
| 23 | .{"f32"}, | |
| 24 | .{"f64"}, | |
| 25 | .{"f80"}, | |
| 26 | .{"false"}, | |
| 27 | .{"isize"}, | |
| 28 | .{"noreturn"}, | |
| 29 | .{"null"}, | |
| 30 | .{"true"}, | |
| 31 | .{"type"}, | |
| 32 | .{"undefined"}, | |
| 33 | .{"usize"}, | |
| 34 | .{"void"}, | |
| 35 | }); | |
| 36 | ||
| 37 | /// Returns true if a name matches a primitive type or value, excluding `_`. | |
| 38 | /// Integer type names like `u8` or `i32` are only matched for syntax, | |
| 39 | /// so this will still return true when they have an oversized bit count | |
| 40 | /// or leading zeroes. | |
| 41 | pub fn isPrimitive(name: []const u8) bool { | |
| 42 | if (names.get(name) != null) return true; | |
| 43 | if (name.len < 2) return false; | |
| 44 | const first_c = name[0]; | |
| 45 | if (first_c != 'i' and first_c != 'u') return false; | |
| 46 | for (name[1..]) |c| switch (c) { | |
| 47 | '0'...'9' => {}, | |
| 48 | else => return false, | |
| 49 | }; | |
| 50 | return true; | |
| 51 | } | |
| 52 | ||
| 53 | test "isPrimitive" { | |
| 54 | const expect = std.testing.expect; | |
| 55 | try expect(!isPrimitive("")); | |
| 56 | try expect(!isPrimitive("_")); | |
| 57 | try expect(!isPrimitive("haberdasher")); | |
| 58 | try expect(isPrimitive("bool")); | |
| 59 | try expect(isPrimitive("false")); | |
| 60 | try expect(isPrimitive("comptime_float")); | |
| 61 | try expect(isPrimitive("u1")); | |
| 62 | try expect(isPrimitive("i99999999999999")); | |
| 63 | } |
lib/std/zig/render.zig+207-40| ... | ... | @@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator; |
| 5 | 5 | const meta = std.meta; |
| 6 | 6 | const Ast = std.zig.Ast; |
| 7 | 7 | const Token = std.zig.Token; |
| 8 | const primitives = std.zig.primitives; | |
| 8 | 9 | |
| 9 | 10 | const indent_delta = 4; |
| 10 | 11 | const asm_indent_delta = 2; |
| ... | ... | @@ -152,8 +153,10 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac |
| 152 | 153 | const test_token = main_tokens[decl]; |
| 153 | 154 | try renderToken(ais, tree, test_token, .space); |
| 154 | 155 | const test_name_tag = token_tags[test_token + 1]; |
| 155 | if (test_name_tag == .string_literal or test_name_tag == .identifier) { | |
| 156 | try renderToken(ais, tree, test_token + 1, .space); | |
| 156 | switch (test_name_tag) { | |
| 157 | .string_literal => try renderToken(ais, tree, test_token + 1, .space), | |
| 158 | .identifier => try renderIdentifier(ais, tree, test_token + 1, .space, .preserve_when_shadowing), | |
| 159 | else => {}, | |
| 157 | 160 | } |
| 158 | 161 | try renderExpression(gpa, ais, tree, datas[decl].rhs, space); |
| 159 | 162 | }, |
| ... | ... | @@ -192,11 +195,10 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 192 | 195 | const lexeme = tokenSliceForRender(tree, token_index); |
| 193 | 196 | if (mem.eql(u8, lexeme, "c_void")) { |
| 194 | 197 | try ais.writer().writeAll("anyopaque"); |
| 198 | return renderSpace(ais, tree, token_index, lexeme.len, space); | |
| 195 | 199 | } else { |
| 196 | try ais.writer().writeAll(lexeme); | |
| 200 | return renderIdentifier(ais, tree, token_index, space, .preserve_when_shadowing); | |
| 197 | 201 | } |
| 198 | ||
| 199 | return renderSpace(ais, tree, token_index, lexeme.len, space); | |
| 200 | 202 | }, |
| 201 | 203 | |
| 202 | 204 | .number_literal, |
| ... | ... | @@ -226,7 +228,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 226 | 228 | .error_value => { |
| 227 | 229 | try renderToken(ais, tree, main_tokens[node], .none); |
| 228 | 230 | try renderToken(ais, tree, main_tokens[node] + 1, .none); |
| 229 | return renderToken(ais, tree, main_tokens[node] + 2, space); | |
| 231 | return renderIdentifier(ais, tree, main_tokens[node] + 2, space, .eagerly_unquote); | |
| 230 | 232 | }, |
| 231 | 233 | |
| 232 | 234 | .block_two, |
| ... | ... | @@ -256,7 +258,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 256 | 258 | try renderToken(ais, tree, defer_token, .space); |
| 257 | 259 | if (payload_token != 0) { |
| 258 | 260 | try renderToken(ais, tree, payload_token - 1, .none); // | |
| 259 | try renderToken(ais, tree, payload_token, .none); // identifier | |
| 261 | try renderIdentifier(ais, tree, payload_token, .none, .preserve_when_shadowing); // identifier | |
| 260 | 262 | try renderToken(ais, tree, payload_token + 1, .space); // | |
| 261 | 263 | } |
| 262 | 264 | return renderExpression(gpa, ais, tree, expr, space); |
| ... | ... | @@ -294,7 +296,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 294 | 296 | if (token_tags[fallback_first - 1] == .pipe) { |
| 295 | 297 | try renderToken(ais, tree, main_token, .space); // catch keyword |
| 296 | 298 | try renderToken(ais, tree, main_token + 1, .none); // pipe |
| 297 | try renderToken(ais, tree, main_token + 2, .none); // payload identifier | |
| 299 | try renderIdentifier(ais, tree, main_token + 2, .none, .preserve_when_shadowing); // payload identifier | |
| 298 | 300 | try renderToken(ais, tree, main_token + 3, after_op_space); // pipe |
| 299 | 301 | } else { |
| 300 | 302 | assert(token_tags[fallback_first - 1] == .keyword_catch); |
| ... | ... | @@ -320,7 +322,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 320 | 322 | ais.pushIndentOneShot(); |
| 321 | 323 | } |
| 322 | 324 | |
| 323 | try renderToken(ais, tree, main_token, .none); | |
| 325 | try renderToken(ais, tree, main_token, .none); // . | |
| 324 | 326 | |
| 325 | 327 | // This check ensures that zag() is indented in the following example: |
| 326 | 328 | // const x = foo |
| ... | ... | @@ -331,7 +333,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 331 | 333 | ais.pushIndentOneShot(); |
| 332 | 334 | } |
| 333 | 335 | |
| 334 | return renderToken(ais, tree, field_access.rhs, space); | |
| 336 | return renderIdentifier(ais, tree, field_access.rhs, space, .eagerly_unquote); // field | |
| 335 | 337 | }, |
| 336 | 338 | |
| 337 | 339 | .error_union, |
| ... | ... | @@ -514,11 +516,11 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 514 | 516 | } else if (label_token != 0 and target == 0) { |
| 515 | 517 | try renderToken(ais, tree, main_token, .space); // break keyword |
| 516 | 518 | try renderToken(ais, tree, label_token - 1, .none); // colon |
| 517 | try renderToken(ais, tree, label_token, space); // identifier | |
| 519 | try renderIdentifier(ais, tree, label_token, space, .eagerly_unquote); // identifier | |
| 518 | 520 | } else if (label_token != 0 and target != 0) { |
| 519 | 521 | try renderToken(ais, tree, main_token, .space); // break keyword |
| 520 | 522 | try renderToken(ais, tree, label_token - 1, .none); // colon |
| 521 | try renderToken(ais, tree, label_token, .space); // identifier | |
| 523 | try renderIdentifier(ais, tree, label_token, .space, .eagerly_unquote); // identifier | |
| 522 | 524 | try renderExpression(gpa, ais, tree, target, space); |
| 523 | 525 | } |
| 524 | 526 | }, |
| ... | ... | @@ -529,7 +531,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 529 | 531 | if (label != 0) { |
| 530 | 532 | try renderToken(ais, tree, main_token, .space); // continue |
| 531 | 533 | try renderToken(ais, tree, label - 1, .none); // : |
| 532 | return renderToken(ais, tree, label, space); // label | |
| 534 | return renderIdentifier(ais, tree, label, space, .eagerly_unquote); // label | |
| 533 | 535 | } else { |
| 534 | 536 | return renderToken(ais, tree, main_token, space); // continue |
| 535 | 537 | } |
| ... | ... | @@ -590,7 +592,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 590 | 592 | // There is exactly one member and no trailing comma or |
| 591 | 593 | // comments, so render without surrounding spaces: `error{Foo}` |
| 592 | 594 | try renderToken(ais, tree, lbrace, .none); |
| 593 | try renderToken(ais, tree, lbrace + 1, .none); // identifier | |
| 595 | try renderIdentifier(ais, tree, lbrace + 1, .none, .eagerly_unquote); // identifier | |
| 594 | 596 | return renderToken(ais, tree, rbrace, space); |
| 595 | 597 | } else if (token_tags[rbrace - 1] == .comma) { |
| 596 | 598 | // There is a trailing comma so render each member on a new line. |
| ... | ... | @@ -601,7 +603,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 601 | 603 | if (i > lbrace + 1) try renderExtraNewlineToken(ais, tree, i); |
| 602 | 604 | switch (token_tags[i]) { |
| 603 | 605 | .doc_comment => try renderToken(ais, tree, i, .newline), |
| 604 | .identifier => try renderToken(ais, tree, i, .comma), | |
| 606 | .identifier => try renderIdentifier(ais, tree, i, .comma, .eagerly_unquote), | |
| 605 | 607 | .comma => {}, |
| 606 | 608 | else => unreachable, |
| 607 | 609 | } |
| ... | ... | @@ -615,7 +617,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 615 | 617 | while (i < rbrace) : (i += 1) { |
| 616 | 618 | switch (token_tags[i]) { |
| 617 | 619 | .doc_comment => unreachable, // TODO |
| 618 | .identifier => try renderToken(ais, tree, i, .comma_space), | |
| 620 | .identifier => try renderIdentifier(ais, tree, i, .comma_space, .eagerly_unquote), | |
| 619 | 621 | .comma => {}, |
| 620 | 622 | else => unreachable, |
| 621 | 623 | } |
| ... | ... | @@ -702,7 +704,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, |
| 702 | 704 | |
| 703 | 705 | .enum_literal => { |
| 704 | 706 | try renderToken(ais, tree, main_tokens[node] - 1, .none); // . |
| 705 | return renderToken(ais, tree, main_tokens[node], space); // name | |
| 707 | return renderIdentifier(ais, tree, main_tokens[node], space, .eagerly_unquote); // name | |
| 706 | 708 | }, |
| 707 | 709 | |
| 708 | 710 | .fn_decl => unreachable, |
| ... | ... | @@ -887,7 +889,7 @@ fn renderAsmOutput( |
| 887 | 889 | const symbolic_name = main_tokens[asm_output]; |
| 888 | 890 | |
| 889 | 891 | try renderToken(ais, tree, symbolic_name - 1, .none); // lbracket |
| 890 | try renderToken(ais, tree, symbolic_name, .none); // ident | |
| 892 | try renderIdentifier(ais, tree, symbolic_name, .none, .eagerly_unquote); // ident | |
| 891 | 893 | try renderToken(ais, tree, symbolic_name + 1, .space); // rbracket |
| 892 | 894 | try renderToken(ais, tree, symbolic_name + 2, .space); // "constraint" |
| 893 | 895 | try renderToken(ais, tree, symbolic_name + 3, .none); // lparen |
| ... | ... | @@ -897,7 +899,7 @@ fn renderAsmOutput( |
| 897 | 899 | try renderExpression(gpa, ais, tree, datas[asm_output].lhs, Space.none); |
| 898 | 900 | return renderToken(ais, tree, datas[asm_output].rhs, space); // rparen |
| 899 | 901 | } else { |
| 900 | try renderToken(ais, tree, symbolic_name + 4, .none); // ident | |
| 902 | try renderIdentifier(ais, tree, symbolic_name + 4, .none, .eagerly_unquote); // ident | |
| 901 | 903 | return renderToken(ais, tree, symbolic_name + 5, space); // rparen |
| 902 | 904 | } |
| 903 | 905 | } |
| ... | ... | @@ -916,7 +918,7 @@ fn renderAsmInput( |
| 916 | 918 | const symbolic_name = main_tokens[asm_input]; |
| 917 | 919 | |
| 918 | 920 | try renderToken(ais, tree, symbolic_name - 1, .none); // lbracket |
| 919 | try renderToken(ais, tree, symbolic_name, .none); // ident | |
| 921 | try renderIdentifier(ais, tree, symbolic_name, .none, .eagerly_unquote); // ident | |
| 920 | 922 | try renderToken(ais, tree, symbolic_name + 1, .space); // rbracket |
| 921 | 923 | try renderToken(ais, tree, symbolic_name + 2, .space); // "constraint" |
| 922 | 924 | try renderToken(ais, tree, symbolic_name + 3, .none); // lparen |
| ... | ... | @@ -955,7 +957,7 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec |
| 955 | 957 | Space.space |
| 956 | 958 | else |
| 957 | 959 | Space.none; |
| 958 | try renderToken(ais, tree, var_decl.ast.mut_token + 1, name_space); // name | |
| 960 | try renderIdentifier(ais, tree, var_decl.ast.mut_token + 1, name_space, .preserve_when_shadowing); // name | |
| 959 | 961 | |
| 960 | 962 | if (var_decl.ast.type_node != 0) { |
| 961 | 963 | try renderToken(ais, tree, var_decl.ast.mut_token + 2, Space.space); // : |
| ... | ... | @@ -1055,7 +1057,7 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While, |
| 1055 | 1057 | const token_tags = tree.tokens.items(.tag); |
| 1056 | 1058 | |
| 1057 | 1059 | if (while_node.label_token) |label| { |
| 1058 | try renderToken(ais, tree, label, .none); // label | |
| 1060 | try renderIdentifier(ais, tree, label, .none, .eagerly_unquote); // label | |
| 1059 | 1061 | try renderToken(ais, tree, label + 1, .space); // : |
| 1060 | 1062 | } |
| 1061 | 1063 | |
| ... | ... | @@ -1080,11 +1082,11 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While, |
| 1080 | 1082 | break :blk payload_token; |
| 1081 | 1083 | } |
| 1082 | 1084 | }; |
| 1083 | try renderToken(ais, tree, ident, .none); // identifier | |
| 1085 | try renderIdentifier(ais, tree, ident, .none, .preserve_when_shadowing); // identifier | |
| 1084 | 1086 | const pipe = blk: { |
| 1085 | 1087 | if (token_tags[ident + 1] == .comma) { |
| 1086 | 1088 | try renderToken(ais, tree, ident + 1, .space); // , |
| 1087 | try renderToken(ais, tree, ident + 2, .none); // index | |
| 1089 | try renderIdentifier(ais, tree, ident + 2, .none, .preserve_when_shadowing); // index | |
| 1088 | 1090 | break :blk ident + 3; |
| 1089 | 1091 | } else { |
| 1090 | 1092 | break :blk ident + 1; |
| ... | ... | @@ -1127,7 +1129,7 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While, |
| 1127 | 1129 | if (while_node.error_token) |error_token| { |
| 1128 | 1130 | try renderToken(ais, tree, while_node.else_token, .space); // else |
| 1129 | 1131 | try renderToken(ais, tree, error_token - 1, .none); // | |
| 1130 | try renderToken(ais, tree, error_token, .none); // identifier | |
| 1132 | try renderIdentifier(ais, tree, error_token, .none, .preserve_when_shadowing); // identifier | |
| 1131 | 1133 | last_else_token = error_token + 1; // | |
| 1132 | 1134 | } |
| 1133 | 1135 | |
| ... | ... | @@ -1163,10 +1165,10 @@ fn renderContainerField( |
| 1163 | 1165 | try renderToken(ais, tree, t, .space); // comptime |
| 1164 | 1166 | } |
| 1165 | 1167 | if (field.ast.type_expr == 0 and field.ast.value_expr == 0) { |
| 1166 | return renderTokenComma(ais, tree, field.ast.name_token, space); // name | |
| 1168 | return renderIdentifierComma(ais, tree, field.ast.name_token, space, .eagerly_unquote); // name | |
| 1167 | 1169 | } |
| 1168 | 1170 | if (field.ast.type_expr != 0 and field.ast.value_expr == 0) { |
| 1169 | try renderToken(ais, tree, field.ast.name_token, .none); // name | |
| 1171 | try renderIdentifier(ais, tree, field.ast.name_token, .none, .eagerly_unquote); // name | |
| 1170 | 1172 | try renderToken(ais, tree, field.ast.name_token + 1, .space); // : |
| 1171 | 1173 | |
| 1172 | 1174 | if (field.ast.align_expr != 0) { |
| ... | ... | @@ -1182,12 +1184,12 @@ fn renderContainerField( |
| 1182 | 1184 | } |
| 1183 | 1185 | } |
| 1184 | 1186 | if (field.ast.type_expr == 0 and field.ast.value_expr != 0) { |
| 1185 | try renderToken(ais, tree, field.ast.name_token, .space); // name | |
| 1187 | try renderIdentifier(ais, tree, field.ast.name_token, .space, .eagerly_unquote); // name | |
| 1186 | 1188 | try renderToken(ais, tree, field.ast.name_token + 1, .space); // = |
| 1187 | 1189 | return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value |
| 1188 | 1190 | } |
| 1189 | 1191 | |
| 1190 | try renderToken(ais, tree, field.ast.name_token, .none); // name | |
| 1192 | try renderIdentifier(ais, tree, field.ast.name_token, .none, .eagerly_unquote); // name | |
| 1191 | 1193 | try renderToken(ais, tree, field.ast.name_token + 1, .space); // : |
| 1192 | 1194 | try renderExpression(gpa, ais, tree, field.ast.type_expr, .space); // type |
| 1193 | 1195 | |
| ... | ... | @@ -1294,7 +1296,7 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt |
| 1294 | 1296 | const after_fn_token = fn_proto.ast.fn_token + 1; |
| 1295 | 1297 | const lparen = if (token_tags[after_fn_token] == .identifier) blk: { |
| 1296 | 1298 | try renderToken(ais, tree, fn_proto.ast.fn_token, .space); // fn |
| 1297 | try renderToken(ais, tree, after_fn_token, .none); // name | |
| 1299 | try renderIdentifier(ais, tree, after_fn_token, .none, .preserve_when_shadowing); // name | |
| 1298 | 1300 | break :blk after_fn_token + 1; |
| 1299 | 1301 | } else blk: { |
| 1300 | 1302 | try renderToken(ais, tree, fn_proto.ast.fn_token, .space); // fn |
| ... | ... | @@ -1383,7 +1385,7 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt |
| 1383 | 1385 | if (token_tags[last_param_token] == .identifier and |
| 1384 | 1386 | token_tags[last_param_token + 1] == .colon) |
| 1385 | 1387 | { |
| 1386 | try renderToken(ais, tree, last_param_token, .none); // name | |
| 1388 | try renderIdentifier(ais, tree, last_param_token, .none, .preserve_when_shadowing); // name | |
| 1387 | 1389 | last_param_token += 1; |
| 1388 | 1390 | try renderToken(ais, tree, last_param_token, .space); // : |
| 1389 | 1391 | last_param_token += 1; |
| ... | ... | @@ -1432,7 +1434,7 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt |
| 1432 | 1434 | if (token_tags[last_param_token] == .identifier and |
| 1433 | 1435 | token_tags[last_param_token + 1] == .colon) |
| 1434 | 1436 | { |
| 1435 | try renderToken(ais, tree, last_param_token, .none); // name | |
| 1437 | try renderIdentifier(ais, tree, last_param_token, .none, .preserve_when_shadowing); // name | |
| 1436 | 1438 | last_param_token += 1; |
| 1437 | 1439 | try renderToken(ais, tree, last_param_token, .space); // : |
| 1438 | 1440 | last_param_token += 1; |
| ... | ... | @@ -1545,7 +1547,7 @@ fn renderSwitchCase( |
| 1545 | 1547 | else |
| 1546 | 1548 | Space.space; |
| 1547 | 1549 | const after_arrow_space: Space = if (switch_case.payload_token == null) pre_target_space else .space; |
| 1548 | try renderToken(ais, tree, switch_case.ast.arrow_token, after_arrow_space); | |
| 1550 | try renderToken(ais, tree, switch_case.ast.arrow_token, after_arrow_space); // => | |
| 1549 | 1551 | |
| 1550 | 1552 | if (switch_case.payload_token) |payload_token| { |
| 1551 | 1553 | try renderToken(ais, tree, payload_token - 1, .none); // pipe |
| ... | ... | @@ -1553,10 +1555,10 @@ fn renderSwitchCase( |
| 1553 | 1555 | if (token_tags[payload_token] == .asterisk) { |
| 1554 | 1556 | try renderToken(ais, tree, payload_token, .none); // asterisk |
| 1555 | 1557 | } |
| 1556 | try renderToken(ais, tree, ident, .none); // identifier | |
| 1558 | try renderIdentifier(ais, tree, ident, .none, .preserve_when_shadowing); // identifier | |
| 1557 | 1559 | if (token_tags[ident + 1] == .comma) { |
| 1558 | 1560 | try renderToken(ais, tree, ident + 1, .space); // , |
| 1559 | try renderToken(ais, tree, ident + 2, .none); // identifier | |
| 1561 | try renderIdentifier(ais, tree, ident + 2, .none, .preserve_when_shadowing); // identifier | |
| 1560 | 1562 | try renderToken(ais, tree, ident + 3, pre_target_space); // pipe |
| 1561 | 1563 | } else { |
| 1562 | 1564 | try renderToken(ais, tree, ident + 1, pre_target_space); // pipe |
| ... | ... | @@ -1581,8 +1583,8 @@ fn renderBlock( |
| 1581 | 1583 | if (token_tags[lbrace - 1] == .colon and |
| 1582 | 1584 | token_tags[lbrace - 2] == .identifier) |
| 1583 | 1585 | { |
| 1584 | try renderToken(ais, tree, lbrace - 2, .none); | |
| 1585 | try renderToken(ais, tree, lbrace - 1, .space); | |
| 1586 | try renderIdentifier(ais, tree, lbrace - 2, .none, .eagerly_unquote); // identifier | |
| 1587 | try renderToken(ais, tree, lbrace - 1, .space); // : | |
| 1586 | 1588 | } |
| 1587 | 1589 | |
| 1588 | 1590 | ais.pushIndentNextLine(); |
| ... | ... | @@ -1635,7 +1637,7 @@ fn renderStructInit( |
| 1635 | 1637 | try renderToken(ais, tree, struct_init.ast.lbrace, .newline); |
| 1636 | 1638 | |
| 1637 | 1639 | try renderToken(ais, tree, struct_init.ast.lbrace + 1, .none); // . |
| 1638 | try renderToken(ais, tree, struct_init.ast.lbrace + 2, .space); // name | |
| 1640 | try renderIdentifier(ais, tree, struct_init.ast.lbrace + 2, .space, .eagerly_unquote); // name | |
| 1639 | 1641 | try renderToken(ais, tree, struct_init.ast.lbrace + 3, .space); // = |
| 1640 | 1642 | try renderExpression(gpa, ais, tree, struct_init.ast.fields[0], .comma); |
| 1641 | 1643 | |
| ... | ... | @@ -1643,7 +1645,7 @@ fn renderStructInit( |
| 1643 | 1645 | const init_token = tree.firstToken(field_init); |
| 1644 | 1646 | try renderExtraNewlineToken(ais, tree, init_token - 3); |
| 1645 | 1647 | try renderToken(ais, tree, init_token - 3, .none); // . |
| 1646 | try renderToken(ais, tree, init_token - 2, .space); // name | |
| 1648 | try renderIdentifier(ais, tree, init_token - 2, .space, .eagerly_unquote); // name | |
| 1647 | 1649 | try renderToken(ais, tree, init_token - 1, .space); // = |
| 1648 | 1650 | try renderExpression(gpa, ais, tree, field_init, .comma); |
| 1649 | 1651 | } |
| ... | ... | @@ -1656,7 +1658,7 @@ fn renderStructInit( |
| 1656 | 1658 | for (struct_init.ast.fields) |field_init| { |
| 1657 | 1659 | const init_token = tree.firstToken(field_init); |
| 1658 | 1660 | try renderToken(ais, tree, init_token - 3, .none); // . |
| 1659 | try renderToken(ais, tree, init_token - 2, .space); // name | |
| 1661 | try renderIdentifier(ais, tree, init_token - 2, .space, .eagerly_unquote); // name | |
| 1660 | 1662 | try renderToken(ais, tree, init_token - 1, .space); // = |
| 1661 | 1663 | try renderExpression(gpa, ais, tree, field_init, .comma_space); |
| 1662 | 1664 | } |
| ... | ... | @@ -2310,6 +2312,19 @@ fn renderTokenComma(ais: *Ais, tree: Ast, token: Ast.TokenIndex, space: Space) E |
| 2310 | 2312 | } |
| 2311 | 2313 | } |
| 2312 | 2314 | |
| 2315 | /// Render an identifier, and the comma that follows it, if it is present in the source. | |
| 2316 | /// If a comma is present, and `space` is `Space.comma`, render only a single comma. | |
| 2317 | fn renderIdentifierComma(ais: *Ais, tree: Ast, token: Ast.TokenIndex, space: Space, quote: QuoteBehavior) Error!void { | |
| 2318 | const token_tags = tree.tokens.items(.tag); | |
| 2319 | const maybe_comma = token + 1; | |
| 2320 | if (token_tags[maybe_comma] == .comma and space != .comma) { | |
| 2321 | try renderIdentifier(ais, tree, token, .none, quote); | |
| 2322 | return renderToken(ais, tree, maybe_comma, space); | |
| 2323 | } else { | |
| 2324 | return renderIdentifier(ais, tree, token, space, quote); | |
| 2325 | } | |
| 2326 | } | |
| 2327 | ||
| 2313 | 2328 | const Space = enum { |
| 2314 | 2329 | /// Output the token lexeme only. |
| 2315 | 2330 | none, |
| ... | ... | @@ -2377,6 +2392,158 @@ fn renderSpace(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, lexeme_len: us |
| 2377 | 2392 | } |
| 2378 | 2393 | } |
| 2379 | 2394 | |
| 2395 | const QuoteBehavior = enum { | |
| 2396 | preserve_when_shadowing, | |
| 2397 | eagerly_unquote, | |
| 2398 | }; | |
| 2399 | ||
| 2400 | fn renderIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Space, quote: QuoteBehavior) Error!void { | |
| 2401 | const token_tags = tree.tokens.items(.tag); | |
| 2402 | assert(token_tags[token_index] == .identifier); | |
| 2403 | const lexeme = tokenSliceForRender(tree, token_index); | |
| 2404 | if (lexeme[0] != '@') { | |
| 2405 | return renderToken(ais, tree, token_index, space); | |
| 2406 | } | |
| 2407 | ||
| 2408 | assert(lexeme.len >= 3); | |
| 2409 | assert(lexeme[0] == '@'); | |
| 2410 | assert(lexeme[1] == '\"'); | |
| 2411 | assert(lexeme[lexeme.len - 1] == '\"'); | |
| 2412 | const contents = lexeme[2 .. lexeme.len - 1]; // inside the @"" quotation | |
| 2413 | ||
| 2414 | // Empty name can't be unquoted. | |
| 2415 | if (contents.len == 0) { | |
| 2416 | return renderQuotedIdentifier(ais, tree, token_index, space, false); | |
| 2417 | } | |
| 2418 | ||
| 2419 | // Special case for _ which would incorrectly be rejected by isValidId below. | |
| 2420 | if (contents.len == 1 and contents[0] == '_') switch (quote) { | |
| 2421 | .eagerly_unquote => return renderQuotedIdentifier(ais, tree, token_index, space, true), | |
| 2422 | .preserve_when_shadowing => return renderQuotedIdentifier(ais, tree, token_index, space, false), | |
| 2423 | }; | |
| 2424 | ||
| 2425 | // Scan the entire name for characters that would (after un-escaping) be illegal in a symbol, | |
| 2426 | // i.e. contents don't match: [A-Za-z_][A-Za-z0-9_]* | |
| 2427 | var contents_i: usize = 0; | |
| 2428 | while (contents_i < contents.len) { | |
| 2429 | switch (contents[contents_i]) { | |
| 2430 | '0'...'9' => if (contents_i == 0) return renderQuotedIdentifier(ais, tree, token_index, space, false), | |
| 2431 | 'A'...'Z', 'a'...'z', '_' => {}, | |
| 2432 | '\\' => { | |
| 2433 | var esc_offset = contents_i; | |
| 2434 | const res = std.zig.string_literal.parseEscapeSequence(contents, &esc_offset); | |
| 2435 | switch (res) { | |
| 2436 | .success => |char| switch (char) { | |
| 2437 | '0'...'9' => if (contents_i == 0) return renderQuotedIdentifier(ais, tree, token_index, space, false), | |
| 2438 | 'A'...'Z', 'a'...'z', '_' => {}, | |
| 2439 | else => return renderQuotedIdentifier(ais, tree, token_index, space, false), | |
| 2440 | }, | |
| 2441 | .failure => return renderQuotedIdentifier(ais, tree, token_index, space, false), | |
| 2442 | } | |
| 2443 | contents_i += esc_offset; | |
| 2444 | continue; | |
| 2445 | }, | |
| 2446 | else => return renderQuotedIdentifier(ais, tree, token_index, space, false), | |
| 2447 | } | |
| 2448 | contents_i += 1; | |
| 2449 | } | |
| 2450 | ||
| 2451 | // Read enough of the name (while un-escaping) to determine if it's a keyword or primitive. | |
| 2452 | // If it's too long to fit in this buffer, we know it's neither and quoting is unnecessary. | |
| 2453 | // If we read the whole thing, we have to do further checks. | |
| 2454 | const longest_keyword_or_primitive_len = comptime blk: { | |
| 2455 | var longest = 0; | |
| 2456 | for (primitives.names.kvs) |kv| { | |
| 2457 | if (kv.key.len > longest) longest = kv.key.len; | |
| 2458 | } | |
| 2459 | for (std.zig.Token.keywords.kvs) |kv| { | |
| 2460 | if (kv.key.len > longest) longest = kv.key.len; | |
| 2461 | } | |
| 2462 | break :blk longest; | |
| 2463 | }; | |
| 2464 | var buf: [longest_keyword_or_primitive_len]u8 = undefined; | |
| 2465 | ||
| 2466 | contents_i = 0; | |
| 2467 | var buf_i: usize = 0; | |
| 2468 | while (contents_i < contents.len and buf_i < longest_keyword_or_primitive_len) { | |
| 2469 | if (contents[contents_i] == '\\') { | |
| 2470 | const res = std.zig.string_literal.parseEscapeSequence(contents, &contents_i).success; | |
| 2471 | buf[buf_i] = @intCast(u8, res); | |
| 2472 | buf_i += 1; | |
| 2473 | } else { | |
| 2474 | buf[buf_i] = contents[contents_i]; | |
| 2475 | contents_i += 1; | |
| 2476 | buf_i += 1; | |
| 2477 | } | |
| 2478 | } | |
| 2479 | ||
| 2480 | // We read the whole thing, so it could be a keyword or primitive. | |
| 2481 | if (contents_i == contents.len) { | |
| 2482 | if (!std.zig.isValidId(buf[0..buf_i])) { | |
| 2483 | return renderQuotedIdentifier(ais, tree, token_index, space, false); | |
| 2484 | } | |
| 2485 | if (primitives.isPrimitive(buf[0..buf_i])) switch (quote) { | |
| 2486 | .eagerly_unquote => return renderQuotedIdentifier(ais, tree, token_index, space, true), | |
| 2487 | .preserve_when_shadowing => return renderQuotedIdentifier(ais, tree, token_index, space, false), | |
| 2488 | }; | |
| 2489 | } | |
| 2490 | ||
| 2491 | try renderQuotedIdentifier(ais, tree, token_index, space, true); | |
| 2492 | } | |
| 2493 | ||
| 2494 | // Renders a @"" quoted identifier, normalizing escapes. | |
| 2495 | // Unnecessary escapes are un-escaped, and \u escapes are normalized to \x when they fit. | |
| 2496 | // If unquote is true, the @"" is removed and the result is a bare symbol whose validity is asserted. | |
| 2497 | fn renderQuotedIdentifier(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Space, comptime unquote: bool) !void { | |
| 2498 | const token_tags = tree.tokens.items(.tag); | |
| 2499 | assert(token_tags[token_index] == .identifier); | |
| 2500 | const lexeme = tokenSliceForRender(tree, token_index); | |
| 2501 | assert(lexeme.len >= 3 and lexeme[0] == '@'); | |
| 2502 | ||
| 2503 | if (!unquote) try ais.writer().writeAll("@\""); | |
| 2504 | const contents = lexeme[2 .. lexeme.len - 1]; | |
| 2505 | try renderIdentifierContents(ais.writer(), contents); | |
| 2506 | if (!unquote) try ais.writer().writeByte('\"'); | |
| 2507 | ||
| 2508 | try renderSpace(ais, tree, token_index, lexeme.len, space); | |
| 2509 | } | |
| 2510 | ||
| 2511 | fn renderIdentifierContents(writer: anytype, bytes: []const u8) !void { | |
| 2512 | var pos: usize = 0; | |
| 2513 | while (pos < bytes.len) { | |
| 2514 | const byte = bytes[pos]; | |
| 2515 | switch (byte) { | |
| 2516 | '\\' => { | |
| 2517 | const old_pos = pos; | |
| 2518 | const res = std.zig.string_literal.parseEscapeSequence(bytes, &pos); | |
| 2519 | const escape_sequence = bytes[old_pos..pos]; | |
| 2520 | switch (res) { | |
| 2521 | .success => |codepoint| { | |
| 2522 | if (codepoint <= 0x7f) { | |
| 2523 | const buf = [1]u8{@intCast(u8, codepoint)}; | |
| 2524 | try std.fmt.format(writer, "{}", .{std.zig.fmtEscapes(&buf)}); | |
| 2525 | } else { | |
| 2526 | try writer.writeAll(escape_sequence); | |
| 2527 | } | |
| 2528 | }, | |
| 2529 | .failure => { | |
| 2530 | try writer.writeAll(escape_sequence); | |
| 2531 | }, | |
| 2532 | } | |
| 2533 | }, | |
| 2534 | 0x00...('\\' - 1), ('\\' + 1)...0x7f => { | |
| 2535 | const buf = [1]u8{@intCast(u8, byte)}; | |
| 2536 | try std.fmt.format(writer, "{}", .{std.zig.fmtEscapes(&buf)}); | |
| 2537 | pos += 1; | |
| 2538 | }, | |
| 2539 | 0x80...0xff => { | |
| 2540 | try writer.writeByte(byte); | |
| 2541 | pos += 1; | |
| 2542 | }, | |
| 2543 | } | |
| 2544 | } | |
| 2545 | } | |
| 2546 | ||
| 2380 | 2547 | /// Returns true if there exists a line comment between any of the tokens from |
| 2381 | 2548 | /// `start_token` to `end_token`. This is used to determine if e.g. a |
| 2382 | 2549 | /// fn_proto should be wrapped and have a trailing comma inserted even if |
lib/std/zig/string_literal.zig+40-2| ... | ... | @@ -63,7 +63,7 @@ pub fn parseCharLiteral(slice: []const u8) ParsedCharLiteral { |
| 63 | 63 | |
| 64 | 64 | /// Parse an escape sequence from `slice[offset..]`. If parsing is successful, |
| 65 | 65 | /// offset is updated to reflect the characters consumed. |
| 66 | fn parseEscapeSequence(slice: []const u8, offset: *usize) ParsedCharLiteral { | |
| 66 | pub fn parseEscapeSequence(slice: []const u8, offset: *usize) ParsedCharLiteral { | |
| 67 | 67 | assert(slice.len > offset.*); |
| 68 | 68 | assert(slice[offset.*] == '\\'); |
| 69 | 69 | |
| ... | ... | @@ -274,12 +274,50 @@ pub fn parseAlloc(allocator: std.mem.Allocator, bytes: []const u8) ParseError![] |
| 274 | 274 | var buf = std.ArrayList(u8).init(allocator); |
| 275 | 275 | defer buf.deinit(); |
| 276 | 276 | |
| 277 | switch (try parseAppend(&buf, bytes)) { | |
| 277 | switch (try parseWrite(buf.writer(), bytes)) { | |
| 278 | 278 | .success => return buf.toOwnedSlice(), |
| 279 | 279 | .failure => return error.InvalidLiteral, |
| 280 | 280 | } |
| 281 | 281 | } |
| 282 | 282 | |
| 283 | /// Parses `bytes` as a Zig string literal and writes the result to the std.io.Writer type. | |
| 284 | /// Asserts `bytes` has '"' at beginning and end. | |
| 285 | pub fn parseWrite(writer: anytype, bytes: []const u8) error{OutOfMemory}!Result { | |
| 286 | assert(bytes.len >= 2 and bytes[0] == '"' and bytes[bytes.len - 1] == '"'); | |
| 287 | ||
| 288 | var index: usize = 1; | |
| 289 | while (true) { | |
| 290 | const b = bytes[index]; | |
| 291 | ||
| 292 | switch (b) { | |
| 293 | '\\' => { | |
| 294 | const escape_char_index = index + 1; | |
| 295 | const result = parseEscapeSequence(bytes, &index); | |
| 296 | switch (result) { | |
| 297 | .success => |codepoint| { | |
| 298 | if (bytes[escape_char_index] == 'u') { | |
| 299 | var buf: [3]u8 = undefined; | |
| 300 | const len = utf8Encode(codepoint, &buf) catch { | |
| 301 | return Result{ .failure = .{ .invalid_unicode_codepoint = escape_char_index + 1 } }; | |
| 302 | }; | |
| 303 | try writer.writeAll(buf[0..len]); | |
| 304 | } else { | |
| 305 | try writer.writeByte(@intCast(u8, codepoint)); | |
| 306 | } | |
| 307 | }, | |
| 308 | .failure => |err| return Result{ .failure = err }, | |
| 309 | } | |
| 310 | }, | |
| 311 | '\n' => return Result{ .failure = .{ .invalid_character = index } }, | |
| 312 | '"' => return Result.success, | |
| 313 | else => { | |
| 314 | try writer.writeByte(b); | |
| 315 | index += 1; | |
| 316 | }, | |
| 317 | } | |
| 318 | } else unreachable; // TODO should not need else unreachable on while(true) | |
| 319 | } | |
| 320 | ||
| 283 | 321 | test "parse" { |
| 284 | 322 | const expect = std.testing.expect; |
| 285 | 323 | const expectError = std.testing.expectError; |
src/AstGen.zig+22-44| ... | ... | @@ -10,6 +10,8 @@ const ArrayListUnmanaged = std.ArrayListUnmanaged; |
| 10 | 10 | const StringIndexAdapter = std.hash_map.StringIndexAdapter; |
| 11 | 11 | const StringIndexContext = std.hash_map.StringIndexContext; |
| 12 | 12 | |
| 13 | const isPrimitive = std.zig.primitives.isPrimitive; | |
| 14 | ||
| 13 | 15 | const Zir = @import("Zir.zig"); |
| 14 | 16 | const refToIndex = Zir.refToIndex; |
| 15 | 17 | const indexToRef = Zir.indexToRef; |
| ... | ... | @@ -4237,33 +4239,7 @@ fn testDecl( |
| 4237 | 4239 | |
| 4238 | 4240 | // if not @"" syntax, just use raw token slice |
| 4239 | 4241 | if (ident_name_raw[0] != '@') { |
| 4240 | if (primitives.get(ident_name_raw)) |_| return astgen.failTok(test_name_token, "cannot test a primitive", .{}); | |
| 4241 | ||
| 4242 | if (ident_name_raw.len >= 2) integer: { | |
| 4243 | const first_c = ident_name_raw[0]; | |
| 4244 | if (first_c == 'i' or first_c == 'u') { | |
| 4245 | _ = switch (first_c == 'i') { | |
| 4246 | true => .signed, | |
| 4247 | false => .unsigned, | |
| 4248 | }; | |
| 4249 | if (ident_name_raw.len >= 3 and ident_name_raw[1] == '0') { | |
| 4250 | return astgen.failTok( | |
| 4251 | test_name_token, | |
| 4252 | "primitive integer type '{s}' has leading zero", | |
| 4253 | .{ident_name_raw}, | |
| 4254 | ); | |
| 4255 | } | |
| 4256 | _ = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) { | |
| 4257 | error.Overflow => return astgen.failTok( | |
| 4258 | test_name_token, | |
| 4259 | "primitive integer type '{s}' exceeds maximum bit width of 65535", | |
| 4260 | .{ident_name_raw}, | |
| 4261 | ), | |
| 4262 | error.InvalidCharacter => break :integer, | |
| 4263 | }; | |
| 4264 | return astgen.failTok(test_name_token, "cannot test a primitive", .{}); | |
| 4265 | } | |
| 4266 | } | |
| 4242 | if (isPrimitive(ident_name_raw)) return astgen.failTok(test_name_token, "cannot test a primitive", .{}); | |
| 4267 | 4243 | } |
| 4268 | 4244 | |
| 4269 | 4245 | // Local variables, including function parameters. |
| ... | ... | @@ -7108,7 +7084,7 @@ fn identifier( |
| 7108 | 7084 | |
| 7109 | 7085 | // if not @"" syntax, just use raw token slice |
| 7110 | 7086 | if (ident_name_raw[0] != '@') { |
| 7111 | if (primitives.get(ident_name_raw)) |zir_const_ref| { | |
| 7087 | if (primitive_instrs.get(ident_name_raw)) |zir_const_ref| { | |
| 7112 | 7088 | return rvalue(gz, ri, zir_const_ref, ident); |
| 7113 | 7089 | } |
| 7114 | 7090 | |
| ... | ... | @@ -8751,7 +8727,7 @@ fn calleeExpr( |
| 8751 | 8727 | } |
| 8752 | 8728 | } |
| 8753 | 8729 | |
| 8754 | const primitives = std.ComptimeStringMap(Zir.Inst.Ref, .{ | |
| 8730 | const primitive_instrs = std.ComptimeStringMap(Zir.Inst.Ref, .{ | |
| 8755 | 8731 | .{ "anyerror", .anyerror_type }, |
| 8756 | 8732 | .{ "anyframe", .anyframe_type }, |
| 8757 | 8733 | .{ "anyopaque", .anyopaque_type }, |
| ... | ... | @@ -8795,6 +8771,21 @@ const primitives = std.ComptimeStringMap(Zir.Inst.Ref, .{ |
| 8795 | 8771 | .{ "void", .void_type }, |
| 8796 | 8772 | }); |
| 8797 | 8773 | |
| 8774 | comptime { | |
| 8775 | // These checks ensure that std.zig.primitives stays in synce with the primitive->Zir map. | |
| 8776 | const primitives = std.zig.primitives; | |
| 8777 | for (primitive_instrs.kvs) |kv| { | |
| 8778 | if (!primitives.isPrimitive(kv.key)) { | |
| 8779 | @compileError("std.zig.isPrimitive() is not aware of Zir instr '" ++ @tagName(kv.value) ++ "'"); | |
| 8780 | } | |
| 8781 | } | |
| 8782 | for (primitives.names.kvs) |kv| { | |
| 8783 | if (primitive_instrs.get(kv.key) == null) { | |
| 8784 | @compileError("std.zig.primitives entry '" ++ kv.key ++ "' does not have a corresponding Zir instr"); | |
| 8785 | } | |
| 8786 | } | |
| 8787 | } | |
| 8788 | ||
| 8798 | 8789 | fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_res_ty: bool) bool { |
| 8799 | 8790 | const node_tags = tree.nodes.items(.tag); |
| 8800 | 8791 | const node_datas = tree.nodes.items(.data); |
| ... | ... | @@ -9458,7 +9449,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In |
| 9458 | 9449 | .identifier => { |
| 9459 | 9450 | const main_tokens = tree.nodes.items(.main_token); |
| 9460 | 9451 | const ident_bytes = tree.tokenSlice(main_tokens[node]); |
| 9461 | if (primitives.get(ident_bytes)) |primitive| switch (primitive) { | |
| 9452 | if (primitive_instrs.get(ident_bytes)) |primitive| switch (primitive) { | |
| 9462 | 9453 | .anyerror_type, |
| 9463 | 9454 | .anyframe_type, |
| 9464 | 9455 | .anyopaque_type, |
| ... | ... | @@ -9702,7 +9693,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool { |
| 9702 | 9693 | .identifier => { |
| 9703 | 9694 | const main_tokens = tree.nodes.items(.main_token); |
| 9704 | 9695 | const ident_bytes = tree.tokenSlice(main_tokens[node]); |
| 9705 | if (primitives.get(ident_bytes)) |primitive| switch (primitive) { | |
| 9696 | if (primitive_instrs.get(ident_bytes)) |primitive| switch (primitive) { | |
| 9706 | 9697 | .anyerror_type, |
| 9707 | 9698 | .anyframe_type, |
| 9708 | 9699 | .anyopaque_type, |
| ... | ... | @@ -12045,19 +12036,6 @@ fn nullTerminatedString(astgen: AstGen, index: usize) [*:0]const u8 { |
| 12045 | 12036 | return @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + index; |
| 12046 | 12037 | } |
| 12047 | 12038 | |
| 12048 | pub fn isPrimitive(name: []const u8) bool { | |
| 12049 | if (primitives.get(name) != null) return true; | |
| 12050 | if (name.len < 2) return false; | |
| 12051 | const first_c = name[0]; | |
| 12052 | if (first_c != 'i' and first_c != 'u') return false; | |
| 12053 | if (parseBitCount(name[1..])) |_| { | |
| 12054 | return true; | |
| 12055 | } else |err| switch (err) { | |
| 12056 | error.Overflow => return true, | |
| 12057 | error.InvalidCharacter => return false, | |
| 12058 | } | |
| 12059 | } | |
| 12060 | ||
| 12061 | 12039 | /// Local variables shadowing detection, including function parameters. |
| 12062 | 12040 | fn detectLocalShadowing( |
| 12063 | 12041 | astgen: *AstGen, |
src/stage1/astgen.cpp+21| ... | ... | @@ -3879,6 +3879,27 @@ static Stage1ZirInst *astgen_identifier(Stage1AstGen *ag, Scope *scope, AstNode |
| 3879 | 3879 | } |
| 3880 | 3880 | } |
| 3881 | 3881 | |
| 3882 | { | |
| 3883 | Stage1ZirInst *value = nullptr; | |
| 3884 | if (buf_eql_str(variable_name, "null")) { | |
| 3885 | value = ir_build_const_null(ag, scope, node); | |
| 3886 | } else if (buf_eql_str(variable_name, "true")) { | |
| 3887 | value = ir_build_const_bool(ag, scope, node, true); | |
| 3888 | } else if (buf_eql_str(variable_name, "false")) { | |
| 3889 | value = ir_build_const_bool(ag, scope, node, false); | |
| 3890 | } else if (buf_eql_str(variable_name, "undefined")) { | |
| 3891 | value = ir_build_const_undefined(ag, scope, node); | |
| 3892 | } | |
| 3893 | ||
| 3894 | if (value != nullptr) { | |
| 3895 | if (lval == LValPtr || lval == LValAssign) { | |
| 3896 | return ir_build_ref_src(ag, scope, node, value); | |
| 3897 | } else { | |
| 3898 | return ir_expr_wrap(ag, scope, value, result_loc); | |
| 3899 | } | |
| 3900 | } | |
| 3901 | } | |
| 3902 | ||
| 3882 | 3903 | ZigType *primitive_type; |
| 3883 | 3904 | if ((err = get_primitive_type(ag->codegen, variable_name, &primitive_type))) { |
| 3884 | 3905 | if (err == ErrorOverflow) { |
src/stage1/parser.cpp-4| ... | ... | @@ -1617,11 +1617,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) { |
| 1617 | 1617 | // / INTEGER |
| 1618 | 1618 | // / KEYWORD_comptime TypeExpr |
| 1619 | 1619 | // / KEYWORD_error DOT IDENTIFIER |
| 1620 | // / KEYWORD_false | |
| 1621 | // / KEYWORD_null | |
| 1622 | 1620 | // / KEYWORD_promise |
| 1623 | // / KEYWORD_true | |
| 1624 | // / KEYWORD_undefined | |
| 1625 | 1621 | // / KEYWORD_unreachable |
| 1626 | 1622 | // / STRINGLITERAL |
| 1627 | 1623 | // / SwitchExpr |
src/translate_c/ast.zig+1-1| ... | ... | @@ -827,7 +827,7 @@ const Context = struct { |
| 827 | 827 | } |
| 828 | 828 | |
| 829 | 829 | fn addIdentifier(c: *Context, bytes: []const u8) Allocator.Error!TokenIndex { |
| 830 | if (@import("../AstGen.zig").isPrimitive(bytes)) | |
| 830 | if (std.zig.primitives.isPrimitive(bytes)) | |
| 831 | 831 | return c.addTokenFmt(.identifier, "@\"{s}\"", .{bytes}); |
| 832 | 832 | return c.addTokenFmt(.identifier, "{s}", .{std.zig.fmtId(bytes)}); |
| 833 | 833 | } |