authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-26 02:22:51-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-11-26 02:22:51-05:00
log7103088e4a51d4362e6665d5949a9677e18fb74a
tree858c52055896b6d6085b3810b6263eed3bafae0a
parent2ff707be789046a733d0d23c6fe42dd2b7210396
parent74010fecc7bbeaf9de77c28dda5906c3c1f4a6df
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #18105 from Vexu/translate-c

Use Aro's tokenizer in `translate-c`

26 files changed, 1299 insertions(+), 2543 deletions(-)

CMakeLists.txt-1
......@@ -218,7 +218,6 @@ set(ZIG_STAGE2_SOURCES
218218 "${CMAKE_SOURCE_DIR}/lib/std/builtin.zig"
219219 "${CMAKE_SOURCE_DIR}/lib/std/c.zig"
220220 "${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig"
221 "${CMAKE_SOURCE_DIR}/lib/std/c/tokenizer.zig"
222221 "${CMAKE_SOURCE_DIR}/lib/std/child_process.zig"
223222 "${CMAKE_SOURCE_DIR}/lib/std/coff.zig"
224223 "${CMAKE_SOURCE_DIR}/lib/std/comptime_string_map.zig"
deps/aro/aro/Builtins/Builtin.def+152
......@@ -17008,3 +17008,155 @@ wmemmove
1700817008 .param_str = "w*w*wC*z"
1700917009 .header = .wchar
1701017010 .attributes = .{ .lib_function_without_prefix = true, .const_evaluable = true }
17011
17012__c11_atomic_init
17013 .param_str = "v."
17014 .attributes = .{ .custom_typecheck = true }
17015
17016__c11_atomic_load
17017 .param_str = "v."
17018 .attributes = .{ .custom_typecheck = true }
17019
17020__c11_atomic_store
17021 .param_str = "v."
17022 .attributes = .{ .custom_typecheck = true }
17023
17024__c11_atomic_exchange
17025 .param_str = "v."
17026 .attributes = .{ .custom_typecheck = true }
17027
17028__c11_atomic_compare_exchange_strong
17029 .param_str = "v."
17030 .attributes = .{ .custom_typecheck = true }
17031
17032__c11_atomic_compare_exchange_weak
17033 .param_str = "v."
17034 .attributes = .{ .custom_typecheck = true }
17035
17036__c11_atomic_fetch_add
17037 .param_str = "v."
17038 .attributes = .{ .custom_typecheck = true }
17039
17040__c11_atomic_fetch_sub
17041 .param_str = "v."
17042 .attributes = .{ .custom_typecheck = true }
17043
17044__c11_atomic_fetch_and
17045 .param_str = "v."
17046 .attributes = .{ .custom_typecheck = true }
17047
17048__c11_atomic_fetch_or
17049 .param_str = "v."
17050 .attributes = .{ .custom_typecheck = true }
17051
17052__c11_atomic_fetch_xor
17053 .param_str = "v."
17054 .attributes = .{ .custom_typecheck = true }
17055
17056__c11_atomic_fetch_nand
17057 .param_str = "v."
17058 .attributes = .{ .custom_typecheck = true }
17059
17060__c11_atomic_fetch_max
17061 .param_str = "v."
17062 .attributes = .{ .custom_typecheck = true }
17063
17064__c11_atomic_fetch_min
17065 .param_str = "v."
17066 .attributes = .{ .custom_typecheck = true }
17067
17068__atomic_load
17069 .param_str = "v."
17070 .attributes = .{ .custom_typecheck = true }
17071
17072__atomic_load_n
17073 .param_str = "v."
17074 .attributes = .{ .custom_typecheck = true }
17075
17076__atomic_store
17077 .param_str = "v."
17078 .attributes = .{ .custom_typecheck = true }
17079
17080__atomic_store_n
17081 .param_str = "v."
17082 .attributes = .{ .custom_typecheck = true }
17083
17084__atomic_exchange
17085 .param_str = "v."
17086 .attributes = .{ .custom_typecheck = true }
17087
17088__atomic_exchange_n
17089 .param_str = "v."
17090 .attributes = .{ .custom_typecheck = true }
17091
17092__atomic_compare_exchange
17093 .param_str = "v."
17094 .attributes = .{ .custom_typecheck = true }
17095
17096__atomic_compare_exchange_n
17097 .param_str = "v."
17098 .attributes = .{ .custom_typecheck = true }
17099
17100__atomic_fetch_add
17101 .param_str = "v."
17102 .attributes = .{ .custom_typecheck = true }
17103
17104__atomic_fetch_sub
17105 .param_str = "v."
17106 .attributes = .{ .custom_typecheck = true }
17107
17108__atomic_fetch_and
17109 .param_str = "v."
17110 .attributes = .{ .custom_typecheck = true }
17111
17112__atomic_fetch_or
17113 .param_str = "v."
17114 .attributes = .{ .custom_typecheck = true }
17115
17116__atomic_fetch_xor
17117 .param_str = "v."
17118 .attributes = .{ .custom_typecheck = true }
17119
17120__atomic_fetch_nand
17121 .param_str = "v."
17122 .attributes = .{ .custom_typecheck = true }
17123
17124__atomic_add_fetch
17125 .param_str = "v."
17126 .attributes = .{ .custom_typecheck = true }
17127
17128__atomic_sub_fetch
17129 .param_str = "v."
17130 .attributes = .{ .custom_typecheck = true }
17131
17132__atomic_and_fetch
17133 .param_str = "v."
17134 .attributes = .{ .custom_typecheck = true }
17135
17136__atomic_or_fetch
17137 .param_str = "v."
17138 .attributes = .{ .custom_typecheck = true }
17139
17140__atomic_xor_fetch
17141 .param_str = "v."
17142 .attributes = .{ .custom_typecheck = true }
17143
17144__atomic_max_fetch
17145 .param_str = "v."
17146 .attributes = .{ .custom_typecheck = true }
17147
17148__atomic_min_fetch
17149 .param_str = "v."
17150 .attributes = .{ .custom_typecheck = true }
17151
17152__atomic_nand_fetch
17153 .param_str = "v."
17154 .attributes = .{ .custom_typecheck = true }
17155
17156__atomic_fetch_min
17157 .param_str = "v."
17158 .attributes = .{ .custom_typecheck = true }
17159
17160__atomic_fetch_max
17161 .param_str = "v."
17162 .attributes = .{ .custom_typecheck = true }
deps/aro/aro/Compilation.zig+73-2
......@@ -408,6 +408,17 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
408408 \\
409409 );
410410
411 // atomics
412 try w.writeAll(
413 \\#define __ATOMIC_RELAXED 0
414 \\#define __ATOMIC_CONSUME 1
415 \\#define __ATOMIC_ACQUIRE 2
416 \\#define __ATOMIC_RELEASE 3
417 \\#define __ATOMIC_ACQ_REL 4
418 \\#define __ATOMIC_SEQ_CST 5
419 \\
420 );
421
411422 // types
412423 if (comp.getCharSignedness() == .unsigned) try w.writeAll("#define __CHAR_UNSIGNED__ 1\n");
413424 try w.writeAll("#define __CHAR_BIT__ 8\n");
......@@ -445,6 +456,10 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
445456 try comp.generateSizeofType(w, "__SIZEOF_WCHAR_T__", comp.types.wchar);
446457 // try comp.generateSizeofType(w, "__SIZEOF_WINT_T__", .{ .specifier = .pointer });
447458
459 if (target_util.hasInt128(comp.target)) {
460 try comp.generateSizeofType(w, "__SIZEOF_INT128__", .{ .specifier = .int128 });
461 }
462
448463 // various int types
449464 const mapper = comp.string_interner.getSlowTypeMapper();
450465 try generateTypeMacro(w, mapper, "__INTPTR_TYPE__", comp.types.intptr, comp.langopts);
......@@ -461,6 +476,7 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
461476 try generateTypeMacro(w, mapper, "__WCHAR_TYPE__", comp.types.wchar, comp.langopts);
462477
463478 try comp.generateExactWidthTypes(w, mapper);
479 try comp.generateFastAndLeastWidthTypes(w, mapper);
464480
465481 if (target_util.FPSemantics.halfPrecisionType(comp.target)) |half| {
466482 try generateFloatMacros(w, "FLT16", half, "F16");
......@@ -497,10 +513,11 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
497513 );
498514 }
499515
516 try buf.appendSlice("#define __STDC__ 1\n");
517 try buf.writer().print("#define __STDC_HOSTED__ {d}\n", .{@intFromBool(comp.target.os.tag != .freestanding)});
518
500519 // standard macros
501520 try buf.appendSlice(
502 \\#define __STDC__ 1
503 \\#define __STDC_HOSTED__ 1
504521 \\#define __STDC_NO_ATOMICS__ 1
505522 \\#define __STDC_NO_COMPLEX__ 1
506523 \\#define __STDC_NO_THREADS__ 1
......@@ -678,6 +695,14 @@ fn generateBuiltinTypes(comp: *Compilation) !void {
678695
679696/// Smallest integer type with at least N bits
680697fn intLeastN(comp: *const Compilation, bits: usize, signedness: std.builtin.Signedness) Type {
698 if (bits == 64 and (comp.target.isDarwin() or comp.target.isWasm())) {
699 // WebAssembly and Darwin use `long long` for `int_least64_t` and `int_fast64_t`.
700 return .{ .specifier = if (signedness == .signed) .long_long else .ulong_long };
701 }
702 if (bits == 16 and comp.target.cpu.arch == .avr) {
703 // AVR uses int for int_least16_t and int_fast16_t.
704 return .{ .specifier = if (signedness == .signed) .int else .uint };
705 }
681706 const candidates = switch (signedness) {
682707 .signed => &[_]Type.Specifier{ .schar, .short, .int, .long, .long_long },
683708 .unsigned => &[_]Type.Specifier{ .uchar, .ushort, .uint, .ulong, .ulong_long },
......@@ -693,6 +718,52 @@ fn intSize(comp: *const Compilation, specifier: Type.Specifier) u64 {
693718 return ty.sizeof(comp).?;
694719}
695720
721fn generateFastOrLeastType(
722 comp: *Compilation,
723 bits: usize,
724 kind: enum { least, fast },
725 signedness: std.builtin.Signedness,
726 w: anytype,
727 mapper: StrInt.TypeMapper,
728) !void {
729 const ty = comp.intLeastN(bits, signedness); // defining the fast types as the least types is permitted
730
731 var buf: [32]u8 = undefined;
732 const suffix = "_TYPE__";
733 const base_name = switch (signedness) {
734 .signed => "__INT_",
735 .unsigned => "__UINT_",
736 };
737 const kind_str = switch (kind) {
738 .fast => "FAST",
739 .least => "LEAST",
740 };
741
742 const full = std.fmt.bufPrint(&buf, "{s}{s}{d}{s}", .{
743 base_name, kind_str, bits, suffix,
744 }) catch return error.OutOfMemory;
745
746 try generateTypeMacro(w, mapper, full, ty, comp.langopts);
747
748 const prefix = full[2 .. full.len - suffix.len]; // remove "__" and "_TYPE__"
749
750 switch (signedness) {
751 .signed => try comp.generateIntMaxAndWidth(w, prefix, ty),
752 .unsigned => try comp.generateIntMax(w, prefix, ty),
753 }
754 try comp.generateFmt(prefix, w, ty);
755}
756
757fn generateFastAndLeastWidthTypes(comp: *Compilation, w: anytype, mapper: StrInt.TypeMapper) !void {
758 const sizes = [_]usize{ 8, 16, 32, 64 };
759 for (sizes) |size| {
760 try comp.generateFastOrLeastType(size, .least, .signed, w, mapper);
761 try comp.generateFastOrLeastType(size, .least, .unsigned, w, mapper);
762 try comp.generateFastOrLeastType(size, .fast, .signed, w, mapper);
763 try comp.generateFastOrLeastType(size, .fast, .unsigned, w, mapper);
764 }
765}
766
696767fn generateExactWidthTypes(comp: *const Compilation, w: anytype, mapper: StrInt.TypeMapper) !void {
697768 try comp.generateExactWidthType(w, mapper, .schar);
698769
deps/aro/aro/Diagnostics.zig+4-3
......@@ -236,7 +236,7 @@ pub fn set(d: *Diagnostics, name: []const u8, to: Kind) !void {
236236 try d.addExtra(.{}, .{
237237 .tag = .unknown_warning,
238238 .extra = .{ .str = name },
239 }, &.{});
239 }, &.{}, true);
240240}
241241
242242pub fn init(gpa: Allocator) Diagnostics {
......@@ -251,7 +251,7 @@ pub fn deinit(d: *Diagnostics) void {
251251}
252252
253253pub fn add(comp: *Compilation, msg: Message, expansion_locs: []const Source.Location) Compilation.Error!void {
254 return comp.diagnostics.addExtra(comp.langopts, msg, expansion_locs);
254 return comp.diagnostics.addExtra(comp.langopts, msg, expansion_locs, true);
255255}
256256
257257pub fn addExtra(
......@@ -259,6 +259,7 @@ pub fn addExtra(
259259 langopts: LangOpts,
260260 msg: Message,
261261 expansion_locs: []const Source.Location,
262 note_msg_loc: bool,
262263) Compilation.Error!void {
263264 const kind = d.tagKind(msg.tag, langopts);
264265 if (kind == .off) return;
......@@ -301,7 +302,7 @@ pub fn addExtra(
301302 }
302303 }
303304
304 d.list.appendAssumeCapacity(.{
305 if (note_msg_loc) d.list.appendAssumeCapacity(.{
305306 .tag = .expanded_from_here,
306307 .kind = .note,
307308 .loc = msg.loc,
deps/aro/aro/Driver.zig+16
......@@ -98,8 +98,10 @@ pub const usage =
9898 \\ -fno-declspec Disable support for __declspec attributes
9999 \\ -ffp-eval-method=[source|double|extended]
100100 \\ Evaluation method to use for floating-point arithmetic
101 \\ -ffreestanding Compilation in a freestanding environment
101102 \\ -fgnu-inline-asm Enable GNU style inline asm (default: enabled)
102103 \\ -fno-gnu-inline-asm Disable GNU style inline asm
104 \\ -fhosted Compilation in a hosted environment
103105 \\ -fms-extensions Enable support for Microsoft extensions
104106 \\ -fno-ms-extensions Disable support for Microsoft extensions
105107 \\ -fdollars-in-identifiers
......@@ -177,6 +179,7 @@ pub fn parseArgs(
177179) !bool {
178180 var i: usize = 1;
179181 var comment_arg: []const u8 = "";
182 var hosted: ?bool = null;
180183 while (i < args.len) : (i += 1) {
181184 const arg = args[i];
182185 if (mem.startsWith(u8, arg, "-") and arg.len > 1) {
......@@ -277,6 +280,10 @@ pub fn parseArgs(
277280 d.comp.langopts.declspec_attrs = true;
278281 } else if (mem.eql(u8, arg, "-fno-declspec")) {
279282 d.comp.langopts.declspec_attrs = false;
283 } else if (mem.eql(u8, arg, "-ffreestanding")) {
284 hosted = false;
285 } else if (mem.eql(u8, arg, "-fhosted")) {
286 hosted = true;
280287 } else if (mem.eql(u8, arg, "-fms-extensions")) {
281288 d.comp.langopts.enableMSExtensions();
282289 } else if (mem.eql(u8, arg, "-fno-ms-extensions")) {
......@@ -440,6 +447,15 @@ pub fn parseArgs(
440447 if (d.comp.langopts.preserve_comments and !d.only_preprocess) {
441448 return d.fatal("invalid argument '{s}' only allowed with '-E'", .{comment_arg});
442449 }
450 if (hosted) |is_hosted| {
451 if (is_hosted) {
452 if (d.comp.target.os.tag == .freestanding) {
453 return d.fatal("Cannot use freestanding target with `-fhosted`", .{});
454 }
455 } else {
456 d.comp.target.os.tag = .freestanding;
457 }
458 }
443459 return false;
444460}
445461
deps/aro/aro/Driver/Filesystem.zig+10-10
......@@ -121,7 +121,7 @@ pub const Filesystem = union(enum) {
121121 base: []const u8,
122122 i: usize = 0,
123123
124 fn next(self: *@This()) !?std.fs.IterableDir.Entry {
124 fn next(self: *@This()) !?std.fs.Dir.Entry {
125125 while (self.i < self.entries.len) {
126126 const entry = self.entries[self.i];
127127 self.i += 1;
......@@ -130,7 +130,7 @@ pub const Filesystem = union(enum) {
130130 const remaining = entry.path[self.base.len + 1 ..];
131131 if (std.mem.indexOfScalar(u8, remaining, std.fs.path.sep) != null) continue;
132132 const extension = std.fs.path.extension(remaining);
133 const kind: std.fs.IterableDir.Entry.Kind = if (extension.len == 0) .directory else .file;
133 const kind: std.fs.Dir.Entry.Kind = if (extension.len == 0) .directory else .file;
134134 return .{ .name = remaining, .kind = kind };
135135 }
136136 }
......@@ -139,18 +139,18 @@ pub const Filesystem = union(enum) {
139139 };
140140 };
141141
142 const IterableDir = union(enum) {
143 dir: std.fs.IterableDir,
142 const Dir = union(enum) {
143 dir: std.fs.Dir,
144144 fake: FakeDir,
145145
146 pub fn iterate(self: IterableDir) Iterator {
146 pub fn iterate(self: Dir) Iterator {
147147 return switch (self) {
148148 .dir => |dir| .{ .iterator = dir.iterate() },
149149 .fake => |fake| .{ .fake = fake.iterate() },
150150 };
151151 }
152152
153 pub fn close(self: *IterableDir) void {
153 pub fn close(self: *Dir) void {
154154 switch (self.*) {
155155 .dir => |*d| d.close(),
156156 .fake => {},
......@@ -159,10 +159,10 @@ pub const Filesystem = union(enum) {
159159 };
160160
161161 const Iterator = union(enum) {
162 iterator: std.fs.IterableDir.Iterator,
162 iterator: std.fs.Dir.Iterator,
163163 fake: FakeDir.Iterator,
164164
165 pub fn next(self: *Iterator) std.fs.IterableDir.Iterator.Error!?std.fs.IterableDir.Entry {
165 pub fn next(self: *Iterator) std.fs.Dir.Iterator.Error!?std.fs.Dir.Entry {
166166 return switch (self.*) {
167167 .iterator => |*it| it.next(),
168168 .fake => |*it| it.next(),
......@@ -221,9 +221,9 @@ pub const Filesystem = union(enum) {
221221 };
222222 }
223223
224 pub fn openIterableDir(fs: Filesystem, dir_name: []const u8) std.fs.Dir.OpenError!IterableDir {
224 pub fn openDir(fs: Filesystem, dir_name: []const u8) std.fs.Dir.OpenError!Dir {
225225 return switch (fs) {
226 .real => .{ .dir = try std.fs.cwd().openIterableDir(dir_name, .{ .access_sub_paths = false }) },
226 .real => .{ .dir = try std.fs.cwd().openDir(dir_name, .{ .access_sub_paths = false, .iterate = true }) },
227227 .fake => |entries| .{ .fake = .{ .entries = entries, .path = dir_name } },
228228 };
229229 }
deps/aro/aro/Driver/GCCDetector.zig+1-1
......@@ -602,7 +602,7 @@ fn scanLibDirForGCCTriple(
602602 const lib_suffix = std.fs.path.join(suffix_buf_fib.allocator(), &.{ base, candidate_triple }) catch continue;
603603
604604 const dir_name = std.fs.path.join(fib.allocator(), &.{ lib_dir, lib_suffix }) catch continue;
605 var parent_dir = tc.filesystem.openIterableDir(dir_name) catch continue;
605 var parent_dir = tc.filesystem.openDir(dir_name) catch continue;
606606 defer parent_dir.close();
607607
608608 var it = parent_dir.iterate();
deps/aro/aro/Parser.zig+79-32
......@@ -9,6 +9,8 @@ const Tokenizer = @import("Tokenizer.zig");
99const Preprocessor = @import("Preprocessor.zig");
1010const Tree = @import("Tree.zig");
1111const Token = Tree.Token;
12const NumberPrefix = Token.NumberPrefix;
13const NumberSuffix = Token.NumberSuffix;
1214const TokenIndex = Tree.TokenIndex;
1315const NodeIndex = Tree.NodeIndex;
1416const Type = @import("Type.zig");
......@@ -24,9 +26,6 @@ const Symbol = SymbolStack.Symbol;
2426const record_layout = @import("record_layout.zig");
2527const StrInt = @import("StringInterner.zig");
2628const StringId = StrInt.StringId;
27const number_affixes = @import("number_affixes.zig");
28const NumberPrefix = number_affixes.Prefix;
29const NumberSuffix = number_affixes.Suffix;
3029const Builtins = @import("Builtins.zig");
3130const Builtin = Builtins.Builtin;
3231const target_util = @import("target.zig");
......@@ -323,7 +322,7 @@ fn expectIdentifier(p: *Parser) Error!TokenIndex {
323322 return p.errExpectedToken(.identifier, actual);
324323 }
325324
326 return (try p.eatIdentifier()) orelse unreachable;
325 return (try p.eatIdentifier()) orelse error.ParsingFailed;
327326}
328327
329328fn eatToken(p: *Parser, id: Token.Id) ?TokenIndex {
......@@ -347,7 +346,7 @@ pub fn tokSlice(p: *Parser, tok: TokenIndex) []const u8 {
347346 const loc = p.pp.tokens.items(.loc)[tok];
348347 var tmp_tokenizer = Tokenizer{
349348 .buf = p.comp.getSource(loc.id).buf,
350 .comp = p.comp,
349 .langopts = p.comp.langopts,
351350 .index = loc.byte_offset,
352351 .source = .generated,
353352 };
......@@ -715,6 +714,9 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {
715714 p.field_attr_buf.deinit();
716715 }
717716
717 try p.syms.pushScope(&p);
718 defer p.syms.popScope();
719
718720 // NodeIndex 0 must be invalid
719721 _ = try p.addNode(.{ .tag = .invalid, .ty = undefined, .data = undefined });
720722
......@@ -1010,7 +1012,7 @@ fn decl(p: *Parser) Error!bool {
10101012 // Collect old style parameter declarations.
10111013 if (init_d.d.old_style_func != null) {
10121014 const attrs = init_d.d.ty.getAttributes();
1013 var base_ty = if (init_d.d.ty.specifier == .attributed) init_d.d.ty.elemType() else init_d.d.ty;
1015 var base_ty = if (init_d.d.ty.specifier == .attributed) init_d.d.ty.data.attributed.base else init_d.d.ty;
10141016 base_ty.specifier = .func;
10151017 init_d.d.ty = try base_ty.withAttributes(p.arena, attrs);
10161018
......@@ -1066,7 +1068,7 @@ fn decl(p: *Parser) Error!bool {
10661068 d.ty = try Attribute.applyParameterAttributes(p, d.ty, attr_buf_top_declarator, .alignas_on_param);
10671069
10681070 // bypass redefinition check to avoid duplicate errors
1069 try p.syms.syms.append(p.gpa, .{
1071 try p.syms.define(p.gpa, .{
10701072 .kind = .def,
10711073 .name = interned_name,
10721074 .tok = d.name,
......@@ -1088,7 +1090,7 @@ fn decl(p: *Parser) Error!bool {
10881090 }
10891091
10901092 // bypass redefinition check to avoid duplicate errors
1091 try p.syms.syms.append(p.gpa, .{
1093 try p.syms.define(p.gpa, .{
10921094 .kind = .def,
10931095 .name = param.name,
10941096 .tok = param.name_tok,
......@@ -1428,12 +1430,14 @@ fn typeof(p: *Parser) Error!?Type {
14281430 .data = typeof_expr.ty.data,
14291431 .qual = if (unqual) .{} else typeof_expr.ty.qual.inheritFromTypeof(),
14301432 .specifier = typeof_expr.ty.specifier,
1433 .decayed = typeof_expr.ty.decayed,
14311434 },
14321435 };
14331436
14341437 return Type{
14351438 .data = .{ .expr = inner },
14361439 .specifier = .typeof_expr,
1440 .decayed = typeof_expr.ty.decayed,
14371441 };
14381442}
14391443
......@@ -1814,6 +1818,7 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
18141818 } else {
18151819 init_d.d.ty.specifier = init_d.initializer.ty.specifier;
18161820 init_d.d.ty.data = init_d.initializer.ty.data;
1821 init_d.d.ty.decayed = init_d.initializer.ty.decayed;
18171822 }
18181823 }
18191824 if (apply_var_attributes) {
......@@ -2105,7 +2110,7 @@ fn recordSpec(p: *Parser) Error!Type {
21052110 .specifier = if (is_struct) .@"struct" else .@"union",
21062111 .data = .{ .record = record_ty },
21072112 }, attr_buf_top, null);
2108 try p.syms.syms.append(p.gpa, .{
2113 try p.syms.define(p.gpa, .{
21092114 .kind = if (is_struct) .@"struct" else .@"union",
21102115 .name = interned_name,
21112116 .tok = ident,
......@@ -2151,10 +2156,8 @@ fn recordSpec(p: *Parser) Error!Type {
21512156
21522157 // declare a symbol for the type
21532158 // We need to replace the symbol's type if it has attributes
2154 var symbol_index: ?usize = null;
21552159 if (maybe_ident != null and !defined) {
2156 symbol_index = p.syms.syms.len;
2157 try p.syms.syms.append(p.gpa, .{
2160 try p.syms.define(p.gpa, .{
21582161 .kind = if (is_struct) .@"struct" else .@"union",
21592162 .name = record_ty.name,
21602163 .tok = maybe_ident.?,
......@@ -2216,8 +2219,11 @@ fn recordSpec(p: *Parser) Error!Type {
22162219 .specifier = if (is_struct) .@"struct" else .@"union",
22172220 .data = .{ .record = record_ty },
22182221 }, attr_buf_top, null);
2219 if (ty.specifier == .attributed and symbol_index != null) {
2220 p.syms.syms.items(.ty)[symbol_index.?] = ty;
2222 if (ty.specifier == .attributed and maybe_ident != null) {
2223 const ident_str = p.tokSlice(maybe_ident.?);
2224 const interned_name = try StrInt.intern(p.comp, ident_str);
2225 const ptr = p.syms.getPtr(interned_name, .tags);
2226 ptr.ty = ty;
22212227 }
22222228
22232229 if (!ty.hasIncompleteSize()) {
......@@ -2474,7 +2480,7 @@ fn enumSpec(p: *Parser) Error!Type {
24742480 .specifier = .@"enum",
24752481 .data = .{ .@"enum" = enum_ty },
24762482 }, attr_buf_top, null);
2477 try p.syms.syms.append(p.gpa, .{
2483 try p.syms.define(p.gpa, .{
24782484 .kind = .@"enum",
24792485 .name = interned_name,
24802486 .tok = ident,
......@@ -2525,7 +2531,6 @@ fn enumSpec(p: *Parser) Error!Type {
25252531 p.enum_buf.items.len = enum_buf_top;
25262532 }
25272533
2528 const sym_stack_top = p.syms.syms.len;
25292534 var e = Enumerator.init(fixed_ty);
25302535 while (try p.enumerator(&e)) |field_and_node| {
25312536 try p.enum_buf.append(field_and_node.field);
......@@ -2551,13 +2556,12 @@ fn enumSpec(p: *Parser) Error!Type {
25512556 const field_nodes = p.list_buf.items[list_buf_top..];
25522557
25532558 if (fixed_ty == null) {
2554 const vals = p.syms.syms.items(.val)[sym_stack_top..];
2555 const types = p.syms.syms.items(.ty)[sym_stack_top..];
2556
25572559 for (enum_fields, 0..) |*field, i| {
25582560 if (field.ty.eql(Type.int, p.comp, false)) continue;
25592561
2560 var res = Result{ .node = field.node, .ty = field.ty, .val = vals[i] };
2562 const sym = p.syms.get(field.name, .vars) orelse continue;
2563
2564 var res = Result{ .node = field.node, .ty = field.ty, .val = sym.val };
25612565 const dest_ty = if (p.comp.fixedEnumTagSpecifier()) |some|
25622566 Type{ .specifier = some }
25632567 else if (try res.intFitsInType(p, Type.int))
......@@ -2567,8 +2571,9 @@ fn enumSpec(p: *Parser) Error!Type {
25672571 else
25682572 continue;
25692573
2570 try vals[i].intCast(dest_ty, p.comp);
2571 types[i] = dest_ty;
2574 const symbol = p.syms.getPtr(field.name, .vars);
2575 try symbol.val.intCast(dest_ty, p.comp);
2576 symbol.ty = dest_ty;
25722577 p.nodes.items(.ty)[@intFromEnum(field_nodes[i])] = dest_ty;
25732578 field.ty = dest_ty;
25742579 res.ty = dest_ty;
......@@ -2585,7 +2590,7 @@ fn enumSpec(p: *Parser) Error!Type {
25852590
25862591 // declare a symbol for the type
25872592 if (maybe_ident != null and !defined) {
2588 try p.syms.syms.append(p.gpa, .{
2593 try p.syms.define(p.gpa, .{
25892594 .kind = .@"enum",
25902595 .name = enum_ty.name,
25912596 .ty = ty,
......@@ -2885,7 +2890,7 @@ fn declarator(
28852890 try res.ty.combine(outer);
28862891 try res.ty.validateCombinedType(p, suffix_start);
28872892 res.old_style_func = d.old_style_func;
2888 res.func_declarator = d.func_declarator;
2893 if (d.func_declarator) |some| res.func_declarator = some;
28892894 return res;
28902895 }
28912896
......@@ -4376,7 +4381,7 @@ fn stmt(p: *Parser) Error!NodeIndex {
43764381/// | keyword_default ':' stmt
43774382fn labeledStmt(p: *Parser) Error!?NodeIndex {
43784383 if ((p.tok_ids[p.tok_i] == .identifier or p.tok_ids[p.tok_i] == .extended_identifier) and p.tok_ids[p.tok_i + 1] == .colon) {
4379 const name_tok = p.expectIdentifier() catch unreachable;
4384 const name_tok = try p.expectIdentifier();
43804385 const str = p.tokSlice(name_tok);
43814386 if (p.findLabel(str)) |some| {
43824387 try p.errStr(.duplicate_label, name_tok, str);
......@@ -4814,10 +4819,23 @@ const CallExpr = union(enum) {
48144819 /// of arguments, `paramCountOverride` is used to tell us how many arguments we should actually expect to see for
48154820 /// these custom-typechecked functions.
48164821 fn paramCountOverride(self: CallExpr) ?u32 {
4822 @setEvalBranchQuota(10_000);
48174823 return switch (self) {
48184824 .standard => null,
48194825 .builtin => |builtin| switch (builtin.tag) {
48204826 Builtin.tagFromName("__builtin_complex").? => 2,
4827
4828 Builtin.tagFromName("__atomic_fetch_add").?,
4829 Builtin.tagFromName("__atomic_fetch_sub").?,
4830 Builtin.tagFromName("__atomic_fetch_and").?,
4831 Builtin.tagFromName("__atomic_fetch_xor").?,
4832 Builtin.tagFromName("__atomic_fetch_or").?,
4833 Builtin.tagFromName("__atomic_fetch_nand").?,
4834 => 3,
4835
4836 Builtin.tagFromName("__atomic_compare_exchange").?,
4837 Builtin.tagFromName("__atomic_compare_exchange_n").?,
4838 => 6,
48214839 else => null,
48224840 },
48234841 };
......@@ -4827,10 +4845,25 @@ const CallExpr = union(enum) {
48274845 return switch (self) {
48284846 .standard => callable_ty.returnType(),
48294847 .builtin => |builtin| switch (builtin.tag) {
4848 Builtin.tagFromName("__atomic_fetch_add").?,
4849 Builtin.tagFromName("__atomic_fetch_sub").?,
4850 Builtin.tagFromName("__atomic_fetch_and").?,
4851 Builtin.tagFromName("__atomic_fetch_xor").?,
4852 Builtin.tagFromName("__atomic_fetch_or").?,
4853 Builtin.tagFromName("__atomic_fetch_nand").?,
4854 => {
4855 if (p.list_buf.items.len < 2) return Type.invalid; // not enough arguments; already an error
4856 const second_param = p.list_buf.items[p.list_buf.items.len - 2];
4857 return p.nodes.items(.ty)[@intFromEnum(second_param)];
4858 },
48304859 Builtin.tagFromName("__builtin_complex").? => {
4860 if (p.list_buf.items.len < 1) return Type.invalid; // not enough arguments; already an error
48314861 const last_param = p.list_buf.items[p.list_buf.items.len - 1];
48324862 return p.nodes.items(.ty)[@intFromEnum(last_param)].makeComplex();
48334863 },
4864 Builtin.tagFromName("__atomic_compare_exchange").?,
4865 Builtin.tagFromName("__atomic_compare_exchange_n").?,
4866 => .{ .specifier = .bool },
48344867 else => callable_ty.returnType(),
48354868 },
48364869 };
......@@ -7458,7 +7491,7 @@ fn primaryExpr(p: *Parser) Error!Result {
74587491 }
74597492 switch (p.tok_ids[p.tok_i]) {
74607493 .identifier, .extended_identifier => {
7461 const name_tok = p.expectIdentifier() catch unreachable;
7494 const name_tok = try p.expectIdentifier();
74627495 const name = p.tokSlice(name_tok);
74637496 const interned_name = try StrInt.intern(p.comp, name);
74647497 if (p.syms.findSymbol(interned_name)) |sym| {
......@@ -7938,6 +7971,8 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {
79387971 .F, .IF => .float,
79397972 .F16 => .float16,
79407973 .L, .IL => .long_double,
7974 .W, .IW => .float80,
7975 .Q, .IQ, .F128, .IF128 => .float128,
79417976 else => unreachable,
79427977 } };
79437978 const val = try Value.intern(p.comp, key: {
......@@ -7946,7 +7981,7 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {
79467981 const strings_top = p.strings.items.len;
79477982 defer p.strings.items.len = strings_top;
79487983 for (buf) |c| {
7949 if (c != '_') p.strings.appendAssumeCapacity(c);
7984 if (c != '\'') p.strings.appendAssumeCapacity(c);
79507985 }
79517986
79527987 const float = std.fmt.parseFloat(f128, p.strings.items[strings_top..]) catch unreachable;
......@@ -7971,6 +8006,8 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {
79718006 .I => .complex_double,
79728007 .IF => .complex_float,
79738008 .IL => .complex_long_double,
8009 .IW => .complex_float80,
8010 .IQ, .IF128 => .complex_float128,
79748011 else => unreachable,
79758012 } };
79768013 res.val = .{}; // TODO add complex values
......@@ -8123,11 +8160,21 @@ fn bitInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok_i: To
81238160 var managed = try big.int.Managed.init(p.gpa);
81248161 defer managed.deinit();
81258162
8126 managed.setString(base, buf) catch |e| switch (e) {
8127 error.InvalidBase => unreachable, // `base` is one of 2, 8, 10, 16
8128 error.InvalidCharacter => unreachable, // digits validated by Tokenizer
8129 else => |er| return er,
8130 };
8163 {
8164 try p.strings.ensureUnusedCapacity(buf.len);
8165
8166 const strings_top = p.strings.items.len;
8167 defer p.strings.items.len = strings_top;
8168 for (buf) |c| {
8169 if (c != '\'') p.strings.appendAssumeCapacity(c);
8170 }
8171
8172 managed.setString(base, p.strings.items[strings_top..]) catch |e| switch (e) {
8173 error.InvalidBase => unreachable, // `base` is one of 2, 8, 10, 16
8174 error.InvalidCharacter => unreachable, // digits validated by Tokenizer
8175 else => |er| return er,
8176 };
8177 }
81318178 const c = managed.toConst();
81328179 const bits_needed: std.math.IntFittingRange(0, Compilation.bit_int_max_bits) = blk: {
81338180 // Literal `0` requires at least 1 bit
deps/aro/aro/Preprocessor.zig+60-25
......@@ -315,7 +315,7 @@ fn invalidTokenDiagnostic(tok_id: Token.Id) Diagnostics.Tag {
315315fn findIncludeGuard(pp: *Preprocessor, source: Source) ?[]const u8 {
316316 var tokenizer = Tokenizer{
317317 .buf = source.buf,
318 .comp = pp.comp,
318 .langopts = pp.comp.langopts,
319319 .source = source.id,
320320 };
321321 var hash = tokenizer.nextNoWS();
......@@ -334,7 +334,7 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
334334 pp.preprocess_count += 1;
335335 var tokenizer = Tokenizer{
336336 .buf = source.buf,
337 .comp = pp.comp,
337 .langopts = pp.comp.langopts,
338338 .source = source.id,
339339 };
340340
......@@ -747,6 +747,17 @@ fn fatal(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anyty
747747 return error.FatalError;
748748}
749749
750fn fatalNotFound(pp: *Preprocessor, tok: Token, filename: []const u8) Compilation.Error {
751 const old = pp.comp.diagnostics.fatal_errors;
752 pp.comp.diagnostics.fatal_errors = true;
753 defer pp.comp.diagnostics.fatal_errors = old;
754
755 try pp.comp.diagnostics.addExtra(pp.comp.langopts, .{ .tag = .cli_error, .loc = tok.loc, .extra = .{
756 .str = try std.fmt.allocPrint(pp.comp.diagnostics.arena.allocator(), "'{s}' not found", .{filename}),
757 } }, tok.expansionSlice(), false);
758 unreachable; // addExtra should've returned FatalError
759}
760
750761fn verboseLog(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anytype) void {
751762 const source = pp.comp.getSource(raw.source);
752763 const line_col = source.lineCol(.{ .id = raw.source, .line = raw.line, .byte_offset = raw.start });
......@@ -1185,7 +1196,7 @@ fn pragmaOperator(pp: *Preprocessor, arg_tok: Token, operator_loc: Source.Locati
11851196 try pp.comp.generated_buf.appendSlice(pp.gpa, pp.char_buf.items);
11861197 var tmp_tokenizer = Tokenizer{
11871198 .buf = pp.comp.generated_buf.items,
1188 .comp = pp.comp,
1199 .langopts = pp.comp.langopts,
11891200 .index = @intCast(start),
11901201 .source = .generated,
11911202 .line = pp.generated_line,
......@@ -1864,7 +1875,7 @@ fn expandVaOpt(
18641875 .buf = source.buf,
18651876 .index = raw.start,
18661877 .source = raw.source,
1867 .comp = pp.comp,
1878 .langopts = pp.comp.langopts,
18681879 .line = raw.line,
18691880 };
18701881 while (tokenizer.index < raw.end) {
......@@ -2282,11 +2293,11 @@ fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, raw: RawToken) MacroErr
22822293
22832294fn expandedSliceExtra(pp: *const Preprocessor, tok: Token, macro_ws_handling: enum { single_macro_ws, preserve_macro_ws }) []const u8 {
22842295 if (tok.id.lexeme()) |some| {
2285 if (!tok.id.allowsDigraphs(pp.comp) and !(tok.id == .macro_ws and macro_ws_handling == .preserve_macro_ws)) return some;
2296 if (!tok.id.allowsDigraphs(pp.comp.langopts) and !(tok.id == .macro_ws and macro_ws_handling == .preserve_macro_ws)) return some;
22862297 }
22872298 var tmp_tokenizer = Tokenizer{
22882299 .buf = pp.comp.getSource(tok.loc.id).buf,
2289 .comp = pp.comp,
2300 .langopts = pp.comp.langopts,
22902301 .index = tok.loc.byte_offset,
22912302 .source = .generated,
22922303 };
......@@ -2340,7 +2351,7 @@ fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token)
23402351 // Try to tokenize the result.
23412352 var tmp_tokenizer = Tokenizer{
23422353 .buf = pp.comp.generated_buf.items,
2343 .comp = pp.comp,
2354 .langopts = pp.comp.langopts,
23442355 .index = @intCast(start),
23452356 .source = .generated,
23462357 };
......@@ -2703,6 +2714,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
27032714 error.InvalidInclude => return,
27042715 else => |e| return e,
27052716 };
2717 defer Token.free(filename_tok.expansion_locs, pp.gpa);
27062718
27072719 // Check for empty filename.
27082720 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);
......@@ -2836,7 +2848,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
28362848 }
28372849
28382850 const embed_bytes = (try pp.comp.findEmbed(filename, first.source, include_type, limit)) orelse
2839 return pp.fatal(first, "'{s}' not found", .{filename});
2851 return pp.fatalNotFound(filename_tok, filename);
28402852 defer pp.comp.gpa.free(embed_bytes);
28412853
28422854 try Range.expand(prefix, pp, tokenizer);
......@@ -2984,8 +2996,6 @@ fn findIncludeFilenameToken(
29842996 tokenizer: *Tokenizer,
29852997 trailing_token_behavior: enum { ignore_trailing_tokens, expect_nl_eof },
29862998) !Token {
2987 const start = pp.tokens.len;
2988 defer pp.tokens.len = start;
29892999 var first = first_token;
29903000
29913001 if (first.id == .angle_bracket_left) to_end: {
......@@ -3008,35 +3018,60 @@ fn findIncludeFilenameToken(
30083018 }, &.{});
30093019 try pp.err(first, .header_str_match);
30103020 }
3011 // Try to expand if the argument is a macro.
3012 try pp.expandMacro(tokenizer, first);
30133021
3014 // Check that we actually got a string.
3015 const filename_tok = pp.tokens.get(start);
3016 switch (filename_tok.id) {
3017 .string_literal, .macro_string => {},
3018 else => {
3019 try pp.err(first, .expected_filename);
3020 try pp.expectNl(tokenizer);
3021 return error.InvalidInclude;
3022 const source_tok = tokFromRaw(first);
3023 const filename_tok, const expanded_trailing = switch (source_tok.id) {
3024 .string_literal, .macro_string => .{ source_tok, false },
3025 else => expanded: {
3026 // Try to expand if the argument is a macro.
3027 pp.top_expansion_buf.items.len = 0;
3028 defer for (pp.top_expansion_buf.items) |tok| Token.free(tok.expansion_locs, pp.gpa);
3029 try pp.top_expansion_buf.append(source_tok);
3030 pp.expansion_source_loc = source_tok.loc;
3031
3032 try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, 1, true, .non_expr);
3033 var trailing_toks: []const Token = &.{};
3034 const include_str = (try pp.reconstructIncludeString(pp.top_expansion_buf.items, &trailing_toks)) orelse {
3035 try pp.err(first, .expected_filename);
3036 try pp.expectNl(tokenizer);
3037 return error.InvalidInclude;
3038 };
3039 const start = pp.comp.generated_buf.items.len;
3040 try pp.comp.generated_buf.appendSlice(pp.gpa, include_str);
3041
3042 break :expanded .{ try pp.makeGeneratedToken(start, switch (include_str[0]) {
3043 '"' => .string_literal,
3044 '<' => .macro_string,
3045 else => unreachable,
3046 }, pp.top_expansion_buf.items[0]), trailing_toks.len != 0 };
30223047 },
3023 }
3048 };
3049
30243050 switch (trailing_token_behavior) {
30253051 .expect_nl_eof => {
30263052 // Error on extra tokens.
30273053 const nl = tokenizer.nextNoWS();
3028 if ((nl.id != .nl and nl.id != .eof) or pp.tokens.len > start + 1) {
3054 if ((nl.id != .nl and nl.id != .eof) or expanded_trailing) {
30293055 skipToNl(tokenizer);
3030 try pp.err(first, .extra_tokens_directive_end);
3056 try pp.comp.diagnostics.addExtra(pp.comp.langopts, .{
3057 .tag = .extra_tokens_directive_end,
3058 .loc = filename_tok.loc,
3059 }, filename_tok.expansionSlice(), false);
30313060 }
30323061 },
3033 .ignore_trailing_tokens => {},
3062 .ignore_trailing_tokens => if (expanded_trailing) {
3063 try pp.comp.diagnostics.addExtra(pp.comp.langopts, .{
3064 .tag = .extra_tokens_directive_end,
3065 .loc = filename_tok.loc,
3066 }, filename_tok.expansionSlice(), false);
3067 },
30343068 }
30353069 return filename_tok;
30363070}
30373071
30383072fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken, which: Compilation.WhichInclude) !Source {
30393073 const filename_tok = try pp.findIncludeFilenameToken(first, tokenizer, .expect_nl_eof);
3074 defer Token.free(filename_tok.expansion_locs, pp.gpa);
30403075
30413076 // Check for empty filename.
30423077 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);
......@@ -3054,7 +3089,7 @@ fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken,
30543089 };
30553090
30563091 return (try pp.comp.findInclude(filename, first, include_type, which)) orelse
3057 pp.fatal(first, "'{s}' not found", .{filename});
3092 return pp.fatalNotFound(filename_tok, filename);
30583093}
30593094
30603095fn printLinemarker(
deps/aro/aro/SymbolStack.zig+201-184
......@@ -11,6 +11,8 @@ const Parser = @import("Parser.zig");
1111const Value = @import("Value.zig");
1212const StringId = @import("StringInterner.zig").StringId;
1313
14const SymbolStack = @This();
15
1416pub const Symbol = struct {
1517 name: StringId,
1618 ty: Type,
......@@ -31,72 +33,74 @@ pub const Kind = enum {
3133 constexpr,
3234};
3335
34const SymbolStack = @This();
36scopes: std.ArrayListUnmanaged(Scope) = .{},
37/// allocations from nested scopes are retained after popping; `active_len` is the number
38/// of currently-active items in `scopes`.
39active_len: usize = 0,
3540
36syms: std.MultiArrayList(Symbol) = .{},
37scopes: std.ArrayListUnmanaged(u32) = .{},
41const Scope = struct {
42 vars: std.AutoHashMapUnmanaged(StringId, Symbol) = .{},
43 tags: std.AutoHashMapUnmanaged(StringId, Symbol) = .{},
44
45 fn deinit(self: *Scope, allocator: Allocator) void {
46 self.vars.deinit(allocator);
47 self.tags.deinit(allocator);
48 }
49
50 fn clearRetainingCapacity(self: *Scope) void {
51 self.vars.clearRetainingCapacity();
52 self.tags.clearRetainingCapacity();
53 }
54};
3855
3956pub fn deinit(s: *SymbolStack, gpa: Allocator) void {
40 s.syms.deinit(gpa);
57 std.debug.assert(s.active_len == 0); // all scopes should have been popped
58 for (s.scopes.items) |*scope| {
59 scope.deinit(gpa);
60 }
4161 s.scopes.deinit(gpa);
4262 s.* = undefined;
4363}
4464
45pub fn scopeEnd(s: SymbolStack) u32 {
46 if (s.scopes.items.len == 0) return 0;
47 return s.scopes.items[s.scopes.items.len - 1];
48}
49
5065pub fn pushScope(s: *SymbolStack, p: *Parser) !void {
51 try s.scopes.append(p.gpa, @intCast(s.syms.len));
66 if (s.active_len + 1 > s.scopes.items.len) {
67 try s.scopes.append(p.gpa, .{});
68 s.active_len = s.scopes.items.len;
69 } else {
70 s.scopes.items[s.active_len].clearRetainingCapacity();
71 s.active_len += 1;
72 }
5273}
5374
5475pub fn popScope(s: *SymbolStack) void {
55 s.syms.len = s.scopes.pop();
76 s.active_len -= 1;
5677}
5778
5879pub fn findTypedef(s: *SymbolStack, p: *Parser, name: StringId, name_tok: TokenIndex, no_type_yet: bool) !?Symbol {
59 const kinds = s.syms.items(.kind);
60 const names = s.syms.items(.name);
61 var i = s.syms.len;
62 while (i > 0) {
63 i -= 1;
64 switch (kinds[i]) {
65 .typedef => if (names[i] == name) return s.syms.get(i),
66 .@"struct" => if (names[i] == name) {
67 if (no_type_yet) return null;
68 try p.errStr(.must_use_struct, name_tok, p.tokSlice(name_tok));
69 return s.syms.get(i);
70 },
71 .@"union" => if (names[i] == name) {
72 if (no_type_yet) return null;
73 try p.errStr(.must_use_union, name_tok, p.tokSlice(name_tok));
74 return s.syms.get(i);
75 },
76 .@"enum" => if (names[i] == name) {
77 if (no_type_yet) return null;
78 try p.errStr(.must_use_enum, name_tok, p.tokSlice(name_tok));
79 return s.syms.get(i);
80 },
81 .def, .decl, .constexpr => if (names[i] == name) return null,
82 else => {},
83 }
80 const prev = s.lookup(name, .vars) orelse s.lookup(name, .tags) orelse return null;
81 switch (prev.kind) {
82 .typedef => return prev,
83 .@"struct" => {
84 if (no_type_yet) return null;
85 try p.errStr(.must_use_struct, name_tok, p.tokSlice(name_tok));
86 return prev;
87 },
88 .@"union" => {
89 if (no_type_yet) return null;
90 try p.errStr(.must_use_union, name_tok, p.tokSlice(name_tok));
91 return prev;
92 },
93 .@"enum" => {
94 if (no_type_yet) return null;
95 try p.errStr(.must_use_enum, name_tok, p.tokSlice(name_tok));
96 return prev;
97 },
98 else => return null,
8499 }
85 return null;
86100}
87101
88102pub fn findSymbol(s: *SymbolStack, name: StringId) ?Symbol {
89 const kinds = s.syms.items(.kind);
90 const names = s.syms.items(.name);
91 var i = s.syms.len;
92 while (i > 0) {
93 i -= 1;
94 switch (kinds[i]) {
95 .def, .decl, .enumeration, .constexpr => if (names[i] == name) return s.syms.get(i),
96 else => {},
97 }
98 }
99 return null;
103 return s.lookup(name, .vars);
100104}
101105
102106pub fn findTag(
......@@ -107,36 +111,62 @@ pub fn findTag(
107111 name_tok: TokenIndex,
108112 next_tok_id: Token.Id,
109113) !?Symbol {
110 const kinds = s.syms.items(.kind);
111 const names = s.syms.items(.name);
112114 // `tag Name;` should always result in a new type if in a new scope.
113 const end = if (next_tok_id == .semicolon) s.scopeEnd() else 0;
114 var i = s.syms.len;
115 while (i > end) {
115 const prev = (if (next_tok_id == .semicolon) s.get(name, .tags) else s.lookup(name, .tags)) orelse return null;
116 switch (prev.kind) {
117 .@"enum" => if (kind == .keyword_enum) return prev,
118 .@"struct" => if (kind == .keyword_struct) return prev,
119 .@"union" => if (kind == .keyword_union) return prev,
120 else => unreachable,
121 }
122 if (s.get(name, .tags) == null) return null;
123 try p.errStr(.wrong_tag, name_tok, p.tokSlice(name_tok));
124 try p.errTok(.previous_definition, prev.tok);
125 return null;
126}
127
128const ScopeKind = enum {
129 /// structs, enums, unions
130 tags,
131 /// everything else
132 vars,
133};
134
135/// Return the Symbol for `name` (or null if not found) in the innermost scope
136pub fn get(s: *SymbolStack, name: StringId, kind: ScopeKind) ?Symbol {
137 return switch (kind) {
138 .vars => s.scopes.items[s.active_len - 1].vars.get(name),
139 .tags => s.scopes.items[s.active_len - 1].tags.get(name),
140 };
141}
142
143/// Return the Symbol for `name` (or null if not found) in the nearest active scope,
144/// starting at the innermost.
145fn lookup(s: *SymbolStack, name: StringId, kind: ScopeKind) ?Symbol {
146 var i = s.active_len;
147 while (i > 0) {
116148 i -= 1;
117 switch (kinds[i]) {
118 .@"enum" => if (names[i] == name) {
119 if (kind == .keyword_enum) return s.syms.get(i);
120 break;
121 },
122 .@"struct" => if (names[i] == name) {
123 if (kind == .keyword_struct) return s.syms.get(i);
124 break;
125 },
126 .@"union" => if (names[i] == name) {
127 if (kind == .keyword_union) return s.syms.get(i);
128 break;
129 },
130 else => {},
149 switch (kind) {
150 .vars => if (s.scopes.items[i].vars.get(name)) |sym| return sym,
151 .tags => if (s.scopes.items[i].tags.get(name)) |sym| return sym,
131152 }
132 } else return null;
133
134 if (i < s.scopeEnd()) return null;
135 try p.errStr(.wrong_tag, name_tok, p.tokSlice(name_tok));
136 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
153 }
137154 return null;
138155}
139156
157/// Define a symbol in the innermost scope. Does not issue diagnostics or check correctness
158/// with regard to the C standard.
159pub fn define(s: *SymbolStack, allocator: Allocator, symbol: Symbol) !void {
160 switch (symbol.kind) {
161 .constexpr, .def, .decl, .enumeration, .typedef => {
162 try s.scopes.items[s.active_len - 1].vars.put(allocator, symbol.name, symbol);
163 },
164 .@"struct", .@"union", .@"enum" => {
165 try s.scopes.items[s.active_len - 1].tags.put(allocator, symbol.name, symbol);
166 },
167 }
168}
169
140170pub fn defineTypedef(
141171 s: *SymbolStack,
142172 p: *Parser,
......@@ -145,25 +175,22 @@ pub fn defineTypedef(
145175 tok: TokenIndex,
146176 node: NodeIndex,
147177) !void {
148 const kinds = s.syms.items(.kind);
149 const names = s.syms.items(.name);
150 const end = s.scopeEnd();
151 var i = s.syms.len;
152 while (i > end) {
153 i -= 1;
154 switch (kinds[i]) {
155 .typedef => if (names[i] == name) {
156 const prev_ty = s.syms.items(.ty)[i];
157 if (ty.eql(prev_ty, p.comp, true)) break;
158 try p.errStr(.redefinition_of_typedef, tok, try p.typePairStrExtra(ty, " vs ", prev_ty));
159 const previous_tok = s.syms.items(.tok)[i];
160 if (previous_tok != 0) try p.errTok(.previous_definition, previous_tok);
161 break;
178 if (s.get(name, .vars)) |prev| {
179 switch (prev.kind) {
180 .typedef => {
181 if (!ty.eql(prev.ty, p.comp, true)) {
182 try p.errStr(.redefinition_of_typedef, tok, try p.typePairStrExtra(ty, " vs ", prev.ty));
183 if (prev.tok != 0) try p.errTok(.previous_definition, prev.tok);
184 }
185 },
186 .enumeration, .decl, .def, .constexpr => {
187 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
188 try p.errTok(.previous_definition, prev.tok);
162189 },
163 else => {},
190 else => unreachable,
164191 }
165192 }
166 try s.syms.append(p.gpa, .{
193 try s.define(p.gpa, .{
167194 .kind = .typedef,
168195 .name = name,
169196 .tok = tok,
......@@ -183,35 +210,31 @@ pub fn defineSymbol(
183210 val: Value,
184211 constexpr: bool,
185212) !void {
186 const kinds = s.syms.items(.kind);
187 const names = s.syms.items(.name);
188 const end = s.scopeEnd();
189 var i = s.syms.len;
190 while (i > end) {
191 i -= 1;
192 switch (kinds[i]) {
193 .enumeration => if (names[i] == name) {
213 if (s.get(name, .vars)) |prev| {
214 switch (prev.kind) {
215 .enumeration => {
194216 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
195 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
196 break;
217 try p.errTok(.previous_definition, prev.tok);
197218 },
198 .decl => if (names[i] == name) {
199 const prev_ty = s.syms.items(.ty)[i];
200 if (!ty.eql(prev_ty, p.comp, true)) {
219 .decl => {
220 if (!ty.eql(prev.ty, p.comp, true)) {
201221 try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok));
202 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
222 try p.errTok(.previous_definition, prev.tok);
203223 }
204 break;
205224 },
206 .def, .constexpr => if (names[i] == name) {
225 .def, .constexpr => {
207226 try p.errStr(.redefinition, tok, p.tokSlice(tok));
208 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
209 break;
227 try p.errTok(.previous_definition, prev.tok);
210228 },
211 else => {},
229 .typedef => {
230 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
231 try p.errTok(.previous_definition, prev.tok);
232 },
233 else => unreachable,
212234 }
213235 }
214 try s.syms.append(p.gpa, .{
236
237 try s.define(p.gpa, .{
215238 .kind = if (constexpr) .constexpr else .def,
216239 .name = name,
217240 .tok = tok,
......@@ -221,6 +244,15 @@ pub fn defineSymbol(
221244 });
222245}
223246
247/// Get a pointer to the named symbol in the innermost scope.
248/// Asserts that a symbol with the name exists.
249pub fn getPtr(s: *SymbolStack, name: StringId, kind: ScopeKind) *Symbol {
250 return switch (kind) {
251 .tags => s.scopes.items[s.active_len - 1].tags.getPtr(name).?,
252 .vars => s.scopes.items[s.active_len - 1].vars.getPtr(name).?,
253 };
254}
255
224256pub fn declareSymbol(
225257 s: *SymbolStack,
226258 p: *Parser,
......@@ -229,39 +261,34 @@ pub fn declareSymbol(
229261 tok: TokenIndex,
230262 node: NodeIndex,
231263) !void {
232 const kinds = s.syms.items(.kind);
233 const names = s.syms.items(.name);
234 const end = s.scopeEnd();
235 var i = s.syms.len;
236 while (i > end) {
237 i -= 1;
238 switch (kinds[i]) {
239 .enumeration => if (names[i] == name) {
264 if (s.get(name, .vars)) |prev| {
265 switch (prev.kind) {
266 .enumeration => {
240267 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
241 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
242 break;
268 try p.errTok(.previous_definition, prev.tok);
243269 },
244 .decl => if (names[i] == name) {
245 const prev_ty = s.syms.items(.ty)[i];
246 if (!ty.eql(prev_ty, p.comp, true)) {
270 .decl => {
271 if (!ty.eql(prev.ty, p.comp, true)) {
247272 try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok));
248 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
273 try p.errTok(.previous_definition, prev.tok);
249274 }
250 break;
251275 },
252 .def, .constexpr => if (names[i] == name) {
253 const prev_ty = s.syms.items(.ty)[i];
254 if (!ty.eql(prev_ty, p.comp, true)) {
276 .def, .constexpr => {
277 if (!ty.eql(prev.ty, p.comp, true)) {
255278 try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok));
256 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
257 break;
279 try p.errTok(.previous_definition, prev.tok);
280 } else {
281 return;
258282 }
259 return;
260283 },
261 else => {},
284 .typedef => {
285 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
286 try p.errTok(.previous_definition, prev.tok);
287 },
288 else => unreachable,
262289 }
263290 }
264 try s.syms.append(p.gpa, .{
291 try s.define(p.gpa, .{
265292 .kind = .decl,
266293 .name = name,
267294 .tok = tok,
......@@ -272,25 +299,23 @@ pub fn declareSymbol(
272299}
273300
274301pub fn defineParam(s: *SymbolStack, p: *Parser, name: StringId, ty: Type, tok: TokenIndex) !void {
275 const kinds = s.syms.items(.kind);
276 const names = s.syms.items(.name);
277 const end = s.scopeEnd();
278 var i = s.syms.len;
279 while (i > end) {
280 i -= 1;
281 switch (kinds[i]) {
282 .enumeration, .decl, .def, .constexpr => if (names[i] == name) {
302 if (s.get(name, .vars)) |prev| {
303 switch (prev.kind) {
304 .enumeration, .decl, .def, .constexpr => {
283305 try p.errStr(.redefinition_of_parameter, tok, p.tokSlice(tok));
284 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
285 break;
306 try p.errTok(.previous_definition, prev.tok);
307 },
308 .typedef => {
309 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
310 try p.errTok(.previous_definition, prev.tok);
286311 },
287 else => {},
312 else => unreachable,
288313 }
289314 }
290315 if (ty.is(.fp16) and !p.comp.hasHalfPrecisionFloatABI()) {
291316 try p.errStr(.suggest_pointer_for_invalid_fp16, tok, "parameters");
292317 }
293 try s.syms.append(p.gpa, .{
318 try s.define(p.gpa, .{
294319 .kind = .def,
295320 .name = name,
296321 .tok = tok,
......@@ -306,35 +331,28 @@ pub fn defineTag(
306331 kind: Token.Id,
307332 tok: TokenIndex,
308333) !?Symbol {
309 const kinds = s.syms.items(.kind);
310 const names = s.syms.items(.name);
311 const end = s.scopeEnd();
312 var i = s.syms.len;
313 while (i > end) {
314 i -= 1;
315 switch (kinds[i]) {
316 .@"enum" => if (names[i] == name) {
317 if (kind == .keyword_enum) return s.syms.get(i);
318 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
319 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
320 return null;
321 },
322 .@"struct" => if (names[i] == name) {
323 if (kind == .keyword_struct) return s.syms.get(i);
324 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
325 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
326 return null;
327 },
328 .@"union" => if (names[i] == name) {
329 if (kind == .keyword_union) return s.syms.get(i);
330 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
331 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
332 return null;
333 },
334 else => {},
335 }
334 const prev = s.get(name, .tags) orelse return null;
335 switch (prev.kind) {
336 .@"enum" => {
337 if (kind == .keyword_enum) return prev;
338 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
339 try p.errTok(.previous_definition, prev.tok);
340 return null;
341 },
342 .@"struct" => {
343 if (kind == .keyword_struct) return prev;
344 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
345 try p.errTok(.previous_definition, prev.tok);
346 return null;
347 },
348 .@"union" => {
349 if (kind == .keyword_union) return prev;
350 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
351 try p.errTok(.previous_definition, prev.tok);
352 return null;
353 },
354 else => unreachable,
336355 }
337 return null;
338356}
339357
340358pub fn defineEnumeration(
......@@ -345,27 +363,26 @@ pub fn defineEnumeration(
345363 tok: TokenIndex,
346364 val: Value,
347365) !void {
348 const kinds = s.syms.items(.kind);
349 const names = s.syms.items(.name);
350 const end = s.scopeEnd();
351 var i = s.syms.len;
352 while (i > end) {
353 i -= 1;
354 switch (kinds[i]) {
355 .enumeration => if (names[i] == name) {
366 if (s.get(name, .vars)) |prev| {
367 switch (prev.kind) {
368 .enumeration => {
356369 try p.errStr(.redefinition, tok, p.tokSlice(tok));
357 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
370 try p.errTok(.previous_definition, prev.tok);
358371 return;
359372 },
360 .decl, .def, .constexpr => if (names[i] == name) {
373 .decl, .def, .constexpr => {
361374 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
362 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);
375 try p.errTok(.previous_definition, prev.tok);
363376 return;
364377 },
365 else => {},
378 .typedef => {
379 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
380 try p.errTok(.previous_definition, prev.tok);
381 },
382 else => unreachable,
366383 }
367384 }
368 try s.syms.append(p.gpa, .{
385 try s.define(p.gpa, .{
369386 .kind = .enumeration,
370387 .name = name,
371388 .tok = tok,
deps/aro/aro/Tokenizer.zig+26-23
......@@ -749,12 +749,15 @@ pub const Token = struct {
749749 .string_literal_utf_8,
750750 .string_literal_utf_32,
751751 .string_literal_wide,
752 .unterminated_string_literal,
752753 => "a string literal",
753754 .char_literal,
754755 .char_literal_utf_8,
755756 .char_literal_utf_16,
756757 .char_literal_utf_32,
757758 .char_literal_wide,
759 .unterminated_char_literal,
760 .empty_char_literal,
758761 => "a character literal",
759762 .pp_num, .embed_byte => "A number",
760763 else => id.lexeme().?,
......@@ -798,7 +801,7 @@ pub const Token = struct {
798801 };
799802 }
800803
801 pub fn allowsDigraphs(id: Id, comp: *const Compilation) bool {
804 pub fn allowsDigraphs(id: Id, langopts: LangOpts) bool {
802805 return switch (id) {
803806 .l_bracket,
804807 .r_bracket,
......@@ -806,7 +809,7 @@ pub const Token = struct {
806809 .r_brace,
807810 .hash,
808811 .hash_hash,
809 => comp.langopts.hasDigraphs(),
812 => langopts.hasDigraphs(),
810813 else => false,
811814 };
812815 }
......@@ -829,15 +832,15 @@ pub const Token = struct {
829832 /// double underscore and underscore + capital letter identifiers
830833 /// belong to the implementation namespace, so we always convert them
831834 /// to keywords.
832 pub fn getTokenId(comp: *const Compilation, str: []const u8) Token.Id {
835 pub fn getTokenId(langopts: LangOpts, str: []const u8) Token.Id {
833836 const kw = all_kws.get(str) orelse return .identifier;
834 const standard = comp.langopts.standard;
837 const standard = langopts.standard;
835838 return switch (kw) {
836839 .keyword_inline => if (standard.isGNU() or standard.atLeast(.c99)) kw else .identifier,
837840 .keyword_restrict => if (standard.atLeast(.c99)) kw else .identifier,
838841 .keyword_typeof => if (standard.isGNU() or standard.atLeast(.c23)) kw else .identifier,
839842 .keyword_asm => if (standard.isGNU()) kw else .identifier,
840 .keyword_declspec => if (comp.langopts.declspec_attrs) kw else .identifier,
843 .keyword_declspec => if (langopts.declspec_attrs) kw else .identifier,
841844
842845 .keyword_c23_alignas,
843846 .keyword_c23_alignof,
......@@ -864,7 +867,7 @@ pub const Token = struct {
864867 .keyword_stdcall2,
865868 .keyword_thiscall2,
866869 .keyword_vectorcall2,
867 => if (comp.langopts.ms_extensions) kw else .identifier,
870 => if (langopts.ms_extensions) kw else .identifier,
868871 else => kw,
869872 };
870873 }
......@@ -1023,7 +1026,7 @@ const Tokenizer = @This();
10231026buf: []const u8,
10241027index: u32 = 0,
10251028source: Source.Id,
1026comp: *const Compilation,
1029langopts: LangOpts,
10271030line: u32 = 1,
10281031
10291032pub fn next(self: *Tokenizer) Token {
......@@ -1162,14 +1165,14 @@ pub fn next(self: *Tokenizer) Token {
11621165 '#' => state = .hash,
11631166 '0'...'9' => state = .pp_num,
11641167 '\t', '\x0B', '\x0C', ' ' => state = .whitespace,
1165 '$' => if (self.comp.langopts.dollars_in_identifiers) {
1168 '$' => if (self.langopts.dollars_in_identifiers) {
11661169 state = .extended_identifier;
11671170 } else {
11681171 id = .invalid;
11691172 self.index += 1;
11701173 break;
11711174 },
1172 0x1A => if (self.comp.langopts.ms_extensions) {
1175 0x1A => if (self.langopts.ms_extensions) {
11731176 id = .eof;
11741177 break;
11751178 } else {
......@@ -1306,15 +1309,15 @@ pub fn next(self: *Tokenizer) Token {
13061309 },
13071310 .identifier, .extended_identifier => switch (c) {
13081311 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
1309 '$' => if (self.comp.langopts.dollars_in_identifiers) {
1312 '$' => if (self.langopts.dollars_in_identifiers) {
13101313 state = .extended_identifier;
13111314 } else {
1312 id = if (state == .identifier) Token.getTokenId(self.comp, self.buf[start..self.index]) else .extended_identifier;
1315 id = if (state == .identifier) Token.getTokenId(self.langopts, self.buf[start..self.index]) else .extended_identifier;
13131316 break;
13141317 },
13151318 0x80...0xFF => state = .extended_identifier,
13161319 else => {
1317 id = if (state == .identifier) Token.getTokenId(self.comp, self.buf[start..self.index]) else .extended_identifier;
1320 id = if (state == .identifier) Token.getTokenId(self.langopts, self.buf[start..self.index]) else .extended_identifier;
13181321 break;
13191322 },
13201323 },
......@@ -1358,7 +1361,7 @@ pub fn next(self: *Tokenizer) Token {
13581361 },
13591362 .colon => switch (c) {
13601363 '>' => {
1361 if (self.comp.langopts.hasDigraphs()) {
1364 if (self.langopts.hasDigraphs()) {
13621365 id = .r_bracket;
13631366 self.index += 1;
13641367 } else {
......@@ -1367,7 +1370,7 @@ pub fn next(self: *Tokenizer) Token {
13671370 break;
13681371 },
13691372 ':' => {
1370 if (self.comp.langopts.standard.atLeast(.c23)) {
1373 if (self.langopts.standard.atLeast(.c23)) {
13711374 id = .colon_colon;
13721375 self.index += 1;
13731376 break;
......@@ -1388,7 +1391,7 @@ pub fn next(self: *Tokenizer) Token {
13881391 break;
13891392 },
13901393 '>' => {
1391 if (self.comp.langopts.hasDigraphs()) {
1394 if (self.langopts.hasDigraphs()) {
13921395 id = .r_brace;
13931396 self.index += 1;
13941397 } else {
......@@ -1397,7 +1400,7 @@ pub fn next(self: *Tokenizer) Token {
13971400 break;
13981401 },
13991402 ':' => {
1400 if (self.comp.langopts.hasDigraphs()) {
1403 if (self.langopts.hasDigraphs()) {
14011404 state = .hash_digraph;
14021405 } else {
14031406 id = .percent;
......@@ -1444,7 +1447,7 @@ pub fn next(self: *Tokenizer) Token {
14441447 break;
14451448 },
14461449 ':' => {
1447 if (self.comp.langopts.hasDigraphs()) {
1450 if (self.langopts.hasDigraphs()) {
14481451 id = .l_bracket;
14491452 self.index += 1;
14501453 } else {
......@@ -1453,7 +1456,7 @@ pub fn next(self: *Tokenizer) Token {
14531456 break;
14541457 },
14551458 '%' => {
1456 if (self.comp.langopts.hasDigraphs()) {
1459 if (self.langopts.hasDigraphs()) {
14571460 id = .l_brace;
14581461 self.index += 1;
14591462 } else {
......@@ -1613,7 +1616,7 @@ pub fn next(self: *Tokenizer) Token {
16131616 },
16141617 .line_comment => switch (c) {
16151618 '\n' => {
1616 if (self.comp.langopts.preserve_comments) {
1619 if (self.langopts.preserve_comments) {
16171620 id = .comment;
16181621 break;
16191622 }
......@@ -1629,7 +1632,7 @@ pub fn next(self: *Tokenizer) Token {
16291632 },
16301633 .multi_line_comment_asterisk => switch (c) {
16311634 '/' => {
1632 if (self.comp.langopts.preserve_comments) {
1635 if (self.langopts.preserve_comments) {
16331636 self.index += 1;
16341637 id = .comment;
16351638 break;
......@@ -1673,7 +1676,7 @@ pub fn next(self: *Tokenizer) Token {
16731676 '.',
16741677 => {},
16751678 'e', 'E', 'p', 'P' => state = .pp_num_exponent,
1676 '\'' => if (self.comp.langopts.standard.atLeast(.c23)) {
1679 '\'' => if (self.langopts.standard.atLeast(.c23)) {
16771680 state = .pp_num_digit_separator;
16781681 } else {
16791682 id = .pp_num;
......@@ -1721,7 +1724,7 @@ pub fn next(self: *Tokenizer) Token {
17211724 } else if (self.index == self.buf.len) {
17221725 switch (state) {
17231726 .start, .line_comment => {},
1724 .u, .u8, .U, .L, .identifier => id = Token.getTokenId(self.comp, self.buf[start..self.index]),
1727 .u, .u8, .U, .L, .identifier => id = Token.getTokenId(self.langopts, self.buf[start..self.index]),
17251728 .extended_identifier => id = .extended_identifier,
17261729
17271730 .period2 => {
......@@ -2149,7 +2152,7 @@ fn expectTokensExtra(contents: []const u8, expected_tokens: []const Token.Id, st
21492152 var tokenizer = Tokenizer{
21502153 .buf = source.buf,
21512154 .source = source.id,
2152 .comp = &comp,
2155 .langopts = comp.langopts,
21532156 };
21542157 var i: usize = 0;
21552158 while (i < expected_tokens.len) {
deps/aro/aro/Toolchain.zig+5-8
......@@ -183,18 +183,15 @@ pub fn getLinkerPath(tc: *const Toolchain, buf: []u8) ![]const u8 {
183183 return tc.getProgramPath(default_linker, buf);
184184}
185185
186const TargetSpecificToolName = std.BoundedArray(u8, 64);
187
188186/// If an explicit target is provided, also check the prefixed tool-specific name
189187/// TODO: this isn't exactly right since our target names don't necessarily match up
190188/// with GCC's.
191189/// For example the Zig target `arm-freestanding-eabi` would need the `arm-none-eabi` tools
192fn possibleProgramNames(raw_triple: ?[]const u8, name: []const u8, target_specific: *TargetSpecificToolName) std.BoundedArray([]const u8, 2) {
190fn possibleProgramNames(raw_triple: ?[]const u8, name: []const u8, buf: *[64]u8) std.BoundedArray([]const u8, 2) {
193191 var possible_names: std.BoundedArray([]const u8, 2) = .{};
194192 if (raw_triple) |triple| {
195 const w = target_specific.writer();
196 if (w.print("{s}-{s}", .{ triple, name })) {
197 possible_names.appendAssumeCapacity(target_specific.constSlice());
193 if (std.fmt.bufPrint(buf, "{s}-{s}", .{ triple, name })) |res| {
194 possible_names.appendAssumeCapacity(res);
198195 } else |_| {}
199196 }
200197 possible_names.appendAssumeCapacity(name);
......@@ -227,8 +224,8 @@ fn getProgramPath(tc: *const Toolchain, name: []const u8, buf: []u8) []const u8
227224 var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
228225 var fib = std.heap.FixedBufferAllocator.init(&path_buf);
229226
230 var tool_specific_name: TargetSpecificToolName = .{};
231 const possible_names = possibleProgramNames(tc.driver.raw_target_triple, name, &tool_specific_name);
227 var tool_specific_buf: [64]u8 = undefined;
228 const possible_names = possibleProgramNames(tc.driver.raw_target_triple, name, &tool_specific_buf);
232229
233230 for (possible_names.constSlice()) |tool_name| {
234231 for (tc.program_paths.items) |program_path| {
deps/aro/aro/Tree.zig+7-4
......@@ -1,11 +1,12 @@
11const std = @import("std");
22const Interner = @import("backend").Interner;
3const Type = @import("Type.zig");
4const Tokenizer = @import("Tokenizer.zig");
3const Attribute = @import("Attribute.zig");
54const CodeGen = @import("CodeGen.zig");
65const Compilation = @import("Compilation.zig");
6const number_affixes = @import("Tree/number_affixes.zig");
77const Source = @import("Source.zig");
8const Attribute = @import("Attribute.zig");
8const Tokenizer = @import("Tokenizer.zig");
9const Type = @import("Type.zig");
910const Value = @import("Value.zig");
1011const StringInterner = @import("StringInterner.zig");
1112
......@@ -92,6 +93,8 @@ pub const Token = struct {
9293
9394 pub const List = std.MultiArrayList(Token);
9495 pub const Id = Tokenizer.Token.Id;
96 pub const NumberPrefix = number_affixes.Prefix;
97 pub const NumberSuffix = number_affixes.Suffix;
9598};
9699
97100pub const TokenIndex = u32;
......@@ -669,7 +672,7 @@ pub fn tokSlice(tree: *const Tree, tok_i: TokenIndex) []const u8 {
669672 const loc = tree.tokens.items(.loc)[tok_i];
670673 var tmp_tokenizer = Tokenizer{
671674 .buf = tree.comp.getSource(loc.id).buf,
672 .comp = tree.comp,
675 .langopts = tree.comp.langopts,
673676 .index = loc.byte_offset,
674677 .source = .generated,
675678 };
deps/aro/aro/Tree/number_affixes.zig created+187
......@@ -0,0 +1,187 @@
1const std = @import("std");
2const mem = std.mem;
3
4pub const Prefix = enum(u8) {
5 binary = 2,
6 octal = 8,
7 decimal = 10,
8 hex = 16,
9
10 pub fn digitAllowed(prefix: Prefix, c: u8) bool {
11 return switch (c) {
12 '0', '1' => true,
13 '2'...'7' => prefix != .binary,
14 '8'...'9' => prefix == .decimal or prefix == .hex,
15 'a'...'f', 'A'...'F' => prefix == .hex,
16 else => false,
17 };
18 }
19
20 pub fn fromString(buf: []const u8) Prefix {
21 if (buf.len == 1) return .decimal;
22 // tokenizer enforces that first byte is a decimal digit or period
23 switch (buf[0]) {
24 '.', '1'...'9' => return .decimal,
25 '0' => {},
26 else => unreachable,
27 }
28 switch (buf[1]) {
29 'x', 'X' => return if (buf.len == 2) .decimal else .hex,
30 'b', 'B' => return if (buf.len == 2) .decimal else .binary,
31 else => {
32 if (mem.indexOfAny(u8, buf, "eE.")) |_| {
33 // This is a decimal floating point number that happens to start with zero
34 return .decimal;
35 } else if (Suffix.fromString(buf[1..], .int)) |_| {
36 // This is `0` with a valid suffix
37 return .decimal;
38 } else {
39 return .octal;
40 }
41 },
42 }
43 }
44
45 /// Length of this prefix as a string
46 pub fn stringLen(prefix: Prefix) usize {
47 return switch (prefix) {
48 .binary => 2,
49 .octal => 1,
50 .decimal => 0,
51 .hex => 2,
52 };
53 }
54};
55
56pub const Suffix = enum {
57 // zig fmt: off
58
59 // int and imaginary int
60 None, I,
61
62 // unsigned real integers
63 U, UL, ULL,
64
65 // unsigned imaginary integers
66 IU, IUL, IULL,
67
68 // long or long double, real and imaginary
69 L, IL,
70
71 // long long and imaginary long long
72 LL, ILL,
73
74 // float and imaginary float
75 F, IF,
76
77 // _Float16
78 F16,
79
80 // __float80
81 W,
82
83 // Imaginary __float80
84 IW,
85
86 // _Float128
87 Q, F128,
88
89 // Imaginary _Float128
90 IQ, IF128,
91
92 // Imaginary _Bitint
93 IWB, IUWB,
94
95 // _Bitint
96 WB, UWB,
97
98 // zig fmt: on
99
100 const Tuple = struct { Suffix, []const []const u8 };
101
102 const IntSuffixes = &[_]Tuple{
103 .{ .U, &.{"U"} },
104 .{ .L, &.{"L"} },
105 .{ .WB, &.{"WB"} },
106 .{ .UL, &.{ "U", "L" } },
107 .{ .UWB, &.{ "U", "WB" } },
108 .{ .LL, &.{"LL"} },
109 .{ .ULL, &.{ "U", "LL" } },
110
111 .{ .I, &.{"I"} },
112
113 .{ .IWB, &.{ "I", "WB" } },
114 .{ .IU, &.{ "I", "U" } },
115 .{ .IL, &.{ "I", "L" } },
116 .{ .IUL, &.{ "I", "U", "L" } },
117 .{ .IUWB, &.{ "I", "U", "WB" } },
118 .{ .ILL, &.{ "I", "LL" } },
119 .{ .IULL, &.{ "I", "U", "LL" } },
120 };
121
122 const FloatSuffixes = &[_]Tuple{
123 .{ .F16, &.{"F16"} },
124 .{ .F, &.{"F"} },
125 .{ .L, &.{"L"} },
126 .{ .W, &.{"W"} },
127 .{ .F128, &.{"F128"} },
128 .{ .Q, &.{"Q"} },
129
130 .{ .I, &.{"I"} },
131 .{ .IL, &.{ "I", "L" } },
132 .{ .IF, &.{ "I", "F" } },
133 .{ .IW, &.{ "I", "W" } },
134 .{ .IF128, &.{ "I", "F128" } },
135 .{ .IQ, &.{ "I", "Q" } },
136 };
137
138 pub fn fromString(buf: []const u8, suffix_kind: enum { int, float }) ?Suffix {
139 if (buf.len == 0) return .None;
140
141 const suffixes = switch (suffix_kind) {
142 .float => FloatSuffixes,
143 .int => IntSuffixes,
144 };
145 var scratch: [4]u8 = undefined;
146 top: for (suffixes) |candidate| {
147 const tag = candidate[0];
148 const parts = candidate[1];
149 var len: usize = 0;
150 for (parts) |part| len += part.len;
151 if (len != buf.len) continue;
152
153 for (parts) |part| {
154 const lower = std.ascii.lowerString(&scratch, part);
155 if (mem.indexOf(u8, buf, part) == null and mem.indexOf(u8, buf, lower) == null) continue :top;
156 }
157 return tag;
158 }
159 return null;
160 }
161
162 pub fn isImaginary(suffix: Suffix) bool {
163 return switch (suffix) {
164 .I, .IL, .IF, .IU, .IUL, .ILL, .IULL, .IWB, .IUWB, .IF128, .IQ, .IW => true,
165 .None, .L, .F16, .F, .U, .UL, .LL, .ULL, .WB, .UWB, .F128, .Q, .W => false,
166 };
167 }
168
169 pub fn isSignedInteger(suffix: Suffix) bool {
170 return switch (suffix) {
171 .None, .L, .LL, .I, .IL, .ILL, .WB, .IWB => true,
172 .U, .UL, .ULL, .IU, .IUL, .IULL, .UWB, .IUWB => false,
173 .F, .IF, .F16, .F128, .IF128, .Q, .IQ, .W, .IW => unreachable,
174 };
175 }
176
177 pub fn signedness(suffix: Suffix) std.builtin.Signedness {
178 return if (suffix.isSignedInteger()) .signed else .unsigned;
179 }
180
181 pub fn isBitInt(suffix: Suffix) bool {
182 return switch (suffix) {
183 .WB, .UWB, .IWB, .IUWB => true,
184 else => false,
185 };
186 }
187};
deps/aro/aro/Type.zig+157-212
......@@ -363,7 +363,6 @@ pub const Specifier = enum {
363363 // data.sub_type
364364 pointer,
365365 unspecified_variable_len_array,
366 decayed_unspecified_variable_len_array,
367366 // data.func
368367 /// int foo(int bar, char baz) and int (void)
369368 func,
......@@ -375,15 +374,11 @@ pub const Specifier = enum {
375374
376375 // data.array
377376 array,
378 decayed_array,
379377 static_array,
380 decayed_static_array,
381378 incomplete_array,
382 decayed_incomplete_array,
383379 vector,
384380 // data.expr
385381 variable_len_array,
386 decayed_variable_len_array,
387382
388383 // data.record
389384 @"struct",
......@@ -394,13 +389,9 @@ pub const Specifier = enum {
394389
395390 /// typeof(type-name)
396391 typeof_type,
397 /// decayed array created with typeof(type-name)
398 decayed_typeof_type,
399392
400393 /// typeof(expression)
401394 typeof_expr,
402 /// decayed array created with typeof(expression)
403 decayed_typeof_expr,
404395
405396 /// data.attributed
406397 attributed,
......@@ -428,6 +419,7 @@ data: union {
428419} = .{ .none = {} },
429420specifier: Specifier,
430421qual: Qualifiers = .{},
422decayed: bool = false,
431423
432424pub const int = Type{ .specifier = .int };
433425pub const invalid = Type{ .specifier = .invalid };
......@@ -442,7 +434,7 @@ pub fn is(ty: Type, specifier: Specifier) bool {
442434pub fn withAttributes(self: Type, allocator: std.mem.Allocator, attributes: []const Attribute) !Type {
443435 if (attributes.len == 0) return self;
444436 const attributed_type = try Type.Attributed.create(allocator, self, self.getAttributes(), attributes);
445 return Type{ .specifier = .attributed, .data = .{ .attributed = attributed_type } };
437 return Type{ .specifier = .attributed, .data = .{ .attributed = attributed_type }, .decayed = self.decayed };
446438}
447439
448440pub fn isCallable(ty: Type) ?Type {
......@@ -468,10 +460,10 @@ pub fn isFunc(ty: Type) bool {
468460
469461pub fn isArray(ty: Type) bool {
470462 return switch (ty.specifier) {
471 .array, .static_array, .incomplete_array, .variable_len_array, .unspecified_variable_len_array => true,
472 .typeof_type => ty.data.sub_type.isArray(),
473 .typeof_expr => ty.data.expr.ty.isArray(),
474 .attributed => ty.data.attributed.base.isArray(),
463 .array, .static_array, .incomplete_array, .variable_len_array, .unspecified_variable_len_array => !ty.isDecayed(),
464 .typeof_type => !ty.isDecayed() and ty.data.sub_type.isArray(),
465 .typeof_expr => !ty.isDecayed() and ty.data.expr.ty.isArray(),
466 .attributed => !ty.isDecayed() and ty.data.attributed.base.isArray(),
475467 else => false,
476468 };
477469}
......@@ -502,35 +494,22 @@ pub fn isScalarNonInt(ty: Type) bool {
502494}
503495
504496pub fn isDecayed(ty: Type) bool {
505 const decayed = switch (ty.specifier) {
506 .decayed_array,
507 .decayed_static_array,
508 .decayed_incomplete_array,
509 .decayed_variable_len_array,
510 .decayed_unspecified_variable_len_array,
511 .decayed_typeof_type,
512 .decayed_typeof_expr,
513 => true,
514 else => false,
515 };
516 std.debug.assert(decayed or !std.mem.startsWith(u8, @tagName(ty.specifier), "decayed"));
517 return decayed;
497 return ty.decayed;
518498}
519499
520500pub fn isPtr(ty: Type) bool {
521501 return switch (ty.specifier) {
522 .pointer,
523 .decayed_array,
524 .decayed_static_array,
525 .decayed_incomplete_array,
526 .decayed_variable_len_array,
527 .decayed_unspecified_variable_len_array,
528 .decayed_typeof_type,
529 .decayed_typeof_expr,
530 => true,
531 .typeof_type => ty.data.sub_type.isPtr(),
532 .typeof_expr => ty.data.expr.ty.isPtr(),
533 .attributed => ty.data.attributed.base.isPtr(),
502 .pointer => true,
503
504 .array,
505 .static_array,
506 .incomplete_array,
507 .variable_len_array,
508 .unspecified_variable_len_array,
509 => ty.isDecayed(),
510 .typeof_type => ty.isDecayed() or ty.data.sub_type.isPtr(),
511 .typeof_expr => ty.isDecayed() or ty.data.expr.ty.isPtr(),
512 .attributed => ty.isDecayed() or ty.data.attributed.base.isPtr(),
534513 else => false,
535514 };
536515}
......@@ -608,15 +587,15 @@ pub fn isVoidStar(ty: Type) bool {
608587
609588pub fn isTypeof(ty: Type) bool {
610589 return switch (ty.specifier) {
611 .typeof_type, .typeof_expr, .decayed_typeof_type, .decayed_typeof_expr => true,
590 .typeof_type, .typeof_expr => true,
612591 else => false,
613592 };
614593}
615594
616595pub fn isConst(ty: Type) bool {
617596 return switch (ty.specifier) {
618 .typeof_type, .decayed_typeof_type => ty.qual.@"const" or ty.data.sub_type.isConst(),
619 .typeof_expr, .decayed_typeof_expr => ty.qual.@"const" or ty.data.expr.ty.isConst(),
597 .typeof_type => ty.qual.@"const" or ty.data.sub_type.isConst(),
598 .typeof_expr => ty.qual.@"const" or ty.data.expr.ty.isConst(),
620599 .attributed => ty.data.attributed.base.isConst(),
621600 else => ty.qual.@"const",
622601 };
......@@ -630,7 +609,7 @@ pub fn signedness(ty: Type, comp: *const Compilation) std.builtin.Signedness {
630609 return switch (ty.specifier) {
631610 // zig fmt: off
632611 .char, .complex_char => return comp.getCharSignedness(),
633 .uchar, .ushort, .uint, .ulong, .ulong_long, .bool, .complex_uchar, .complex_ushort,
612 .uchar, .ushort, .uint, .ulong, .ulong_long, .uint128, .bool, .complex_uchar, .complex_ushort,
634613 .complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128 => .unsigned,
635614 // zig fmt: on
636615 .bit_int, .complex_bit_int => ty.data.int.signedness,
......@@ -678,16 +657,16 @@ pub fn isAnonymousRecord(ty: Type, comp: *const Compilation) bool {
678657
679658pub fn elemType(ty: Type) Type {
680659 return switch (ty.specifier) {
681 .pointer, .unspecified_variable_len_array, .decayed_unspecified_variable_len_array => ty.data.sub_type.*,
682 .array, .static_array, .incomplete_array, .decayed_array, .decayed_static_array, .decayed_incomplete_array, .vector => ty.data.array.elem,
683 .variable_len_array, .decayed_variable_len_array => ty.data.expr.ty,
684 .typeof_type, .decayed_typeof_type, .typeof_expr, .decayed_typeof_expr => {
660 .pointer, .unspecified_variable_len_array => ty.data.sub_type.*,
661 .array, .static_array, .incomplete_array, .vector => ty.data.array.elem,
662 .variable_len_array => ty.data.expr.ty,
663 .typeof_type, .typeof_expr => {
685664 const unwrapped = ty.canonicalize(.preserve_quals);
686665 var elem = unwrapped.elemType();
687666 elem.qual = elem.qual.mergeAll(unwrapped.qual);
688667 return elem;
689668 },
690 .attributed => ty.data.attributed.base,
669 .attributed => ty.data.attributed.base.elemType(),
691670 .invalid => Type.invalid,
692671 // zig fmt: off
693672 .complex_float, .complex_double, .complex_long_double, .complex_float80,
......@@ -703,8 +682,8 @@ pub fn elemType(ty: Type) Type {
703682pub fn returnType(ty: Type) Type {
704683 return switch (ty.specifier) {
705684 .func, .var_args_func, .old_style_func => ty.data.func.return_type,
706 .typeof_type, .decayed_typeof_type => ty.data.sub_type.returnType(),
707 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.returnType(),
685 .typeof_type => ty.data.sub_type.returnType(),
686 .typeof_expr => ty.data.expr.ty.returnType(),
708687 .attributed => ty.data.attributed.base.returnType(),
709688 .invalid => Type.invalid,
710689 else => unreachable,
......@@ -714,8 +693,8 @@ pub fn returnType(ty: Type) Type {
714693pub fn params(ty: Type) []Func.Param {
715694 return switch (ty.specifier) {
716695 .func, .var_args_func, .old_style_func => ty.data.func.params,
717 .typeof_type, .decayed_typeof_type => ty.data.sub_type.params(),
718 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.params(),
696 .typeof_type => ty.data.sub_type.params(),
697 .typeof_expr => ty.data.expr.ty.params(),
719698 .attributed => ty.data.attributed.base.params(),
720699 .invalid => &.{},
721700 else => unreachable,
......@@ -724,9 +703,9 @@ pub fn params(ty: Type) []Func.Param {
724703
725704pub fn arrayLen(ty: Type) ?u64 {
726705 return switch (ty.specifier) {
727 .array, .static_array, .decayed_array, .decayed_static_array => ty.data.array.len,
728 .typeof_type, .decayed_typeof_type => ty.data.sub_type.arrayLen(),
729 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.arrayLen(),
706 .array, .static_array => ty.data.array.len,
707 .typeof_type => ty.data.sub_type.arrayLen(),
708 .typeof_expr => ty.data.expr.ty.arrayLen(),
730709 .attributed => ty.data.attributed.base.arrayLen(),
731710 else => null,
732711 };
......@@ -748,8 +727,8 @@ pub fn anyQual(ty: Type) bool {
748727pub fn getAttributes(ty: Type) []const Attribute {
749728 return switch (ty.specifier) {
750729 .attributed => ty.data.attributed.attributes,
751 .typeof_type, .decayed_typeof_type => ty.data.sub_type.getAttributes(),
752 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.getAttributes(),
730 .typeof_type => ty.data.sub_type.getAttributes(),
731 .typeof_expr => ty.data.expr.ty.getAttributes(),
753732 else => &.{},
754733 };
755734}
......@@ -757,8 +736,8 @@ pub fn getAttributes(ty: Type) []const Attribute {
757736pub fn getRecord(ty: Type) ?*const Type.Record {
758737 return switch (ty.specifier) {
759738 .attributed => ty.data.attributed.base.getRecord(),
760 .typeof_type, .decayed_typeof_type => ty.data.sub_type.getRecord(),
761 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.getRecord(),
739 .typeof_type => ty.data.sub_type.getRecord(),
740 .typeof_expr => ty.data.expr.ty.getRecord(),
762741 .@"struct", .@"union" => ty.data.record,
763742 else => null,
764743 };
......@@ -901,6 +880,7 @@ pub fn bitfieldPromotion(ty: Type, comp: *Compilation, width: u32) ?Type {
901880}
902881
903882pub fn hasIncompleteSize(ty: Type) bool {
883 if (ty.isDecayed()) return false;
904884 return switch (ty.specifier) {
905885 .void, .incomplete_array => true,
906886 .@"enum" => ty.data.@"enum".isIncomplete() and !ty.data.@"enum".fixed,
......@@ -917,20 +897,14 @@ pub fn hasUnboundVLA(ty: Type) bool {
917897 var cur = ty;
918898 while (true) {
919899 switch (cur.specifier) {
920 .unspecified_variable_len_array,
921 .decayed_unspecified_variable_len_array,
922 => return true,
900 .unspecified_variable_len_array => return true,
923901 .array,
924902 .static_array,
925903 .incomplete_array,
926904 .variable_len_array,
927 .decayed_array,
928 .decayed_static_array,
929 .decayed_incomplete_array,
930 .decayed_variable_len_array,
931905 => cur = cur.elemType(),
932 .typeof_type, .decayed_typeof_type => cur = cur.data.sub_type.*,
933 .typeof_expr, .decayed_typeof_expr => cur = cur.data.expr.ty,
906 .typeof_type => cur = cur.data.sub_type.*,
907 .typeof_expr => cur = cur.data.expr.ty,
934908 .attributed => cur = cur.data.attributed.base,
935909 else => return false,
936910 }
......@@ -1006,9 +980,11 @@ pub fn sizeCompare(a: Type, b: Type, comp: *Compilation) TypeSizeOrder {
1006980
1007981/// Size of type as reported by sizeof
1008982pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {
983 if (ty.isPtr()) return comp.target.ptrBitWidth() / 8;
984
1009985 return switch (ty.specifier) {
1010986 .auto_type, .c23_auto => unreachable,
1011 .variable_len_array, .unspecified_variable_len_array => return null,
987 .variable_len_array, .unspecified_variable_len_array => null,
1012988 .incomplete_array => return if (comp.langopts.emulate == .msvc) @as(?u64, 0) else null,
1013989 .func, .var_args_func, .old_style_func, .void, .bool => 1,
1014990 .char, .schar, .uchar => 1,
......@@ -1037,14 +1013,7 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {
10371013 .complex_long_double, .complex_float80, .complex_float128, .complex_bit_int,
10381014 => return 2 * ty.makeReal().sizeof(comp).?,
10391015 // zig fmt: on
1040 .pointer,
1041 .decayed_array,
1042 .decayed_static_array,
1043 .decayed_incomplete_array,
1044 .decayed_variable_len_array,
1045 .decayed_unspecified_variable_len_array,
1046 .decayed_typeof_type,
1047 .decayed_typeof_expr,
1016 .pointer => unreachable,
10481017 .static_array,
10491018 .nullptr_t,
10501019 => comp.target.ptrBitWidth() / 8,
......@@ -1073,8 +1042,8 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {
10731042pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 {
10741043 return switch (ty.specifier) {
10751044 .bool => if (comp.langopts.emulate == .msvc) @as(u64, 8) else 1,
1076 .typeof_type, .decayed_typeof_type => ty.data.sub_type.bitSizeof(comp),
1077 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.bitSizeof(comp),
1045 .typeof_type => ty.data.sub_type.bitSizeof(comp),
1046 .typeof_expr => ty.data.expr.ty.bitSizeof(comp),
10781047 .attributed => ty.data.attributed.base.bitSizeof(comp),
10791048 .bit_int => return ty.data.int.bits,
10801049 .long_double => comp.target.c_type_bit_size(.longdouble),
......@@ -1117,7 +1086,10 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
11171086 .unspecified_variable_len_array,
11181087 .array,
11191088 .vector,
1120 => ty.elemType().alignof(comp),
1089 => if (ty.isPtr()) switch (comp.target.cpu.arch) {
1090 .avr => 1,
1091 else => comp.target.ptrBitWidth() / 8,
1092 } else ty.elemType().alignof(comp),
11211093 .func, .var_args_func, .old_style_func => target_util.defaultFunctionAlignment(comp.target),
11221094 .char, .schar, .uchar, .void, .bool => 1,
11231095
......@@ -1153,11 +1125,6 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
11531125
11541126 .float80, .float128 => 16,
11551127 .pointer,
1156 .decayed_array,
1157 .decayed_static_array,
1158 .decayed_incomplete_array,
1159 .decayed_variable_len_array,
1160 .decayed_unspecified_variable_len_array,
11611128 .static_array,
11621129 .nullptr_t,
11631130 => switch (comp.target.cpu.arch) {
......@@ -1166,8 +1133,8 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
11661133 },
11671134 .@"struct", .@"union" => if (ty.data.record.isIncomplete()) 0 else @intCast(ty.data.record.type_layout.field_alignment_bits / 8),
11681135 .@"enum" => if (ty.data.@"enum".isIncomplete() and !ty.data.@"enum".fixed) 0 else ty.data.@"enum".tag_ty.alignof(comp),
1169 .typeof_type, .decayed_typeof_type => ty.data.sub_type.alignof(comp),
1170 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.alignof(comp),
1136 .typeof_type => ty.data.sub_type.alignof(comp),
1137 .typeof_expr => ty.data.expr.ty.alignof(comp),
11711138 .attributed => ty.data.attributed.base.alignof(comp),
11721139 };
11731140}
......@@ -1179,7 +1146,10 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
11791146/// arrays and pointers.
11801147pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals }) Type {
11811148 var cur = ty;
1182 if (cur.specifier == .attributed) cur = cur.data.attributed.base;
1149 if (cur.specifier == .attributed) {
1150 cur = cur.data.attributed.base;
1151 cur.decayed = ty.decayed;
1152 }
11831153 if (!cur.isTypeof()) return cur;
11841154
11851155 var qual = cur.qual;
......@@ -1187,14 +1157,6 @@ pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals })
11871157 switch (cur.specifier) {
11881158 .typeof_type => cur = cur.data.sub_type.*,
11891159 .typeof_expr => cur = cur.data.expr.ty,
1190 .decayed_typeof_type => {
1191 cur = cur.data.sub_type.*;
1192 cur.decayArray();
1193 },
1194 .decayed_typeof_expr => {
1195 cur = cur.data.expr.ty;
1196 cur.decayArray();
1197 },
11981160 else => break,
11991161 }
12001162 qual = qual.mergeAll(cur.qual);
......@@ -1204,6 +1166,7 @@ pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals })
12041166 } else {
12051167 cur.qual = qual;
12061168 }
1169 cur.decayed = ty.decayed;
12071170 return cur;
12081171}
12091172
......@@ -1219,8 +1182,8 @@ pub fn get(ty: *const Type, specifier: Specifier) ?*const Type {
12191182
12201183pub fn requestedAlignment(ty: Type, comp: *const Compilation) ?u29 {
12211184 return switch (ty.specifier) {
1222 .typeof_type, .decayed_typeof_type => ty.data.sub_type.requestedAlignment(comp),
1223 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.requestedAlignment(comp),
1185 .typeof_type => ty.data.sub_type.requestedAlignment(comp),
1186 .typeof_expr => ty.data.expr.ty.requestedAlignment(comp),
12241187 .attributed => annotationAlignment(comp, ty.data.attributed.attributes),
12251188 else => null,
12261189 };
......@@ -1265,14 +1228,11 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi
12651228 if (a.qual.@"volatile" != b.qual.@"volatile") return false;
12661229 }
12671230
1231 if (a.isPtr()) {
1232 return a_param.elemType().eql(b_param.elemType(), comp, check_qualifiers);
1233 }
12681234 switch (a.specifier) {
1269 .pointer,
1270 .decayed_array,
1271 .decayed_static_array,
1272 .decayed_incomplete_array,
1273 .decayed_variable_len_array,
1274 .decayed_unspecified_variable_len_array,
1275 => if (!a_param.elemType().eql(b_param.elemType(), comp, check_qualifiers)) return false,
1235 .pointer => unreachable,
12761236
12771237 .func,
12781238 .var_args_func,
......@@ -1293,8 +1253,9 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi
12931253 }
12941254 if (!a.elemType().eql(b.elemType(), comp, false)) return false;
12951255 },
1296 .variable_len_array => if (!a.elemType().eql(b.elemType(), comp, check_qualifiers)) return false,
1297
1256 .variable_len_array => {
1257 if (!a.elemType().eql(b.elemType(), comp, check_qualifiers)) return false;
1258 },
12981259 .@"struct", .@"union" => if (a.data.record != b.data.record) return false,
12991260 .@"enum" => if (a.data.@"enum" != b.data.@"enum") return false,
13001261 .bit_int, .complex_bit_int => return a.data.int.bits == b.data.int.bits and a.data.int.signedness == b.data.int.signedness,
......@@ -1306,14 +1267,14 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi
13061267
13071268/// Decays an array to a pointer
13081269pub fn decayArray(ty: *Type) void {
1309 // the decayed array type is the current specifier +1
1310 ty.specifier = @enumFromInt(@intFromEnum(ty.specifier) + 1);
1270 std.debug.assert(ty.isArray());
1271 ty.decayed = true;
13111272}
13121273
13131274pub fn originalTypeOfDecayedArray(ty: Type) Type {
13141275 std.debug.assert(ty.isDecayed());
13151276 var copy = ty;
1316 copy.specifier = @enumFromInt(@intFromEnum(ty.specifier) - 1);
1277 copy.decayed = false;
13171278 return copy;
13181279}
13191280
......@@ -1405,25 +1366,23 @@ pub fn combine(inner: *Type, outer: Type) Parser.Error!void {
14051366 switch (inner.specifier) {
14061367 .pointer => return inner.data.sub_type.combine(outer),
14071368 .unspecified_variable_len_array => {
1369 std.debug.assert(!inner.isDecayed());
14081370 try inner.data.sub_type.combine(outer);
14091371 },
14101372 .variable_len_array => {
1373 std.debug.assert(!inner.isDecayed());
14111374 try inner.data.expr.ty.combine(outer);
14121375 },
14131376 .array, .static_array, .incomplete_array => {
1377 std.debug.assert(!inner.isDecayed());
14141378 try inner.data.array.elem.combine(outer);
14151379 },
14161380 .func, .var_args_func, .old_style_func => {
14171381 try inner.data.func.return_type.combine(outer);
14181382 },
1419 .decayed_array,
1420 .decayed_static_array,
1421 .decayed_incomplete_array,
1422 .decayed_variable_len_array,
1423 .decayed_unspecified_variable_len_array,
1424 .decayed_typeof_type,
1425 .decayed_typeof_expr,
1426 => unreachable, // type should not be able to decay before being combined
1383 .typeof_type,
1384 .typeof_expr,
1385 => std.debug.assert(!inner.isDecayed()),
14271386 .void, .invalid => inner.* = outer,
14281387 else => unreachable,
14291388 }
......@@ -1474,8 +1433,8 @@ pub fn validateCombinedType(ty: Type, p: *Parser, source_tok: TokenIndex) Parser
14741433 try p.errStr(.suggest_pointer_for_invalid_fp16, source_tok, "function return value");
14751434 }
14761435 },
1477 .typeof_type, .decayed_typeof_type => return ty.data.sub_type.validateCombinedType(p, source_tok),
1478 .typeof_expr, .decayed_typeof_expr => return ty.data.expr.ty.validateCombinedType(p, source_tok),
1436 .typeof_type => return ty.data.sub_type.validateCombinedType(p, source_tok),
1437 .typeof_expr => return ty.data.expr.ty.validateCombinedType(p, source_tok),
14791438 .attributed => return ty.data.attributed.base.validateCombinedType(p, source_tok),
14801439 else => {},
14811440 }
......@@ -1610,6 +1569,7 @@ pub const Builder = struct {
16101569 decayed_typeof_expr: *Expr,
16111570
16121571 attributed: *Attributed,
1572 decayed_attributed: *Attributed,
16131573
16141574 pub fn str(spec: Builder.Specifier, langopts: LangOpts) ?[]const u8 {
16151575 return switch (spec) {
......@@ -1835,13 +1795,10 @@ pub const Builder = struct {
18351795 ty.specifier = .pointer;
18361796 ty.data = .{ .sub_type = data };
18371797 },
1838 .unspecified_variable_len_array => |data| {
1798 .unspecified_variable_len_array, .decayed_unspecified_variable_len_array => |data| {
18391799 ty.specifier = .unspecified_variable_len_array;
18401800 ty.data = .{ .sub_type = data };
1841 },
1842 .decayed_unspecified_variable_len_array => |data| {
1843 ty.specifier = .decayed_unspecified_variable_len_array;
1844 ty.data = .{ .sub_type = data };
1801 ty.decayed = b.specifier == .decayed_unspecified_variable_len_array;
18451802 },
18461803 .func => |data| {
18471804 ty.specifier = .func;
......@@ -1855,41 +1812,29 @@ pub const Builder = struct {
18551812 ty.specifier = .old_style_func;
18561813 ty.data = .{ .func = data };
18571814 },
1858 .array => |data| {
1815 .array, .decayed_array => |data| {
18591816 ty.specifier = .array;
18601817 ty.data = .{ .array = data };
1818 ty.decayed = b.specifier == .decayed_array;
18611819 },
1862 .decayed_array => |data| {
1863 ty.specifier = .decayed_array;
1864 ty.data = .{ .array = data };
1865 },
1866 .static_array => |data| {
1820 .static_array, .decayed_static_array => |data| {
18671821 ty.specifier = .static_array;
18681822 ty.data = .{ .array = data };
1823 ty.decayed = b.specifier == .decayed_static_array;
18691824 },
1870 .decayed_static_array => |data| {
1871 ty.specifier = .decayed_static_array;
1872 ty.data = .{ .array = data };
1873 },
1874 .incomplete_array => |data| {
1825 .incomplete_array, .decayed_incomplete_array => |data| {
18751826 ty.specifier = .incomplete_array;
18761827 ty.data = .{ .array = data };
1877 },
1878 .decayed_incomplete_array => |data| {
1879 ty.specifier = .decayed_incomplete_array;
1880 ty.data = .{ .array = data };
1828 ty.decayed = b.specifier == .decayed_incomplete_array;
18811829 },
18821830 .vector => |data| {
18831831 ty.specifier = .vector;
18841832 ty.data = .{ .array = data };
18851833 },
1886 .variable_len_array => |data| {
1834 .variable_len_array, .decayed_variable_len_array => |data| {
18871835 ty.specifier = .variable_len_array;
18881836 ty.data = .{ .expr = data };
1889 },
1890 .decayed_variable_len_array => |data| {
1891 ty.specifier = .decayed_variable_len_array;
1892 ty.data = .{ .expr = data };
1837 ty.decayed = b.specifier == .decayed_variable_len_array;
18931838 },
18941839 .@"struct" => |data| {
18951840 ty.specifier = .@"struct";
......@@ -1903,25 +1848,20 @@ pub const Builder = struct {
19031848 ty.specifier = .@"enum";
19041849 ty.data = .{ .@"enum" = data };
19051850 },
1906 .typeof_type => |data| {
1851 .typeof_type, .decayed_typeof_type => |data| {
19071852 ty.specifier = .typeof_type;
19081853 ty.data = .{ .sub_type = data };
1854 ty.decayed = b.specifier == .decayed_typeof_type;
19091855 },
1910 .decayed_typeof_type => |data| {
1911 ty.specifier = .decayed_typeof_type;
1912 ty.data = .{ .sub_type = data };
1913 },
1914 .typeof_expr => |data| {
1856 .typeof_expr, .decayed_typeof_expr => |data| {
19151857 ty.specifier = .typeof_expr;
19161858 ty.data = .{ .expr = data };
1859 ty.decayed = b.specifier == .decayed_typeof_expr;
19171860 },
1918 .decayed_typeof_expr => |data| {
1919 ty.specifier = .decayed_typeof_expr;
1920 ty.data = .{ .expr = data };
1921 },
1922 .attributed => |data| {
1861 .attributed, .decayed_attributed => |data| {
19231862 ty.specifier = .attributed;
19241863 ty.data = .{ .attributed = data };
1864 ty.decayed = b.specifier == .decayed_attributed;
19251865 },
19261866 }
19271867 if (!ty.isReal() and ty.isInt()) {
......@@ -2359,30 +2299,47 @@ pub const Builder = struct {
23592299 .complex_float128 => .complex_float128,
23602300
23612301 .pointer => .{ .pointer = ty.data.sub_type },
2362 .unspecified_variable_len_array => .{ .unspecified_variable_len_array = ty.data.sub_type },
2363 .decayed_unspecified_variable_len_array => .{ .decayed_unspecified_variable_len_array = ty.data.sub_type },
2302 .unspecified_variable_len_array => if (ty.isDecayed())
2303 .{ .decayed_unspecified_variable_len_array = ty.data.sub_type }
2304 else
2305 .{ .unspecified_variable_len_array = ty.data.sub_type },
23642306 .func => .{ .func = ty.data.func },
23652307 .var_args_func => .{ .var_args_func = ty.data.func },
23662308 .old_style_func => .{ .old_style_func = ty.data.func },
2367 .array => .{ .array = ty.data.array },
2368 .decayed_array => .{ .decayed_array = ty.data.array },
2369 .static_array => .{ .static_array = ty.data.array },
2370 .decayed_static_array => .{ .decayed_static_array = ty.data.array },
2371 .incomplete_array => .{ .incomplete_array = ty.data.array },
2372 .decayed_incomplete_array => .{ .decayed_incomplete_array = ty.data.array },
2309 .array => if (ty.isDecayed())
2310 .{ .decayed_array = ty.data.array }
2311 else
2312 .{ .array = ty.data.array },
2313 .static_array => if (ty.isDecayed())
2314 .{ .decayed_static_array = ty.data.array }
2315 else
2316 .{ .static_array = ty.data.array },
2317 .incomplete_array => if (ty.isDecayed())
2318 .{ .decayed_incomplete_array = ty.data.array }
2319 else
2320 .{ .incomplete_array = ty.data.array },
23732321 .vector => .{ .vector = ty.data.array },
2374 .variable_len_array => .{ .variable_len_array = ty.data.expr },
2375 .decayed_variable_len_array => .{ .decayed_variable_len_array = ty.data.expr },
2322 .variable_len_array => if (ty.isDecayed())
2323 .{ .decayed_variable_len_array = ty.data.expr }
2324 else
2325 .{ .variable_len_array = ty.data.expr },
23762326 .@"struct" => .{ .@"struct" = ty.data.record },
23772327 .@"union" => .{ .@"union" = ty.data.record },
23782328 .@"enum" => .{ .@"enum" = ty.data.@"enum" },
23792329
2380 .typeof_type => .{ .typeof_type = ty.data.sub_type },
2381 .decayed_typeof_type => .{ .decayed_typeof_type = ty.data.sub_type },
2382 .typeof_expr => .{ .typeof_expr = ty.data.expr },
2383 .decayed_typeof_expr => .{ .decayed_typeof_expr = ty.data.expr },
2330 .typeof_type => if (ty.isDecayed())
2331 .{ .decayed_typeof_type = ty.data.sub_type }
2332 else
2333 .{ .typeof_type = ty.data.sub_type },
2334 .typeof_expr => if (ty.isDecayed())
2335 .{ .decayed_typeof_expr = ty.data.expr }
2336 else
2337 .{ .typeof_expr = ty.data.expr },
23842338
2385 .attributed => .{ .attributed = ty.data.attributed },
2339 .attributed => if (ty.isDecayed())
2340 .{ .decayed_attributed = ty.data.attributed }
2341 else
2342 .{ .attributed = ty.data.attributed },
23862343 else => unreachable,
23872344 };
23882345 }
......@@ -2472,24 +2429,17 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts
24722429 try w.writeAll(")");
24732430 return true;
24742431 }
2432 if (ty.isPtr()) {
2433 const elem_ty = ty.elemType();
2434 const simple = try elem_ty.printPrologue(mapper, langopts, w);
2435 if (simple) try w.writeByte(' ');
2436 if (elem_ty.isFunc() or elem_ty.isArray()) try w.writeByte('(');
2437 try w.writeByte('*');
2438 try ty.qual.dump(w);
2439 return false;
2440 }
24752441 switch (ty.specifier) {
2476 .pointer,
2477 .decayed_array,
2478 .decayed_static_array,
2479 .decayed_incomplete_array,
2480 .decayed_variable_len_array,
2481 .decayed_unspecified_variable_len_array,
2482 .decayed_typeof_type,
2483 .decayed_typeof_expr,
2484 => {
2485 const elem_ty = ty.elemType();
2486 const simple = try elem_ty.printPrologue(mapper, langopts, w);
2487 if (simple) try w.writeByte(' ');
2488 if (elem_ty.isFunc() or elem_ty.isArray()) try w.writeByte('(');
2489 try w.writeByte('*');
2490 try ty.qual.dump(w);
2491 return false;
2492 },
2442 .pointer => unreachable,
24932443 .func, .var_args_func, .old_style_func => {
24942444 const ret_ty = ty.data.func.return_type;
24952445 const simple = try ret_ty.printPrologue(mapper, langopts, w);
......@@ -2541,20 +2491,14 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts
25412491
25422492fn printEpilogue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: anytype) @TypeOf(w).Error!void {
25432493 if (ty.qual.atomic) return;
2494 if (ty.isPtr()) {
2495 const elem_ty = ty.elemType();
2496 if (elem_ty.isFunc() or elem_ty.isArray()) try w.writeByte(')');
2497 try elem_ty.printEpilogue(mapper, langopts, w);
2498 return;
2499 }
25442500 switch (ty.specifier) {
2545 .pointer,
2546 .decayed_array,
2547 .decayed_static_array,
2548 .decayed_incomplete_array,
2549 .decayed_variable_len_array,
2550 .decayed_unspecified_variable_len_array,
2551 .decayed_typeof_type,
2552 .decayed_typeof_expr,
2553 => {
2554 const elem_ty = ty.elemType();
2555 if (elem_ty.isFunc() or elem_ty.isArray()) try w.writeByte(')');
2556 try elem_ty.printEpilogue(mapper, langopts, w);
2557 },
2501 .pointer => unreachable, // handled above
25582502 .func, .var_args_func, .old_style_func => {
25592503 try w.writeByte('(');
25602504 for (ty.data.func.params, 0..) |param, i| {
......@@ -2637,10 +2581,10 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
26372581 try w.writeAll(") ");
26382582 try ty.data.func.return_type.dump(mapper, langopts, w);
26392583 },
2640 .array, .static_array, .decayed_array, .decayed_static_array => {
2641 if (ty.specifier == .decayed_array or ty.specifier == .decayed_static_array) try w.writeAll("*d");
2584 .array, .static_array => {
2585 if (ty.isDecayed()) try w.writeAll("*d");
26422586 try w.writeByte('[');
2643 if (ty.specifier == .static_array or ty.specifier == .decayed_static_array) try w.writeAll("static ");
2587 if (ty.specifier == .static_array) try w.writeAll("static ");
26442588 try w.print("{d}]", .{ty.data.array.len});
26452589 try ty.data.array.elem.dump(mapper, langopts, w);
26462590 },
......@@ -2649,8 +2593,8 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
26492593 try ty.data.array.elem.dump(mapper, langopts, w);
26502594 try w.writeAll(")");
26512595 },
2652 .incomplete_array, .decayed_incomplete_array => {
2653 if (ty.specifier == .decayed_incomplete_array) try w.writeAll("*d");
2596 .incomplete_array => {
2597 if (ty.isDecayed()) try w.writeAll("*d");
26542598 try w.writeAll("[]");
26552599 try ty.data.array.elem.dump(mapper, langopts, w);
26562600 },
......@@ -2672,27 +2616,28 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
26722616 try w.print("union {s}", .{mapper.lookup(ty.data.record.name)});
26732617 if (dump_detailed_containers) try dumpRecord(ty.data.record, mapper, langopts, w);
26742618 },
2675 .unspecified_variable_len_array, .decayed_unspecified_variable_len_array => {
2676 if (ty.specifier == .decayed_unspecified_variable_len_array) try w.writeAll("*d");
2619 .unspecified_variable_len_array => {
2620 if (ty.isDecayed()) try w.writeAll("*d");
26772621 try w.writeAll("[*]");
26782622 try ty.data.sub_type.dump(mapper, langopts, w);
26792623 },
2680 .variable_len_array, .decayed_variable_len_array => {
2681 if (ty.specifier == .decayed_variable_len_array) try w.writeAll("*d");
2624 .variable_len_array => {
2625 if (ty.isDecayed()) try w.writeAll("*d");
26822626 try w.writeAll("[<expr>]");
26832627 try ty.data.expr.ty.dump(mapper, langopts, w);
26842628 },
2685 .typeof_type, .decayed_typeof_type => {
2629 .typeof_type => {
26862630 try w.writeAll("typeof(");
26872631 try ty.data.sub_type.dump(mapper, langopts, w);
26882632 try w.writeAll(")");
26892633 },
2690 .typeof_expr, .decayed_typeof_expr => {
2634 .typeof_expr => {
26912635 try w.writeAll("typeof(<expr>: ");
26922636 try ty.data.expr.ty.dump(mapper, langopts, w);
26932637 try w.writeAll(")");
26942638 },
26952639 .attributed => {
2640 if (ty.isDecayed()) try w.writeAll("*d:");
26962641 try w.writeAll("attributed(");
26972642 try ty.data.attributed.base.dump(mapper, langopts, w);
26982643 try w.writeAll(")");
deps/aro/aro/Value.zig+1-1
......@@ -215,7 +215,7 @@ pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
215215
216216 const limbs = try comp.gpa.alloc(
217217 std.math.big.Limb,
218 std.math.big.int.calcTwosCompLimbCount(bits),
218 std.math.big.int.calcTwosCompLimbCount(@max(big.bitCountTwosComp(), bits)),
219219 );
220220 defer comp.gpa.free(limbs);
221221 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
deps/aro/aro/number_affixes.zig deleted-169
......@@ -1,169 +0,0 @@
1const std = @import("std");
2const mem = std.mem;
3
4pub const Prefix = enum(u8) {
5 binary = 2,
6 octal = 8,
7 decimal = 10,
8 hex = 16,
9
10 pub fn digitAllowed(prefix: Prefix, c: u8) bool {
11 return switch (c) {
12 '0', '1' => true,
13 '2'...'7' => prefix != .binary,
14 '8'...'9' => prefix == .decimal or prefix == .hex,
15 'a'...'f', 'A'...'F' => prefix == .hex,
16 else => false,
17 };
18 }
19
20 pub fn fromString(buf: []const u8) Prefix {
21 if (buf.len == 1) return .decimal;
22 // tokenizer enforces that first byte is a decimal digit or period
23 switch (buf[0]) {
24 '.', '1'...'9' => return .decimal,
25 '0' => {},
26 else => unreachable,
27 }
28 switch (buf[1]) {
29 'x', 'X' => return if (buf.len == 2) .decimal else .hex,
30 'b', 'B' => return if (buf.len == 2) .decimal else .binary,
31 else => {
32 if (mem.indexOfAny(u8, buf, "eE.")) |_| {
33 // This is a decimal floating point number that happens to start with zero
34 return .decimal;
35 } else if (Suffix.fromString(buf[1..], .int)) |_| {
36 // This is `0` with a valid suffix
37 return .decimal;
38 } else {
39 return .octal;
40 }
41 },
42 }
43 }
44
45 /// Length of this prefix as a string
46 pub fn stringLen(prefix: Prefix) usize {
47 return switch (prefix) {
48 .binary => 2,
49 .octal => 1,
50 .decimal => 0,
51 .hex => 2,
52 };
53 }
54};
55
56pub const Suffix = enum {
57 // zig fmt: off
58
59 // int and imaginary int
60 None, I,
61
62 // unsigned real integers
63 U, UL, ULL,
64
65 // unsigned imaginary integers
66 IU, IUL, IULL,
67
68 // long or long double, real and imaginary
69 L, IL,
70
71 // long long and imaginary long long
72 LL, ILL,
73
74 // float and imaginary float
75 F, IF,
76
77 // _Float16
78 F16,
79
80 // Imaginary _Bitint
81 IWB, IUWB,
82
83 // _Bitint
84 WB, UWB,
85
86 // zig fmt: on
87
88 const Tuple = struct { Suffix, []const []const u8 };
89
90 const IntSuffixes = &[_]Tuple{
91 .{ .U, &.{"U"} },
92 .{ .L, &.{"L"} },
93 .{ .WB, &.{"WB"} },
94 .{ .UL, &.{ "U", "L" } },
95 .{ .UWB, &.{ "U", "WB" } },
96 .{ .LL, &.{"LL"} },
97 .{ .ULL, &.{ "U", "LL" } },
98
99 .{ .I, &.{"I"} },
100
101 .{ .IWB, &.{ "I", "WB" } },
102 .{ .IU, &.{ "I", "U" } },
103 .{ .IL, &.{ "I", "L" } },
104 .{ .IUL, &.{ "I", "U", "L" } },
105 .{ .IUWB, &.{ "I", "U", "WB" } },
106 .{ .ILL, &.{ "I", "LL" } },
107 .{ .IULL, &.{ "I", "U", "LL" } },
108 };
109
110 const FloatSuffixes = &[_]Tuple{
111 .{ .F16, &.{"F16"} },
112 .{ .F, &.{"F"} },
113 .{ .L, &.{"L"} },
114
115 .{ .I, &.{"I"} },
116 .{ .IL, &.{ "I", "L" } },
117 .{ .IF, &.{ "I", "F" } },
118 };
119
120 pub fn fromString(buf: []const u8, suffix_kind: enum { int, float }) ?Suffix {
121 if (buf.len == 0) return .None;
122
123 const suffixes = switch (suffix_kind) {
124 .float => FloatSuffixes,
125 .int => IntSuffixes,
126 };
127 var scratch: [3]u8 = undefined;
128 top: for (suffixes) |candidate| {
129 const tag = candidate[0];
130 const parts = candidate[1];
131 var len: usize = 0;
132 for (parts) |part| len += part.len;
133 if (len != buf.len) continue;
134
135 for (parts) |part| {
136 const lower = std.ascii.lowerString(&scratch, part);
137 if (mem.indexOf(u8, buf, part) == null and mem.indexOf(u8, buf, lower) == null) continue :top;
138 }
139 return tag;
140 }
141 return null;
142 }
143
144 pub fn isImaginary(suffix: Suffix) bool {
145 return switch (suffix) {
146 .I, .IL, .IF, .IU, .IUL, .ILL, .IULL, .IWB, .IUWB => true,
147 .None, .L, .F16, .F, .U, .UL, .LL, .ULL, .WB, .UWB => false,
148 };
149 }
150
151 pub fn isSignedInteger(suffix: Suffix) bool {
152 return switch (suffix) {
153 .None, .L, .LL, .I, .IL, .ILL, .WB, .IWB => true,
154 .U, .UL, .ULL, .IU, .IUL, .IULL, .UWB, .IUWB => false,
155 .F, .IF, .F16 => unreachable,
156 };
157 }
158
159 pub fn signedness(suffix: Suffix) std.builtin.Signedness {
160 return if (suffix.isSignedInteger()) .signed else .unsigned;
161 }
162
163 pub fn isBitInt(suffix: Suffix) bool {
164 return switch (suffix) {
165 .WB, .UWB, .IWB, .IUWB => true,
166 else => false,
167 };
168 }
169};
deps/aro/aro/target.zig-1
......@@ -1,7 +1,6 @@
11const std = @import("std");
22const LangOpts = @import("LangOpts.zig");
33const Type = @import("Type.zig");
4const llvm = @import("root").codegen.llvm;
54const TargetSet = @import("Builtins/Properties.zig").TargetSet;
65
76/// intmax_t for this target
lib/std/c.zig-8
......@@ -5,14 +5,6 @@ const page_size = std.mem.page_size;
55const iovec = std.os.iovec;
66const iovec_const = std.os.iovec_const;
77
8test {
9 _ = tokenizer;
10}
11
12pub const tokenizer = @import("c/tokenizer.zig");
13pub const Token = tokenizer.Token;
14pub const Tokenizer = tokenizer.Tokenizer;
15
168/// The return type is `type` to force comptime function call execution.
179/// TODO: https://github.com/ziglang/zig/issues/425
1810/// If not linking libc, returns struct{pub const ok = false;}
lib/std/c/tokenizer.zig deleted-1585
......@@ -1,1585 +0,0 @@
1const std = @import("std");
2
3pub const Token = struct {
4 id: Id,
5 start: usize,
6 end: usize,
7
8 pub const Id = union(enum) {
9 Invalid,
10 Eof,
11 Nl,
12 Identifier,
13
14 /// special case for #include <...>
15 MacroString,
16 StringLiteral: StrKind,
17 CharLiteral: StrKind,
18 IntegerLiteral: NumSuffix,
19 FloatLiteral: NumSuffix,
20 Bang,
21 BangEqual,
22 Pipe,
23 PipePipe,
24 PipeEqual,
25 Equal,
26 EqualEqual,
27 LParen,
28 RParen,
29 LBrace,
30 RBrace,
31 LBracket,
32 RBracket,
33 Period,
34 Ellipsis,
35 Caret,
36 CaretEqual,
37 Plus,
38 PlusPlus,
39 PlusEqual,
40 Minus,
41 MinusMinus,
42 MinusEqual,
43 Asterisk,
44 AsteriskEqual,
45 Percent,
46 PercentEqual,
47 Arrow,
48 Colon,
49 Semicolon,
50 Slash,
51 SlashEqual,
52 Comma,
53 Ampersand,
54 AmpersandAmpersand,
55 AmpersandEqual,
56 QuestionMark,
57 AngleBracketLeft,
58 AngleBracketLeftEqual,
59 AngleBracketAngleBracketLeft,
60 AngleBracketAngleBracketLeftEqual,
61 AngleBracketRight,
62 AngleBracketRightEqual,
63 AngleBracketAngleBracketRight,
64 AngleBracketAngleBracketRightEqual,
65 Tilde,
66 LineComment,
67 MultiLineComment,
68 Hash,
69 HashHash,
70
71 Keyword_auto,
72 Keyword_break,
73 Keyword_case,
74 Keyword_char,
75 Keyword_const,
76 Keyword_continue,
77 Keyword_default,
78 Keyword_do,
79 Keyword_double,
80 Keyword_else,
81 Keyword_enum,
82 Keyword_extern,
83 Keyword_float,
84 Keyword_for,
85 Keyword_goto,
86 Keyword_if,
87 Keyword_int,
88 Keyword_long,
89 Keyword_register,
90 Keyword_return,
91 Keyword_short,
92 Keyword_signed,
93 Keyword_sizeof,
94 Keyword_static,
95 Keyword_struct,
96 Keyword_switch,
97 Keyword_typedef,
98 Keyword_union,
99 Keyword_unsigned,
100 Keyword_void,
101 Keyword_volatile,
102 Keyword_while,
103
104 // ISO C99
105 Keyword_bool,
106 Keyword_complex,
107 Keyword_imaginary,
108 Keyword_inline,
109 Keyword_restrict,
110
111 // ISO C11
112 Keyword_alignas,
113 Keyword_alignof,
114 Keyword_atomic,
115 Keyword_generic,
116 Keyword_noreturn,
117 Keyword_static_assert,
118 Keyword_thread_local,
119
120 // Preprocessor directives
121 Keyword_include,
122 Keyword_define,
123 Keyword_ifdef,
124 Keyword_ifndef,
125 Keyword_error,
126 Keyword_pragma,
127
128 pub fn symbol(id: Id) []const u8 {
129 return symbolName(id);
130 }
131
132 pub fn symbolName(id: std.meta.Tag(Id)) []const u8 {
133 return switch (id) {
134 .Invalid => "Invalid",
135 .Eof => "Eof",
136 .Nl => "NewLine",
137 .Identifier => "Identifier",
138 .MacroString => "MacroString",
139 .StringLiteral => "StringLiteral",
140 .CharLiteral => "CharLiteral",
141 .IntegerLiteral => "IntegerLiteral",
142 .FloatLiteral => "FloatLiteral",
143 .LineComment => "LineComment",
144 .MultiLineComment => "MultiLineComment",
145
146 .Bang => "!",
147 .BangEqual => "!=",
148 .Pipe => "|",
149 .PipePipe => "||",
150 .PipeEqual => "|=",
151 .Equal => "=",
152 .EqualEqual => "==",
153 .LParen => "(",
154 .RParen => ")",
155 .LBrace => "{",
156 .RBrace => "}",
157 .LBracket => "[",
158 .RBracket => "]",
159 .Period => ".",
160 .Ellipsis => "...",
161 .Caret => "^",
162 .CaretEqual => "^=",
163 .Plus => "+",
164 .PlusPlus => "++",
165 .PlusEqual => "+=",
166 .Minus => "-",
167 .MinusMinus => "--",
168 .MinusEqual => "-=",
169 .Asterisk => "*",
170 .AsteriskEqual => "*=",
171 .Percent => "%",
172 .PercentEqual => "%=",
173 .Arrow => "->",
174 .Colon => ":",
175 .Semicolon => ";",
176 .Slash => "/",
177 .SlashEqual => "/=",
178 .Comma => ",",
179 .Ampersand => "&",
180 .AmpersandAmpersand => "&&",
181 .AmpersandEqual => "&=",
182 .QuestionMark => "?",
183 .AngleBracketLeft => "<",
184 .AngleBracketLeftEqual => "<=",
185 .AngleBracketAngleBracketLeft => "<<",
186 .AngleBracketAngleBracketLeftEqual => "<<=",
187 .AngleBracketRight => ">",
188 .AngleBracketRightEqual => ">=",
189 .AngleBracketAngleBracketRight => ">>",
190 .AngleBracketAngleBracketRightEqual => ">>=",
191 .Tilde => "~",
192 .Hash => "#",
193 .HashHash => "##",
194 .Keyword_auto => "auto",
195 .Keyword_break => "break",
196 .Keyword_case => "case",
197 .Keyword_char => "char",
198 .Keyword_const => "const",
199 .Keyword_continue => "continue",
200 .Keyword_default => "default",
201 .Keyword_do => "do",
202 .Keyword_double => "double",
203 .Keyword_else => "else",
204 .Keyword_enum => "enum",
205 .Keyword_extern => "extern",
206 .Keyword_float => "float",
207 .Keyword_for => "for",
208 .Keyword_goto => "goto",
209 .Keyword_if => "if",
210 .Keyword_int => "int",
211 .Keyword_long => "long",
212 .Keyword_register => "register",
213 .Keyword_return => "return",
214 .Keyword_short => "short",
215 .Keyword_signed => "signed",
216 .Keyword_sizeof => "sizeof",
217 .Keyword_static => "static",
218 .Keyword_struct => "struct",
219 .Keyword_switch => "switch",
220 .Keyword_typedef => "typedef",
221 .Keyword_union => "union",
222 .Keyword_unsigned => "unsigned",
223 .Keyword_void => "void",
224 .Keyword_volatile => "volatile",
225 .Keyword_while => "while",
226 .Keyword_bool => "_Bool",
227 .Keyword_complex => "_Complex",
228 .Keyword_imaginary => "_Imaginary",
229 .Keyword_inline => "inline",
230 .Keyword_restrict => "restrict",
231 .Keyword_alignas => "_Alignas",
232 .Keyword_alignof => "_Alignof",
233 .Keyword_atomic => "_Atomic",
234 .Keyword_generic => "_Generic",
235 .Keyword_noreturn => "_Noreturn",
236 .Keyword_static_assert => "_Static_assert",
237 .Keyword_thread_local => "_Thread_local",
238 .Keyword_include => "include",
239 .Keyword_define => "define",
240 .Keyword_ifdef => "ifdef",
241 .Keyword_ifndef => "ifndef",
242 .Keyword_error => "error",
243 .Keyword_pragma => "pragma",
244 };
245 }
246 };
247
248 // TODO extensions
249 pub const keywords = std.ComptimeStringMap(Id, .{
250 .{ "auto", .Keyword_auto },
251 .{ "break", .Keyword_break },
252 .{ "case", .Keyword_case },
253 .{ "char", .Keyword_char },
254 .{ "const", .Keyword_const },
255 .{ "continue", .Keyword_continue },
256 .{ "default", .Keyword_default },
257 .{ "do", .Keyword_do },
258 .{ "double", .Keyword_double },
259 .{ "else", .Keyword_else },
260 .{ "enum", .Keyword_enum },
261 .{ "extern", .Keyword_extern },
262 .{ "float", .Keyword_float },
263 .{ "for", .Keyword_for },
264 .{ "goto", .Keyword_goto },
265 .{ "if", .Keyword_if },
266 .{ "int", .Keyword_int },
267 .{ "long", .Keyword_long },
268 .{ "register", .Keyword_register },
269 .{ "return", .Keyword_return },
270 .{ "short", .Keyword_short },
271 .{ "signed", .Keyword_signed },
272 .{ "sizeof", .Keyword_sizeof },
273 .{ "static", .Keyword_static },
274 .{ "struct", .Keyword_struct },
275 .{ "switch", .Keyword_switch },
276 .{ "typedef", .Keyword_typedef },
277 .{ "union", .Keyword_union },
278 .{ "unsigned", .Keyword_unsigned },
279 .{ "void", .Keyword_void },
280 .{ "volatile", .Keyword_volatile },
281 .{ "while", .Keyword_while },
282
283 // ISO C99
284 .{ "_Bool", .Keyword_bool },
285 .{ "_Complex", .Keyword_complex },
286 .{ "_Imaginary", .Keyword_imaginary },
287 .{ "inline", .Keyword_inline },
288 .{ "restrict", .Keyword_restrict },
289
290 // ISO C11
291 .{ "_Alignas", .Keyword_alignas },
292 .{ "_Alignof", .Keyword_alignof },
293 .{ "_Atomic", .Keyword_atomic },
294 .{ "_Generic", .Keyword_generic },
295 .{ "_Noreturn", .Keyword_noreturn },
296 .{ "_Static_assert", .Keyword_static_assert },
297 .{ "_Thread_local", .Keyword_thread_local },
298
299 // Preprocessor directives
300 .{ "include", .Keyword_include },
301 .{ "define", .Keyword_define },
302 .{ "ifdef", .Keyword_ifdef },
303 .{ "ifndef", .Keyword_ifndef },
304 .{ "error", .Keyword_error },
305 .{ "pragma", .Keyword_pragma },
306 });
307
308 // TODO do this in the preprocessor
309 pub fn getKeyword(bytes: []const u8, pp_directive: bool) ?Id {
310 if (keywords.get(bytes)) |id| {
311 switch (id) {
312 .Keyword_include,
313 .Keyword_define,
314 .Keyword_ifdef,
315 .Keyword_ifndef,
316 .Keyword_error,
317 .Keyword_pragma,
318 => if (!pp_directive) return null,
319 else => {},
320 }
321 return id;
322 }
323 return null;
324 }
325
326 pub const NumSuffix = enum {
327 none,
328 f,
329 l,
330 u,
331 lu,
332 ll,
333 llu,
334 };
335
336 pub const StrKind = enum {
337 none,
338 wide,
339 utf_8,
340 utf_16,
341 utf_32,
342 };
343};
344
345pub const Tokenizer = struct {
346 buffer: []const u8,
347 index: usize = 0,
348 prev_tok_id: std.meta.Tag(Token.Id) = .Invalid,
349 pp_directive: bool = false,
350
351 pub fn next(self: *Tokenizer) Token {
352 var result = Token{
353 .id = .Eof,
354 .start = self.index,
355 .end = undefined,
356 };
357 var state: enum {
358 Start,
359 Cr,
360 BackSlash,
361 BackSlashCr,
362 u,
363 u8,
364 U,
365 L,
366 StringLiteral,
367 CharLiteralStart,
368 CharLiteral,
369 EscapeSequence,
370 CrEscape,
371 OctalEscape,
372 HexEscape,
373 UnicodeEscape,
374 Identifier,
375 Equal,
376 Bang,
377 Pipe,
378 Percent,
379 Asterisk,
380 Plus,
381
382 /// special case for #include <...>
383 MacroString,
384 AngleBracketLeft,
385 AngleBracketAngleBracketLeft,
386 AngleBracketRight,
387 AngleBracketAngleBracketRight,
388 Caret,
389 Period,
390 Period2,
391 Minus,
392 Slash,
393 Ampersand,
394 Hash,
395 LineComment,
396 MultiLineComment,
397 MultiLineCommentAsterisk,
398 Zero,
399 IntegerLiteralOct,
400 IntegerLiteralBinary,
401 IntegerLiteralBinaryFirst,
402 IntegerLiteralHex,
403 IntegerLiteralHexFirst,
404 IntegerLiteral,
405 IntegerSuffix,
406 IntegerSuffixU,
407 IntegerSuffixL,
408 IntegerSuffixLL,
409 IntegerSuffixUL,
410 FloatFraction,
411 FloatFractionHex,
412 FloatExponent,
413 FloatExponentDigits,
414 FloatSuffix,
415 } = .Start;
416 var string = false;
417 var counter: u32 = 0;
418 while (self.index < self.buffer.len) : (self.index += 1) {
419 const c = self.buffer[self.index];
420 switch (state) {
421 .Start => switch (c) {
422 '\n' => {
423 self.pp_directive = false;
424 result.id = .Nl;
425 self.index += 1;
426 break;
427 },
428 '\r' => {
429 state = .Cr;
430 },
431 '"' => {
432 result.id = .{ .StringLiteral = .none };
433 state = .StringLiteral;
434 },
435 '\'' => {
436 result.id = .{ .CharLiteral = .none };
437 state = .CharLiteralStart;
438 },
439 'u' => {
440 state = .u;
441 },
442 'U' => {
443 state = .U;
444 },
445 'L' => {
446 state = .L;
447 },
448 'a'...'t', 'v'...'z', 'A'...'K', 'M'...'T', 'V'...'Z', '_', '$' => {
449 state = .Identifier;
450 },
451 '=' => {
452 state = .Equal;
453 },
454 '!' => {
455 state = .Bang;
456 },
457 '|' => {
458 state = .Pipe;
459 },
460 '(' => {
461 result.id = .LParen;
462 self.index += 1;
463 break;
464 },
465 ')' => {
466 result.id = .RParen;
467 self.index += 1;
468 break;
469 },
470 '[' => {
471 result.id = .LBracket;
472 self.index += 1;
473 break;
474 },
475 ']' => {
476 result.id = .RBracket;
477 self.index += 1;
478 break;
479 },
480 ';' => {
481 result.id = .Semicolon;
482 self.index += 1;
483 break;
484 },
485 ',' => {
486 result.id = .Comma;
487 self.index += 1;
488 break;
489 },
490 '?' => {
491 result.id = .QuestionMark;
492 self.index += 1;
493 break;
494 },
495 ':' => {
496 result.id = .Colon;
497 self.index += 1;
498 break;
499 },
500 '%' => {
501 state = .Percent;
502 },
503 '*' => {
504 state = .Asterisk;
505 },
506 '+' => {
507 state = .Plus;
508 },
509 '<' => {
510 if (self.prev_tok_id == .Keyword_include)
511 state = .MacroString
512 else
513 state = .AngleBracketLeft;
514 },
515 '>' => {
516 state = .AngleBracketRight;
517 },
518 '^' => {
519 state = .Caret;
520 },
521 '{' => {
522 result.id = .LBrace;
523 self.index += 1;
524 break;
525 },
526 '}' => {
527 result.id = .RBrace;
528 self.index += 1;
529 break;
530 },
531 '~' => {
532 result.id = .Tilde;
533 self.index += 1;
534 break;
535 },
536 '.' => {
537 state = .Period;
538 },
539 '-' => {
540 state = .Minus;
541 },
542 '/' => {
543 state = .Slash;
544 },
545 '&' => {
546 state = .Ampersand;
547 },
548 '#' => {
549 state = .Hash;
550 },
551 '0' => {
552 state = .Zero;
553 },
554 '1'...'9' => {
555 state = .IntegerLiteral;
556 },
557 '\\' => {
558 state = .BackSlash;
559 },
560 '\t', '\x0B', '\x0C', ' ' => {
561 result.start = self.index + 1;
562 },
563 else => {
564 // TODO handle invalid bytes better
565 result.id = .Invalid;
566 self.index += 1;
567 break;
568 },
569 },
570 .Cr => switch (c) {
571 '\n' => {
572 self.pp_directive = false;
573 result.id = .Nl;
574 self.index += 1;
575 break;
576 },
577 else => {
578 result.id = .Invalid;
579 break;
580 },
581 },
582 .BackSlash => switch (c) {
583 '\n' => {
584 result.start = self.index + 1;
585 state = .Start;
586 },
587 '\r' => {
588 state = .BackSlashCr;
589 },
590 '\t', '\x0B', '\x0C', ' ' => {
591 // TODO warn
592 },
593 else => {
594 result.id = .Invalid;
595 break;
596 },
597 },
598 .BackSlashCr => switch (c) {
599 '\n' => {
600 result.start = self.index + 1;
601 state = .Start;
602 },
603 else => {
604 result.id = .Invalid;
605 break;
606 },
607 },
608 .u => switch (c) {
609 '8' => {
610 state = .u8;
611 },
612 '\'' => {
613 result.id = .{ .CharLiteral = .utf_16 };
614 state = .CharLiteralStart;
615 },
616 '\"' => {
617 result.id = .{ .StringLiteral = .utf_16 };
618 state = .StringLiteral;
619 },
620 else => {
621 self.index -= 1;
622 state = .Identifier;
623 },
624 },
625 .u8 => switch (c) {
626 '\"' => {
627 result.id = .{ .StringLiteral = .utf_8 };
628 state = .StringLiteral;
629 },
630 else => {
631 self.index -= 1;
632 state = .Identifier;
633 },
634 },
635 .U => switch (c) {
636 '\'' => {
637 result.id = .{ .CharLiteral = .utf_32 };
638 state = .CharLiteralStart;
639 },
640 '\"' => {
641 result.id = .{ .StringLiteral = .utf_32 };
642 state = .StringLiteral;
643 },
644 else => {
645 self.index -= 1;
646 state = .Identifier;
647 },
648 },
649 .L => switch (c) {
650 '\'' => {
651 result.id = .{ .CharLiteral = .wide };
652 state = .CharLiteralStart;
653 },
654 '\"' => {
655 result.id = .{ .StringLiteral = .wide };
656 state = .StringLiteral;
657 },
658 else => {
659 self.index -= 1;
660 state = .Identifier;
661 },
662 },
663 .StringLiteral => switch (c) {
664 '\\' => {
665 string = true;
666 state = .EscapeSequence;
667 },
668 '"' => {
669 self.index += 1;
670 break;
671 },
672 '\n', '\r' => {
673 result.id = .Invalid;
674 break;
675 },
676 else => {},
677 },
678 .CharLiteralStart => switch (c) {
679 '\\' => {
680 string = false;
681 state = .EscapeSequence;
682 },
683 '\'', '\n' => {
684 result.id = .Invalid;
685 break;
686 },
687 else => {
688 state = .CharLiteral;
689 },
690 },
691 .CharLiteral => switch (c) {
692 '\\' => {
693 string = false;
694 state = .EscapeSequence;
695 },
696 '\'' => {
697 self.index += 1;
698 break;
699 },
700 '\n' => {
701 result.id = .Invalid;
702 break;
703 },
704 else => {},
705 },
706 .EscapeSequence => switch (c) {
707 '\'', '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v', '\n' => {
708 state = if (string) .StringLiteral else .CharLiteral;
709 },
710 '\r' => {
711 state = .CrEscape;
712 },
713 '0'...'7' => {
714 counter = 1;
715 state = .OctalEscape;
716 },
717 'x' => {
718 state = .HexEscape;
719 },
720 'u' => {
721 counter = 4;
722 state = .OctalEscape;
723 },
724 'U' => {
725 counter = 8;
726 state = .OctalEscape;
727 },
728 else => {
729 result.id = .Invalid;
730 break;
731 },
732 },
733 .CrEscape => switch (c) {
734 '\n' => {
735 state = if (string) .StringLiteral else .CharLiteral;
736 },
737 else => {
738 result.id = .Invalid;
739 break;
740 },
741 },
742 .OctalEscape => switch (c) {
743 '0'...'7' => {
744 counter += 1;
745 if (counter == 3) {
746 state = if (string) .StringLiteral else .CharLiteral;
747 }
748 },
749 else => {
750 self.index -= 1;
751 state = if (string) .StringLiteral else .CharLiteral;
752 },
753 },
754 .HexEscape => switch (c) {
755 '0'...'9', 'a'...'f', 'A'...'F' => {},
756 else => {
757 self.index -= 1;
758 state = if (string) .StringLiteral else .CharLiteral;
759 },
760 },
761 .UnicodeEscape => switch (c) {
762 '0'...'9', 'a'...'f', 'A'...'F' => {
763 counter -= 1;
764 if (counter == 0) {
765 state = if (string) .StringLiteral else .CharLiteral;
766 }
767 },
768 else => {
769 if (counter != 0) {
770 result.id = .Invalid;
771 break;
772 }
773 self.index -= 1;
774 state = if (string) .StringLiteral else .CharLiteral;
775 },
776 },
777 .Identifier => switch (c) {
778 'a'...'z', 'A'...'Z', '_', '0'...'9', '$' => {},
779 else => {
780 result.id = Token.getKeyword(self.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier;
781 if (self.prev_tok_id == .Hash)
782 self.pp_directive = true;
783 break;
784 },
785 },
786 .Equal => switch (c) {
787 '=' => {
788 result.id = .EqualEqual;
789 self.index += 1;
790 break;
791 },
792 else => {
793 result.id = .Equal;
794 break;
795 },
796 },
797 .Bang => switch (c) {
798 '=' => {
799 result.id = .BangEqual;
800 self.index += 1;
801 break;
802 },
803 else => {
804 result.id = .Bang;
805 break;
806 },
807 },
808 .Pipe => switch (c) {
809 '=' => {
810 result.id = .PipeEqual;
811 self.index += 1;
812 break;
813 },
814 '|' => {
815 result.id = .PipePipe;
816 self.index += 1;
817 break;
818 },
819 else => {
820 result.id = .Pipe;
821 break;
822 },
823 },
824 .Percent => switch (c) {
825 '=' => {
826 result.id = .PercentEqual;
827 self.index += 1;
828 break;
829 },
830 else => {
831 result.id = .Percent;
832 break;
833 },
834 },
835 .Asterisk => switch (c) {
836 '=' => {
837 result.id = .AsteriskEqual;
838 self.index += 1;
839 break;
840 },
841 else => {
842 result.id = .Asterisk;
843 break;
844 },
845 },
846 .Plus => switch (c) {
847 '=' => {
848 result.id = .PlusEqual;
849 self.index += 1;
850 break;
851 },
852 '+' => {
853 result.id = .PlusPlus;
854 self.index += 1;
855 break;
856 },
857 else => {
858 result.id = .Plus;
859 break;
860 },
861 },
862 .MacroString => switch (c) {
863 '>' => {
864 result.id = .MacroString;
865 self.index += 1;
866 break;
867 },
868 else => {},
869 },
870 .AngleBracketLeft => switch (c) {
871 '<' => {
872 state = .AngleBracketAngleBracketLeft;
873 },
874 '=' => {
875 result.id = .AngleBracketLeftEqual;
876 self.index += 1;
877 break;
878 },
879 else => {
880 result.id = .AngleBracketLeft;
881 break;
882 },
883 },
884 .AngleBracketAngleBracketLeft => switch (c) {
885 '=' => {
886 result.id = .AngleBracketAngleBracketLeftEqual;
887 self.index += 1;
888 break;
889 },
890 else => {
891 result.id = .AngleBracketAngleBracketLeft;
892 break;
893 },
894 },
895 .AngleBracketRight => switch (c) {
896 '>' => {
897 state = .AngleBracketAngleBracketRight;
898 },
899 '=' => {
900 result.id = .AngleBracketRightEqual;
901 self.index += 1;
902 break;
903 },
904 else => {
905 result.id = .AngleBracketRight;
906 break;
907 },
908 },
909 .AngleBracketAngleBracketRight => switch (c) {
910 '=' => {
911 result.id = .AngleBracketAngleBracketRightEqual;
912 self.index += 1;
913 break;
914 },
915 else => {
916 result.id = .AngleBracketAngleBracketRight;
917 break;
918 },
919 },
920 .Caret => switch (c) {
921 '=' => {
922 result.id = .CaretEqual;
923 self.index += 1;
924 break;
925 },
926 else => {
927 result.id = .Caret;
928 break;
929 },
930 },
931 .Period => switch (c) {
932 '.' => {
933 state = .Period2;
934 },
935 '0'...'9' => {
936 state = .FloatFraction;
937 },
938 else => {
939 result.id = .Period;
940 break;
941 },
942 },
943 .Period2 => switch (c) {
944 '.' => {
945 result.id = .Ellipsis;
946 self.index += 1;
947 break;
948 },
949 else => {
950 result.id = .Period;
951 self.index -= 1;
952 break;
953 },
954 },
955 .Minus => switch (c) {
956 '>' => {
957 result.id = .Arrow;
958 self.index += 1;
959 break;
960 },
961 '=' => {
962 result.id = .MinusEqual;
963 self.index += 1;
964 break;
965 },
966 '-' => {
967 result.id = .MinusMinus;
968 self.index += 1;
969 break;
970 },
971 else => {
972 result.id = .Minus;
973 break;
974 },
975 },
976 .Slash => switch (c) {
977 '/' => {
978 state = .LineComment;
979 },
980 '*' => {
981 state = .MultiLineComment;
982 },
983 '=' => {
984 result.id = .SlashEqual;
985 self.index += 1;
986 break;
987 },
988 else => {
989 result.id = .Slash;
990 break;
991 },
992 },
993 .Ampersand => switch (c) {
994 '&' => {
995 result.id = .AmpersandAmpersand;
996 self.index += 1;
997 break;
998 },
999 '=' => {
1000 result.id = .AmpersandEqual;
1001 self.index += 1;
1002 break;
1003 },
1004 else => {
1005 result.id = .Ampersand;
1006 break;
1007 },
1008 },
1009 .Hash => switch (c) {
1010 '#' => {
1011 result.id = .HashHash;
1012 self.index += 1;
1013 break;
1014 },
1015 else => {
1016 result.id = .Hash;
1017 break;
1018 },
1019 },
1020 .LineComment => switch (c) {
1021 '\n' => {
1022 result.id = .LineComment;
1023 break;
1024 },
1025 else => {},
1026 },
1027 .MultiLineComment => switch (c) {
1028 '*' => {
1029 state = .MultiLineCommentAsterisk;
1030 },
1031 else => {},
1032 },
1033 .MultiLineCommentAsterisk => switch (c) {
1034 '/' => {
1035 result.id = .MultiLineComment;
1036 self.index += 1;
1037 break;
1038 },
1039 else => {
1040 state = .MultiLineComment;
1041 },
1042 },
1043 .Zero => switch (c) {
1044 '0'...'9' => {
1045 state = .IntegerLiteralOct;
1046 },
1047 'b', 'B' => {
1048 state = .IntegerLiteralBinaryFirst;
1049 },
1050 'x', 'X' => {
1051 state = .IntegerLiteralHexFirst;
1052 },
1053 '.' => {
1054 state = .FloatFraction;
1055 },
1056 else => {
1057 state = .IntegerSuffix;
1058 self.index -= 1;
1059 },
1060 },
1061 .IntegerLiteralOct => switch (c) {
1062 '0'...'7' => {},
1063 else => {
1064 state = .IntegerSuffix;
1065 self.index -= 1;
1066 },
1067 },
1068 .IntegerLiteralBinaryFirst => switch (c) {
1069 '0'...'7' => state = .IntegerLiteralBinary,
1070 else => {
1071 result.id = .Invalid;
1072 break;
1073 },
1074 },
1075 .IntegerLiteralBinary => switch (c) {
1076 '0', '1' => {},
1077 else => {
1078 state = .IntegerSuffix;
1079 self.index -= 1;
1080 },
1081 },
1082 .IntegerLiteralHexFirst => switch (c) {
1083 '0'...'9', 'a'...'f', 'A'...'F' => state = .IntegerLiteralHex,
1084 '.' => {
1085 state = .FloatFractionHex;
1086 },
1087 'p', 'P' => {
1088 state = .FloatExponent;
1089 },
1090 else => {
1091 result.id = .Invalid;
1092 break;
1093 },
1094 },
1095 .IntegerLiteralHex => switch (c) {
1096 '0'...'9', 'a'...'f', 'A'...'F' => {},
1097 '.' => {
1098 state = .FloatFractionHex;
1099 },
1100 'p', 'P' => {
1101 state = .FloatExponent;
1102 },
1103 else => {
1104 state = .IntegerSuffix;
1105 self.index -= 1;
1106 },
1107 },
1108 .IntegerLiteral => switch (c) {
1109 '0'...'9' => {},
1110 '.' => {
1111 state = .FloatFraction;
1112 },
1113 'e', 'E' => {
1114 state = .FloatExponent;
1115 },
1116 else => {
1117 state = .IntegerSuffix;
1118 self.index -= 1;
1119 },
1120 },
1121 .IntegerSuffix => switch (c) {
1122 'u', 'U' => {
1123 state = .IntegerSuffixU;
1124 },
1125 'l', 'L' => {
1126 state = .IntegerSuffixL;
1127 },
1128 else => {
1129 result.id = .{ .IntegerLiteral = .none };
1130 break;
1131 },
1132 },
1133 .IntegerSuffixU => switch (c) {
1134 'l', 'L' => {
1135 state = .IntegerSuffixUL;
1136 },
1137 else => {
1138 result.id = .{ .IntegerLiteral = .u };
1139 break;
1140 },
1141 },
1142 .IntegerSuffixL => switch (c) {
1143 'l', 'L' => {
1144 state = .IntegerSuffixLL;
1145 },
1146 'u', 'U' => {
1147 result.id = .{ .IntegerLiteral = .lu };
1148 self.index += 1;
1149 break;
1150 },
1151 else => {
1152 result.id = .{ .IntegerLiteral = .l };
1153 break;
1154 },
1155 },
1156 .IntegerSuffixLL => switch (c) {
1157 'u', 'U' => {
1158 result.id = .{ .IntegerLiteral = .llu };
1159 self.index += 1;
1160 break;
1161 },
1162 else => {
1163 result.id = .{ .IntegerLiteral = .ll };
1164 break;
1165 },
1166 },
1167 .IntegerSuffixUL => switch (c) {
1168 'l', 'L' => {
1169 result.id = .{ .IntegerLiteral = .llu };
1170 self.index += 1;
1171 break;
1172 },
1173 else => {
1174 result.id = .{ .IntegerLiteral = .lu };
1175 break;
1176 },
1177 },
1178 .FloatFraction => switch (c) {
1179 '0'...'9' => {},
1180 'e', 'E' => {
1181 state = .FloatExponent;
1182 },
1183 else => {
1184 self.index -= 1;
1185 state = .FloatSuffix;
1186 },
1187 },
1188 .FloatFractionHex => switch (c) {
1189 '0'...'9', 'a'...'f', 'A'...'F' => {},
1190 'p', 'P' => {
1191 state = .FloatExponent;
1192 },
1193 else => {
1194 result.id = .Invalid;
1195 break;
1196 },
1197 },
1198 .FloatExponent => switch (c) {
1199 '+', '-' => {
1200 state = .FloatExponentDigits;
1201 },
1202 else => {
1203 self.index -= 1;
1204 state = .FloatExponentDigits;
1205 },
1206 },
1207 .FloatExponentDigits => switch (c) {
1208 '0'...'9' => {
1209 counter += 1;
1210 },
1211 else => {
1212 if (counter == 0) {
1213 result.id = .Invalid;
1214 break;
1215 }
1216 self.index -= 1;
1217 state = .FloatSuffix;
1218 },
1219 },
1220 .FloatSuffix => switch (c) {
1221 'l', 'L' => {
1222 result.id = .{ .FloatLiteral = .l };
1223 self.index += 1;
1224 break;
1225 },
1226 'f', 'F' => {
1227 result.id = .{ .FloatLiteral = .f };
1228 self.index += 1;
1229 break;
1230 },
1231 else => {
1232 result.id = .{ .FloatLiteral = .none };
1233 break;
1234 },
1235 },
1236 }
1237 } else if (self.index == self.buffer.len) {
1238 switch (state) {
1239 .Start => {},
1240 .u, .u8, .U, .L, .Identifier => {
1241 result.id = Token.getKeyword(self.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier;
1242 },
1243
1244 .Cr,
1245 .BackSlash,
1246 .BackSlashCr,
1247 .Period2,
1248 .StringLiteral,
1249 .CharLiteralStart,
1250 .CharLiteral,
1251 .EscapeSequence,
1252 .CrEscape,
1253 .OctalEscape,
1254 .HexEscape,
1255 .UnicodeEscape,
1256 .MultiLineComment,
1257 .MultiLineCommentAsterisk,
1258 .FloatExponent,
1259 .MacroString,
1260 .IntegerLiteralBinaryFirst,
1261 .IntegerLiteralHexFirst,
1262 => result.id = .Invalid,
1263
1264 .FloatExponentDigits => result.id = if (counter == 0) .Invalid else .{ .FloatLiteral = .none },
1265
1266 .FloatFraction,
1267 .FloatFractionHex,
1268 => result.id = .{ .FloatLiteral = .none },
1269
1270 .IntegerLiteralOct,
1271 .IntegerLiteralBinary,
1272 .IntegerLiteralHex,
1273 .IntegerLiteral,
1274 .IntegerSuffix,
1275 .Zero,
1276 => result.id = .{ .IntegerLiteral = .none },
1277 .IntegerSuffixU => result.id = .{ .IntegerLiteral = .u },
1278 .IntegerSuffixL => result.id = .{ .IntegerLiteral = .l },
1279 .IntegerSuffixLL => result.id = .{ .IntegerLiteral = .ll },
1280 .IntegerSuffixUL => result.id = .{ .IntegerLiteral = .lu },
1281
1282 .FloatSuffix => result.id = .{ .FloatLiteral = .none },
1283 .Equal => result.id = .Equal,
1284 .Bang => result.id = .Bang,
1285 .Minus => result.id = .Minus,
1286 .Slash => result.id = .Slash,
1287 .Ampersand => result.id = .Ampersand,
1288 .Hash => result.id = .Hash,
1289 .Period => result.id = .Period,
1290 .Pipe => result.id = .Pipe,
1291 .AngleBracketAngleBracketRight => result.id = .AngleBracketAngleBracketRight,
1292 .AngleBracketRight => result.id = .AngleBracketRight,
1293 .AngleBracketAngleBracketLeft => result.id = .AngleBracketAngleBracketLeft,
1294 .AngleBracketLeft => result.id = .AngleBracketLeft,
1295 .Plus => result.id = .Plus,
1296 .Percent => result.id = .Percent,
1297 .Caret => result.id = .Caret,
1298 .Asterisk => result.id = .Asterisk,
1299 .LineComment => result.id = .LineComment,
1300 }
1301 }
1302
1303 self.prev_tok_id = result.id;
1304 result.end = self.index;
1305 return result;
1306 }
1307};
1308
1309test "operators" {
1310 try expectTokens(
1311 \\ ! != | || |= = ==
1312 \\ ( ) { } [ ] . .. ...
1313 \\ ^ ^= + ++ += - -- -=
1314 \\ * *= % %= -> : ; / /=
1315 \\ , & && &= ? < <= <<
1316 \\ <<= > >= >> >>= ~ # ##
1317 \\
1318 , &[_]Token.Id{
1319 .Bang,
1320 .BangEqual,
1321 .Pipe,
1322 .PipePipe,
1323 .PipeEqual,
1324 .Equal,
1325 .EqualEqual,
1326 .Nl,
1327 .LParen,
1328 .RParen,
1329 .LBrace,
1330 .RBrace,
1331 .LBracket,
1332 .RBracket,
1333 .Period,
1334 .Period,
1335 .Period,
1336 .Ellipsis,
1337 .Nl,
1338 .Caret,
1339 .CaretEqual,
1340 .Plus,
1341 .PlusPlus,
1342 .PlusEqual,
1343 .Minus,
1344 .MinusMinus,
1345 .MinusEqual,
1346 .Nl,
1347 .Asterisk,
1348 .AsteriskEqual,
1349 .Percent,
1350 .PercentEqual,
1351 .Arrow,
1352 .Colon,
1353 .Semicolon,
1354 .Slash,
1355 .SlashEqual,
1356 .Nl,
1357 .Comma,
1358 .Ampersand,
1359 .AmpersandAmpersand,
1360 .AmpersandEqual,
1361 .QuestionMark,
1362 .AngleBracketLeft,
1363 .AngleBracketLeftEqual,
1364 .AngleBracketAngleBracketLeft,
1365 .Nl,
1366 .AngleBracketAngleBracketLeftEqual,
1367 .AngleBracketRight,
1368 .AngleBracketRightEqual,
1369 .AngleBracketAngleBracketRight,
1370 .AngleBracketAngleBracketRightEqual,
1371 .Tilde,
1372 .Hash,
1373 .HashHash,
1374 .Nl,
1375 });
1376}
1377
1378test "keywords" {
1379 try expectTokens(
1380 \\auto break case char const continue default do
1381 \\double else enum extern float for goto if int
1382 \\long register return short signed sizeof static
1383 \\struct switch typedef union unsigned void volatile
1384 \\while _Bool _Complex _Imaginary inline restrict _Alignas
1385 \\_Alignof _Atomic _Generic _Noreturn _Static_assert _Thread_local
1386 \\
1387 , &[_]Token.Id{
1388 .Keyword_auto,
1389 .Keyword_break,
1390 .Keyword_case,
1391 .Keyword_char,
1392 .Keyword_const,
1393 .Keyword_continue,
1394 .Keyword_default,
1395 .Keyword_do,
1396 .Nl,
1397 .Keyword_double,
1398 .Keyword_else,
1399 .Keyword_enum,
1400 .Keyword_extern,
1401 .Keyword_float,
1402 .Keyword_for,
1403 .Keyword_goto,
1404 .Keyword_if,
1405 .Keyword_int,
1406 .Nl,
1407 .Keyword_long,
1408 .Keyword_register,
1409 .Keyword_return,
1410 .Keyword_short,
1411 .Keyword_signed,
1412 .Keyword_sizeof,
1413 .Keyword_static,
1414 .Nl,
1415 .Keyword_struct,
1416 .Keyword_switch,
1417 .Keyword_typedef,
1418 .Keyword_union,
1419 .Keyword_unsigned,
1420 .Keyword_void,
1421 .Keyword_volatile,
1422 .Nl,
1423 .Keyword_while,
1424 .Keyword_bool,
1425 .Keyword_complex,
1426 .Keyword_imaginary,
1427 .Keyword_inline,
1428 .Keyword_restrict,
1429 .Keyword_alignas,
1430 .Nl,
1431 .Keyword_alignof,
1432 .Keyword_atomic,
1433 .Keyword_generic,
1434 .Keyword_noreturn,
1435 .Keyword_static_assert,
1436 .Keyword_thread_local,
1437 .Nl,
1438 });
1439}
1440
1441test "preprocessor keywords" {
1442 try expectTokens(
1443 \\#include <test>
1444 \\#define #include <1
1445 \\#ifdef
1446 \\#ifndef
1447 \\#error
1448 \\#pragma
1449 \\
1450 , &[_]Token.Id{
1451 .Hash,
1452 .Keyword_include,
1453 .MacroString,
1454 .Nl,
1455 .Hash,
1456 .Keyword_define,
1457 .Hash,
1458 .Identifier,
1459 .AngleBracketLeft,
1460 .{ .IntegerLiteral = .none },
1461 .Nl,
1462 .Hash,
1463 .Keyword_ifdef,
1464 .Nl,
1465 .Hash,
1466 .Keyword_ifndef,
1467 .Nl,
1468 .Hash,
1469 .Keyword_error,
1470 .Nl,
1471 .Hash,
1472 .Keyword_pragma,
1473 .Nl,
1474 });
1475}
1476
1477test "line continuation" {
1478 try expectTokens(
1479 \\#define foo \
1480 \\ bar
1481 \\"foo\
1482 \\ bar"
1483 \\#define "foo"
1484 \\ "bar"
1485 \\#define "foo" \
1486 \\ "bar"
1487 , &[_]Token.Id{
1488 .Hash,
1489 .Keyword_define,
1490 .Identifier,
1491 .Identifier,
1492 .Nl,
1493 .{ .StringLiteral = .none },
1494 .Nl,
1495 .Hash,
1496 .Keyword_define,
1497 .{ .StringLiteral = .none },
1498 .Nl,
1499 .{ .StringLiteral = .none },
1500 .Nl,
1501 .Hash,
1502 .Keyword_define,
1503 .{ .StringLiteral = .none },
1504 .{ .StringLiteral = .none },
1505 });
1506}
1507
1508test "string prefix" {
1509 try expectTokens(
1510 \\"foo"
1511 \\u"foo"
1512 \\u8"foo"
1513 \\U"foo"
1514 \\L"foo"
1515 \\'foo'
1516 \\u'foo'
1517 \\U'foo'
1518 \\L'foo'
1519 \\
1520 , &[_]Token.Id{
1521 .{ .StringLiteral = .none },
1522 .Nl,
1523 .{ .StringLiteral = .utf_16 },
1524 .Nl,
1525 .{ .StringLiteral = .utf_8 },
1526 .Nl,
1527 .{ .StringLiteral = .utf_32 },
1528 .Nl,
1529 .{ .StringLiteral = .wide },
1530 .Nl,
1531 .{ .CharLiteral = .none },
1532 .Nl,
1533 .{ .CharLiteral = .utf_16 },
1534 .Nl,
1535 .{ .CharLiteral = .utf_32 },
1536 .Nl,
1537 .{ .CharLiteral = .wide },
1538 .Nl,
1539 });
1540}
1541
1542test "num suffixes" {
1543 try expectTokens(
1544 \\ 1.0f 1.0L 1.0 .0 1.
1545 \\ 0l 0lu 0ll 0llu 0
1546 \\ 1u 1ul 1ull 1
1547 \\ 0x 0b
1548 \\
1549 , &[_]Token.Id{
1550 .{ .FloatLiteral = .f },
1551 .{ .FloatLiteral = .l },
1552 .{ .FloatLiteral = .none },
1553 .{ .FloatLiteral = .none },
1554 .{ .FloatLiteral = .none },
1555 .Nl,
1556 .{ .IntegerLiteral = .l },
1557 .{ .IntegerLiteral = .lu },
1558 .{ .IntegerLiteral = .ll },
1559 .{ .IntegerLiteral = .llu },
1560 .{ .IntegerLiteral = .none },
1561 .Nl,
1562 .{ .IntegerLiteral = .u },
1563 .{ .IntegerLiteral = .lu },
1564 .{ .IntegerLiteral = .llu },
1565 .{ .IntegerLiteral = .none },
1566 .Nl,
1567 .Invalid,
1568 .Invalid,
1569 .Nl,
1570 });
1571}
1572
1573fn expectTokens(source: []const u8, expected_tokens: []const Token.Id) !void {
1574 var tokenizer = Tokenizer{
1575 .buffer = source,
1576 };
1577 for (expected_tokens) |expected_token_id| {
1578 const token = tokenizer.next();
1579 if (!std.meta.eql(token.id, expected_token_id)) {
1580 std.debug.panic("expected {s}, found {s}\n", .{ @tagName(expected_token_id), @tagName(token.id) });
1581 }
1582 }
1583 const last_token = tokenizer.next();
1584 try std.testing.expect(last_token.id == .Eof);
1585}
lib/std/zig/c_translation.zig+3-3
......@@ -252,7 +252,7 @@ test "sizeof" {
252252 try testing.expect(sizeof(anyopaque) == 1);
253253}
254254
255pub const CIntLiteralBase = enum { decimal, octal, hexadecimal };
255pub const CIntLiteralBase = enum { decimal, octal, hex };
256256
257257/// Deprecated: use `CIntLiteralBase`
258258pub const CIntLiteralRadix = CIntLiteralBase;
......@@ -289,13 +289,13 @@ pub fn promoteIntLiteral(
289289}
290290
291291test "promoteIntLiteral" {
292 const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hexadecimal);
292 const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hex);
293293 try testing.expectEqual(c_uint, @TypeOf(signed_hex));
294294
295295 if (math.maxInt(c_longlong) == math.maxInt(c_int)) return;
296296
297297 const signed_decimal = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .decimal);
298 const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hexadecimal);
298 const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hex);
299299
300300 if (math.maxInt(c_long) > math.maxInt(c_int)) {
301301 try testing.expectEqual(c_long, @TypeOf(signed_decimal));
src/Compilation.zig+1-1
......@@ -4205,7 +4205,7 @@ pub const CImportResult = struct {
42054205/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked
42064206/// a bit when we want to start using it from self-hosted.
42074207pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
4208 if (build_options.only_c) unreachable; // @cImport is not needed for bootstrapping
4208 if (build_options.only_core_functionality) @panic("@cImport is not available in a zig2.c build");
42094209 const tracy_trace = trace(@src());
42104210 defer tracy_trace.end();
42114211
src/main.zig+1-1
......@@ -4293,7 +4293,7 @@ fn updateModule(comp: *Compilation) !void {
42934293}
42944294
42954295fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilation.CImportResult) !void {
4296 if (build_options.only_c) unreachable; // translate-c is not needed for bootstrapping
4296 if (build_options.only_core_functionality) @panic("@translate-c is not available in a zig2.c build");
42974297 assert(comp.c_source_files.len == 1);
42984298 const c_source_file = comp.c_source_files[0];
42994299
src/stubs/aro_builtins.zig+3-1
......@@ -22,7 +22,9 @@ pub fn with(comptime Properties: type) type {
2222 return .{};
2323 }
2424 pub fn tagFromName(name: []const u8) ?Tag {
25 return @enumFromInt(name.len);
25 var res: u16 = 0;
26 for (name) |c| res +%= c;
27 return @enumFromInt(res);
2628 }
2729 pub const NameBuf = struct {
2830 pub fn span(_: *const NameBuf) []const u8 {
src/translate_c.zig+305-261
......@@ -1,13 +1,13 @@
11const std = @import("std");
22const testing = std.testing;
33const assert = std.debug.assert;
4const clang = @import("clang.zig");
5const ctok = std.c.tokenizer;
6const CToken = std.c.Token;
74const mem = std.mem;
85const math = std.math;
96const meta = std.meta;
107const CallingConvention = std.builtin.CallingConvention;
8const clang = @import("clang.zig");
9const aro = @import("aro");
10const CToken = aro.Tokenizer.Token;
1111const ast = @import("translate_c/ast.zig");
1212const Node = ast.Node;
1313const Tag = Node.Tag;
......@@ -190,19 +190,21 @@ pub fn translate(
190190
191191/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)
192192/// Macros of this form will not be translated.
193fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) bool {
194 const source = getMacroText(unit, c, macro);
195 var tokenizer = std.c.Tokenizer{
196 .buffer = source,
193fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) !bool {
194 const source = try getMacroText(unit, c, macro);
195 var tokenizer: aro.Tokenizer = .{
196 .buf = source,
197 .source = .unused,
198 .langopts = .{},
197199 };
198 const name_tok = tokenizer.next();
200 const name_tok = tokenizer.nextNoWS();
199201 const name = source[name_tok.start..name_tok.end];
200202
201 const first_tok = tokenizer.next();
203 const first_tok = tokenizer.nextNoWS();
202204 // We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by
203205 // the tokenizer.
204206 // In other words we would miss `#define inline inline` (`inline` is a valid c89 identifier)
205 if (first_tok.id == .Eof) return false;
207 if (first_tok.id == .eof) return false;
206208 return mem.eql(u8, name, source[first_tok.start..first_tok.end]);
207209}
208210
......@@ -223,7 +225,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
223225 const raw_name = macro.getName_getNameStart();
224226 const name = try c.str(raw_name);
225227
226 if (!isSelfDefinedMacro(ast_unit, c, macro)) {
228 if (!try isSelfDefinedMacro(ast_unit, c, macro)) {
227229 try c.global_names.put(c.gpa, name, {});
228230 }
229231 },
......@@ -5159,16 +5161,16 @@ pub const PatternList = struct {
51595161 /// Assumes that `ms` represents a tokenized function-like macro.
51605162 fn buildArgsHash(allocator: mem.Allocator, ms: MacroSlicer, hash: *ArgsPositionMap) MacroProcessingError!void {
51615163 assert(ms.tokens.len > 2);
5162 assert(ms.tokens[0].id == .Identifier);
5163 assert(ms.tokens[1].id == .LParen);
5164 assert(ms.tokens[0].id == .identifier or ms.tokens[0].id == .extended_identifier);
5165 assert(ms.tokens[1].id == .l_paren);
51645166
51655167 var i: usize = 2;
51665168 while (true) : (i += 1) {
51675169 const token = ms.tokens[i];
51685170 switch (token.id) {
5169 .RParen => break,
5170 .Comma => continue,
5171 .Identifier => {
5171 .r_paren => break,
5172 .comma => continue,
5173 .identifier, .extended_identifier => {
51725174 const identifier = ms.slice(token);
51735175 try hash.put(allocator, identifier, i);
51745176 },
......@@ -5220,18 +5222,18 @@ pub const PatternList = struct {
52205222 if (args_hash.count() != self.args_hash.count()) return false;
52215223
52225224 var i: usize = 2;
5223 while (self.tokens[i].id != .RParen) : (i += 1) {}
5225 while (self.tokens[i].id != .r_paren) : (i += 1) {}
52245226
52255227 const pattern_slicer = MacroSlicer{ .source = self.source, .tokens = self.tokens };
52265228 while (i < self.tokens.len) : (i += 1) {
52275229 const pattern_token = self.tokens[i];
52285230 const macro_token = ms.tokens[i];
5229 if (meta.activeTag(pattern_token.id) != meta.activeTag(macro_token.id)) return false;
5231 if (pattern_token.id != macro_token.id) return false;
52305232
52315233 const pattern_bytes = pattern_slicer.slice(pattern_token);
52325234 const macro_bytes = ms.slice(macro_token);
52335235 switch (pattern_token.id) {
5234 .Identifier => {
5236 .identifier, .extended_identifier => {
52355237 const pattern_arg_index = self.args_hash.get(pattern_bytes);
52365238 const macro_arg_index = args_hash.get(macro_bytes);
52375239
......@@ -5243,7 +5245,7 @@ pub const PatternList = struct {
52435245 return false;
52445246 }
52455247 },
5246 .MacroString, .StringLiteral, .CharLiteral, .IntegerLiteral, .FloatLiteral => {
5248 .string_literal, .char_literal, .pp_num => {
52475249 if (!mem.eql(u8, pattern_bytes, macro_bytes)) return false;
52485250 },
52495251 else => {
......@@ -5359,13 +5361,13 @@ const MacroCtx = struct {
53595361 return self.list[self.i].id;
53605362 }
53615363
5362 fn skip(self: *MacroCtx, c: *Context, expected_id: std.meta.Tag(CToken.Id)) ParseError!void {
5364 fn skip(self: *MacroCtx, c: *Context, expected_id: CToken.Id) ParseError!void {
53635365 const next_id = self.next().?;
5364 if (next_id != expected_id) {
5366 if (next_id != expected_id and !(expected_id == .identifier and next_id == .extended_identifier)) {
53655367 try self.fail(
53665368 c,
53675369 "unable to translate C expr: expected '{s}' instead got '{s}'",
5368 .{ CToken.Id.symbolName(expected_id), next_id.symbol() },
5370 .{ expected_id.symbol(), next_id.symbol() },
53695371 );
53705372 return error.ParseError;
53715373 }
......@@ -5396,12 +5398,12 @@ const MacroCtx = struct {
53965398 while (i < self.list.len) : (i += 1) {
53975399 const token = self.list[i];
53985400 switch (token.id) {
5399 .Period, .Arrow => i += 1, // skip next token since field identifiers can be unknown
5400 .Keyword_struct, .Keyword_union, .Keyword_enum => if (!last_is_type_kw) {
5401 .period, .arrow => i += 1, // skip next token since field identifiers can be unknown
5402 .keyword_struct, .keyword_union, .keyword_enum => if (!last_is_type_kw) {
54015403 last_is_type_kw = true;
54025404 continue;
54035405 },
5404 .Identifier => {
5406 .identifier, .extended_identifier => {
54055407 const identifier = slicer.slice(token);
54065408 const is_param = for (params) |param| {
54075409 if (param.name != null and mem.eql(u8, identifier, param.name.?)) break true;
......@@ -5422,31 +5424,38 @@ const MacroCtx = struct {
54225424};
54235425
54245426fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!void {
5425 var tokenizer = std.c.Tokenizer{
5426 .buffer = source,
5427 var tokenizer: aro.Tokenizer = .{
5428 .buf = source,
5429 .source = .unused,
5430 .langopts = .{},
54275431 };
54285432 while (true) {
54295433 const tok = tokenizer.next();
54305434 switch (tok.id) {
5431 .Nl, .Eof => {
5435 .whitespace => continue,
5436 .nl, .eof => {
54325437 try tok_list.append(tok);
54335438 break;
54345439 },
5435 .LineComment, .MultiLineComment => continue,
54365440 else => {},
54375441 }
54385442 try tok_list.append(tok);
54395443 }
54405444}
54415445
5442fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) []const u8 {
5446fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) ![]const u8 {
54435447 const begin_loc = macro.getSourceRange_getBegin();
54445448 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
54455449
54465450 const begin_c = c.source_manager.getCharacterData(begin_loc);
54475451 const end_c = c.source_manager.getCharacterData(end_loc);
54485452 const slice_len = @intFromPtr(end_c) - @intFromPtr(begin_c);
5449 return begin_c[0..slice_len];
5453
5454 var comp = aro.Compilation.init(c.gpa);
5455 defer comp.deinit();
5456 const result = comp.addSourceFromBuffer("", begin_c[0..slice_len]) catch return error.OutOfMemory;
5457
5458 return c.arena.dupe(u8, result.buf);
54505459}
54515460
54525461fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
......@@ -5471,7 +5480,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54715480 continue;
54725481 }
54735482
5474 const source = getMacroText(unit, c, macro);
5483 const source = try getMacroText(unit, c, macro);
54755484
54765485 try tokenizeMacro(source, &tok_list);
54775486
......@@ -5485,7 +5494,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54855494
54865495 var macro_fn = false;
54875496 switch (macro_ctx.peek().?) {
5488 .Identifier => {
5497 .identifier, .extended_identifier => {
54895498 // if it equals itself, ignore. for example, from stdio.h:
54905499 // #define stdin stdin
54915500 const tok = macro_ctx.list[1];
......@@ -5494,7 +5503,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54945503 continue;
54955504 }
54965505 },
5497 .Nl, .Eof => {
5506 .nl, .eof => {
54985507 // this means it is a macro without a value
54995508 // We define it as an empty string so that it can still be used with ++
55005509 const str_node = try Tag.string_literal.create(c.arena, "\"\"");
......@@ -5503,7 +5512,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
55035512 try c.global_scope.blank_macros.put(name, {});
55045513 continue;
55055514 },
5506 .LParen => {
5515 .l_paren => {
55075516 // if the name is immediately followed by a '(' then it is a function
55085517 macro_fn = macro_ctx.list[0].end == macro_ctx.list[1].start;
55095518 },
......@@ -5534,7 +5543,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
55345543 // Check if the macro only uses other blank macros.
55355544 while (true) {
55365545 switch (m.peek().?) {
5537 .Identifier => {
5546 .identifier, .extended_identifier => {
55385547 const tok = m.list[m.i + 1];
55395548 const slice = m.source[tok.start..tok.end];
55405549 if (c.global_scope.blank_macros.contains(slice)) {
......@@ -5542,7 +5551,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
55425551 continue;
55435552 }
55445553 },
5545 .Eof, .Nl => {
5554 .eof, .nl => {
55465555 try c.global_scope.blank_macros.put(m.name, {});
55475556 const init_node = try Tag.string_literal.create(c.arena, "\"\"");
55485557 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
......@@ -5556,7 +5565,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
55565565
55575566 const init_node = try parseCExpr(c, m, scope);
55585567 const last = m.next().?;
5559 if (last != .Eof and last != .Nl)
5568 if (last != .eof and last != .nl)
55605569 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
55615570
55625571 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
......@@ -5578,14 +5587,16 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
55785587 defer block_scope.deinit();
55795588 const scope = &block_scope.base;
55805589
5581 try m.skip(c, .LParen);
5590 try m.skip(c, .l_paren);
55825591
55835592 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
55845593 defer fn_params.deinit();
55855594
55865595 while (true) {
5587 if (m.peek().? != .Identifier) break;
5588 _ = m.next();
5596 switch (m.peek().?) {
5597 .identifier, .extended_identifier => _ = m.next(),
5598 else => break,
5599 }
55895600
55905601 const mangled_name = try block_scope.makeMangledName(c, m.slice());
55915602 try fn_params.append(.{
......@@ -5594,11 +5605,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
55945605 .type = Tag.@"anytype".init(),
55955606 });
55965607 try block_scope.discardVariable(c, mangled_name);
5597 if (m.peek().? != .Comma) break;
5608 if (m.peek().? != .comma) break;
55985609 _ = m.next();
55995610 }
56005611
5601 try m.skip(c, .RParen);
5612 try m.skip(c, .r_paren);
56025613
56035614 if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) {
56045615 .undefined_identifier => |ident| return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}),
......@@ -5607,7 +5618,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
56075618
56085619 const expr = try parseCExpr(c, m, scope);
56095620 const last = m.next().?;
5610 if (last != .Eof and last != .Nl)
5621 if (last != .eof and last != .nl)
56115622 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
56125623
56135624 const typeof_arg = if (expr.castTag(.block)) |some| blk: {
......@@ -5644,7 +5655,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56445655 defer block_scope.deinit();
56455656
56465657 const node = try parseCCondExpr(c, m, &block_scope.base);
5647 if (m.next().? != .Comma) {
5658 if (m.next().? != .comma) {
56485659 m.i -= 1;
56495660 return node;
56505661 }
......@@ -5656,7 +5667,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56565667 try block_scope.statements.append(ignore);
56575668
56585669 last = try parseCCondExpr(c, m, &block_scope.base);
5659 if (m.next().? != .Comma) {
5670 if (m.next().? != .comma) {
56605671 m.i -= 1;
56615672 break;
56625673 }
......@@ -5670,118 +5681,135 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56705681 return try block_scope.complete(c);
56715682}
56725683
5673fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
5674 var lit_bytes = m.slice();
5684fn parseCNumLit(ctx: *Context, m: *MacroCtx) ParseError!Node {
5685 const lit_bytes = m.slice();
5686 var bytes = try std.ArrayListUnmanaged(u8).initCapacity(ctx.arena, lit_bytes.len + 3);
56755687
5676 switch (m.list[m.i].id) {
5677 .IntegerLiteral => |suffix| {
5678 var base: []const u8 = "decimal";
5679 if (lit_bytes.len >= 2 and lit_bytes[0] == '0') {
5680 switch (lit_bytes[1]) {
5681 '0'...'7' => {
5682 // Octal
5683 lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes[1..]});
5684 base = "octal";
5685 },
5686 'X' => {
5687 // Hexadecimal with capital X, valid in C but not in Zig
5688 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]});
5689 base = "hexadecimal";
5690 },
5691 'x' => {
5692 base = "hexadecimal";
5693 },
5694 else => {},
5695 }
5696 }
5697
5698 const type_node = try Tag.type.create(c.arena, switch (suffix) {
5699 .none => "c_int",
5700 .u => "c_uint",
5701 .l => "c_long",
5702 .lu => "c_ulong",
5703 .ll => "c_longlong",
5704 .llu => "c_ulonglong",
5705 .f => unreachable,
5706 });
5707 lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (suffix) {
5708 .none => @as(u8, 0),
5709 .u, .l => 1,
5710 .lu, .ll => 2,
5711 .llu => 3,
5712 .f => unreachable,
5713 }];
5714
5715 const value = std.fmt.parseInt(i128, lit_bytes, 0) catch math.maxInt(i128);
5716
5717 // make the output less noisy by skipping promoteIntLiteral where
5718 // it's guaranteed to not be required because of C standard type constraints
5719 const guaranteed_to_fit = switch (suffix) {
5720 .none => math.cast(i16, value) != null,
5721 .u => math.cast(u16, value) != null,
5722 .l => math.cast(i32, value) != null,
5723 .lu => math.cast(u32, value) != null,
5724 .ll => math.cast(i64, value) != null,
5725 .llu => math.cast(u64, value) != null,
5726 .f => unreachable,
5727 };
5728
5729 const literal_node = try transCreateNodeNumber(c, lit_bytes, .int);
5688 const prefix = aro.Tree.Token.NumberPrefix.fromString(lit_bytes);
5689 switch (prefix) {
5690 .binary => bytes.appendSliceAssumeCapacity("0b"),
5691 .octal => bytes.appendSliceAssumeCapacity("0o"),
5692 .hex => bytes.appendSliceAssumeCapacity("0x"),
5693 .decimal => {},
5694 }
57305695
5731 if (guaranteed_to_fit) {
5732 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = literal_node });
5733 } else {
5734 return Tag.helpers_promoteIntLiteral.create(c.arena, .{
5735 .type = type_node,
5736 .value = literal_node,
5737 .base = try Tag.enum_literal.create(c.arena, base),
5738 });
5696 const after_prefix = lit_bytes[prefix.stringLen()..];
5697 const after_int = for (after_prefix, 0..) |c, i| switch (c) {
5698 '.' => {
5699 if (i == 0) {
5700 bytes.appendAssumeCapacity('0');
57395701 }
5702 break after_prefix[i..];
57405703 },
5741 .FloatLiteral => |suffix| {
5742 if (suffix != .none) lit_bytes = lit_bytes[0 .. lit_bytes.len - 1];
5743
5744 if (lit_bytes.len >= 2 and std.ascii.eqlIgnoreCase(lit_bytes[0..2], "0x")) {
5745 if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| {
5746 if (dot_index == 2) {
5747 lit_bytes = try std.fmt.allocPrint(c.arena, "0x0{s}", .{lit_bytes[2..]});
5748 } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isHex(lit_bytes[dot_index + 1])) {
5749 // If the literal lacks a digit after the `.`, we need to
5750 // add one since `0x1.p10` would be invalid syntax in Zig.
5751 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}0{s}", .{
5752 lit_bytes[2 .. dot_index + 1],
5753 lit_bytes[dot_index + 1 ..],
5754 });
5755 }
5756 }
5704 'e', 'E' => {
5705 if (prefix != .hex) break after_prefix[i..];
5706 bytes.appendAssumeCapacity(c);
5707 },
5708 'p', 'P' => break after_prefix[i..],
5709 '0'...'9', 'a'...'d', 'A'...'D', 'f', 'F' => {
5710 if (!prefix.digitAllowed(c)) break after_prefix[i..];
5711 bytes.appendAssumeCapacity(c);
5712 },
5713 '\'' => {
5714 bytes.appendAssumeCapacity('_');
5715 },
5716 else => break after_prefix[i..],
5717 } else "";
57575718
5758 if (lit_bytes[1] == 'X') {
5759 // Hexadecimal with capital X, valid in C but not in Zig
5760 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]});
5761 }
5762 } else if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| {
5763 if (dot_index == 0) {
5764 lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes});
5765 } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isDigit(lit_bytes[dot_index + 1])) {
5766 // If the literal lacks a digit after the `.`, we need to
5767 // add one since `1.` or `1.e10` would be invalid syntax in Zig.
5768 lit_bytes = try std.fmt.allocPrint(c.arena, "{s}0{s}", .{
5769 lit_bytes[0 .. dot_index + 1],
5770 lit_bytes[dot_index + 1 ..],
5771 });
5772 }
5719 const after_frac = frac: {
5720 if (after_int.len == 0 or after_int[0] != '.') break :frac after_int;
5721 bytes.appendAssumeCapacity('.');
5722 for (after_int[1..], 1..) |c, i| {
5723 if (c == '\'') {
5724 bytes.appendAssumeCapacity('_');
5725 continue;
57735726 }
5727 if (!prefix.digitAllowed(c)) break :frac after_int[i..];
5728 bytes.appendAssumeCapacity(c);
5729 }
5730 break :frac "";
5731 };
5732
5733 const suffix_str = exponent: {
5734 if (after_frac.len == 0) break :exponent after_frac;
5735 switch (after_frac[0]) {
5736 'e', 'E' => {},
5737 'p', 'P' => if (prefix != .hex) break :exponent after_frac,
5738 else => break :exponent after_frac,
5739 }
5740 bytes.appendAssumeCapacity(after_frac[0]);
5741 for (after_frac[1..], 1..) |c, i| switch (c) {
5742 '+', '-', '0'...'9' => {
5743 bytes.appendAssumeCapacity(c);
5744 },
5745 '\'' => {
5746 bytes.appendAssumeCapacity('_');
5747 },
5748 else => break :exponent after_frac[i..],
5749 };
5750 break :exponent "";
5751 };
5752
5753 const is_float = after_int.len != suffix_str.len;
5754 const suffix = aro.Tree.Token.NumberSuffix.fromString(suffix_str, if (is_float) .float else .int) orelse {
5755 try m.fail(ctx, "invalid number suffix: '{s}'", .{suffix_str});
5756 return error.ParseError;
5757 };
5758 if (suffix.isImaginary()) {
5759 try m.fail(ctx, "TODO: imaginary literals", .{});
5760 return error.ParseError;
5761 }
5762 if (suffix.isBitInt()) {
5763 try m.fail(ctx, "TODO: _BitInt literals", .{});
5764 return error.ParseError;
5765 }
5766
5767 if (is_float) {
5768 const type_node = try Tag.type.create(ctx.arena, switch (suffix) {
5769 .F16 => "f16",
5770 .F => "f32",
5771 .None => "f64",
5772 .L => "c_longdouble",
5773 .W => "f80",
5774 .Q, .F128 => "f128",
5775 else => unreachable,
5776 });
5777 const rhs = try Tag.float_literal.create(ctx.arena, bytes.items);
5778 return Tag.as.create(ctx.arena, .{ .lhs = type_node, .rhs = rhs });
5779 } else {
5780 const type_node = try Tag.type.create(ctx.arena, switch (suffix) {
5781 .None => "c_int",
5782 .U => "c_uint",
5783 .L => "c_long",
5784 .UL => "c_ulong",
5785 .LL => "c_longlong",
5786 .ULL => "c_ulonglong",
5787 else => unreachable,
5788 });
5789 const value = std.fmt.parseInt(i128, bytes.items, 0) catch math.maxInt(i128);
5790
5791 // make the output less noisy by skipping promoteIntLiteral where
5792 // it's guaranteed to not be required because of C standard type constraints
5793 const guaranteed_to_fit = switch (suffix) {
5794 .None => math.cast(i16, value) != null,
5795 .U => math.cast(u16, value) != null,
5796 .L => math.cast(i32, value) != null,
5797 .UL => math.cast(u32, value) != null,
5798 .LL => math.cast(i64, value) != null,
5799 .ULL => math.cast(u64, value) != null,
5800 else => unreachable,
5801 };
57745802
5775 const type_node = try Tag.type.create(c.arena, switch (suffix) {
5776 .f => "f32",
5777 .none => "f64",
5778 .l => "c_longdouble",
5779 else => unreachable,
5803 const literal_node = try Tag.integer_literal.create(ctx.arena, bytes.items);
5804 if (guaranteed_to_fit) {
5805 return Tag.as.create(ctx.arena, .{ .lhs = type_node, .rhs = literal_node });
5806 } else {
5807 return Tag.helpers_promoteIntLiteral.create(ctx.arena, .{
5808 .type = type_node,
5809 .value = literal_node,
5810 .base = try Tag.enum_literal.create(ctx.arena, @tagName(prefix)),
57805811 });
5781 const rhs = try transCreateNodeNumber(c, lit_bytes, .float);
5782 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
5783 },
5784 else => unreachable,
5812 }
57855813 }
57865814}
57875815
......@@ -5800,17 +5828,17 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58005828 } else return source;
58015829 var bytes = try ctx.arena.alloc(u8, source.len * 2);
58025830 var state: enum {
5803 Start,
5804 Escape,
5805 Hex,
5806 Octal,
5807 } = .Start;
5831 start,
5832 escape,
5833 hex,
5834 octal,
5835 } = .start;
58085836 var i: usize = 0;
58095837 var count: u8 = 0;
58105838 var num: u8 = 0;
58115839 for (source) |c| {
58125840 switch (state) {
5813 .Escape => {
5841 .escape => {
58145842 switch (c) {
58155843 'n', 'r', 't', '\\', '\'', '\"' => {
58165844 bytes[i] = c;
......@@ -5818,11 +5846,11 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58185846 '0'...'7' => {
58195847 count += 1;
58205848 num += c - '0';
5821 state = .Octal;
5849 state = .octal;
58225850 bytes[i] = 'x';
58235851 },
58245852 'x' => {
5825 state = .Hex;
5853 state = .hex;
58265854 bytes[i] = 'x';
58275855 },
58285856 'a' => {
......@@ -5867,10 +5895,10 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58675895 },
58685896 }
58695897 i += 1;
5870 if (state == .Escape)
5871 state = .Start;
5898 if (state == .escape)
5899 state = .start;
58725900 },
5873 .Start => {
5901 .start => {
58745902 if (c == '\t') {
58755903 bytes[i] = '\\';
58765904 i += 1;
......@@ -5879,12 +5907,12 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58795907 continue;
58805908 }
58815909 if (c == '\\') {
5882 state = .Escape;
5910 state = .escape;
58835911 }
58845912 bytes[i] = c;
58855913 i += 1;
58865914 },
5887 .Hex => {
5915 .hex => {
58885916 switch (c) {
58895917 '0'...'9' => {
58905918 num = std.math.mul(u8, num, 16) catch {
......@@ -5911,15 +5939,15 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
59115939 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
59125940 num = 0;
59135941 if (c == '\\')
5914 state = .Escape
5942 state = .escape
59155943 else
5916 state = .Start;
5944 state = .start;
59175945 bytes[i] = c;
59185946 i += 1;
59195947 },
59205948 }
59215949 },
5922 .Octal => {
5950 .octal => {
59235951 const accept_digit = switch (c) {
59245952 // The maximum length of a octal literal is 3 digits
59255953 '0'...'7' => count < 3,
......@@ -5938,16 +5966,16 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
59385966 num = 0;
59395967 count = 0;
59405968 if (c == '\\')
5941 state = .Escape
5969 state = .escape
59425970 else
5943 state = .Start;
5971 state = .start;
59445972 bytes[i] = c;
59455973 i += 1;
59465974 }
59475975 },
59485976 }
59495977 }
5950 if (state == .Hex or state == .Octal)
5978 if (state == .hex or state == .octal)
59515979 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
59525980 return bytes[0..i];
59535981}
......@@ -5972,7 +6000,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
59726000 const tok = m.next().?;
59736001 const slice = m.slice();
59746002 switch (tok) {
5975 .CharLiteral => {
6003 .char_literal,
6004 .char_literal_utf_8,
6005 .char_literal_utf_16,
6006 .char_literal_utf_32,
6007 .char_literal_wide,
6008 => {
59766009 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
59776010 return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m));
59786011 } else {
......@@ -5980,13 +6013,18 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
59806013 return Tag.integer_literal.create(c.arena, str);
59816014 }
59826015 },
5983 .StringLiteral => {
6016 .string_literal,
6017 .string_literal_utf_16,
6018 .string_literal_utf_8,
6019 .string_literal_utf_32,
6020 .string_literal_wide,
6021 => {
59846022 return Tag.string_literal.create(c.arena, try escapeUnprintables(c, m));
59856023 },
5986 .IntegerLiteral, .FloatLiteral => {
6024 .pp_num => {
59876025 return parseCNumLit(c, m);
59886026 },
5989 .Identifier => {
6027 .identifier, .extended_identifier => {
59906028 if (c.global_scope.blank_macros.contains(slice)) {
59916029 return parseCPrimaryExprInner(c, m, scope);
59926030 }
......@@ -5996,10 +6034,10 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
59966034 scope.skipVariableDiscard(identifier.castTag(.identifier).?.data);
59976035 return identifier;
59986036 },
5999 .LParen => {
6037 .l_paren => {
60006038 const inner_node = try parseCExpr(c, m, scope);
60016039
6002 try m.skip(c, .RParen);
6040 try m.skip(c, .r_paren);
60036041 return inner_node;
60046042 },
60056043 else => {
......@@ -6022,8 +6060,13 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60226060 // after a primary expression.
60236061 while (true) {
60246062 switch (m.peek().?) {
6025 .StringLiteral => {},
6026 .Identifier => {
6063 .string_literal,
6064 .string_literal_utf_16,
6065 .string_literal_utf_8,
6066 .string_literal_utf_32,
6067 .string_literal_wide,
6068 => {},
6069 .identifier, .extended_identifier => {
60276070 const tok = m.list[m.i + 1];
60286071 const slice = m.source[tok.start..tok.end];
60296072 if (c.global_scope.blank_macros.contains(slice)) {
......@@ -6057,20 +6100,20 @@ fn macroIntToBool(c: *Context, node: Node) !Node {
60576100
60586101fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60596102 const node = try parseCOrExpr(c, m, scope);
6060 if (m.peek().? != .QuestionMark) {
6103 if (m.peek().? != .question_mark) {
60616104 return node;
60626105 }
60636106 _ = m.next();
60646107
60656108 const then_body = try parseCOrExpr(c, m, scope);
6066 try m.skip(c, .Colon);
6109 try m.skip(c, .colon);
60676110 const else_body = try parseCCondExpr(c, m, scope);
60686111 return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });
60696112}
60706113
60716114fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60726115 var node = try parseCAndExpr(c, m, scope);
6073 while (m.next().? == .PipePipe) {
6116 while (m.next().? == .pipe_pipe) {
60746117 const lhs = try macroIntToBool(c, node);
60756118 const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope));
60766119 node = try Tag.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs });
......@@ -6081,7 +6124,7 @@ fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60816124
60826125fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60836126 var node = try parseCBitOrExpr(c, m, scope);
6084 while (m.next().? == .AmpersandAmpersand) {
6127 while (m.next().? == .ampersand_ampersand) {
60856128 const lhs = try macroIntToBool(c, node);
60866129 const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope));
60876130 node = try Tag.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs });
......@@ -6092,7 +6135,7 @@ fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60926135
60936136fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60946137 var node = try parseCBitXorExpr(c, m, scope);
6095 while (m.next().? == .Pipe) {
6138 while (m.next().? == .pipe) {
60966139 const lhs = try macroIntFromBool(c, node);
60976140 const rhs = try macroIntFromBool(c, try parseCBitXorExpr(c, m, scope));
60986141 node = try Tag.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
......@@ -6103,7 +6146,7 @@ fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61036146
61046147fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61056148 var node = try parseCBitAndExpr(c, m, scope);
6106 while (m.next().? == .Caret) {
6149 while (m.next().? == .caret) {
61076150 const lhs = try macroIntFromBool(c, node);
61086151 const rhs = try macroIntFromBool(c, try parseCBitAndExpr(c, m, scope));
61096152 node = try Tag.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
......@@ -6114,7 +6157,7 @@ fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61146157
61156158fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61166159 var node = try parseCEqExpr(c, m, scope);
6117 while (m.next().? == .Ampersand) {
6160 while (m.next().? == .ampersand) {
61186161 const lhs = try macroIntFromBool(c, node);
61196162 const rhs = try macroIntFromBool(c, try parseCEqExpr(c, m, scope));
61206163 node = try Tag.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
......@@ -6127,13 +6170,13 @@ fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61276170 var node = try parseCRelExpr(c, m, scope);
61286171 while (true) {
61296172 switch (m.peek().?) {
6130 .BangEqual => {
6173 .bang_equal => {
61316174 _ = m.next();
61326175 const lhs = try macroIntFromBool(c, node);
61336176 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));
61346177 node = try Tag.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
61356178 },
6136 .EqualEqual => {
6179 .equal_equal => {
61376180 _ = m.next();
61386181 const lhs = try macroIntFromBool(c, node);
61396182 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));
......@@ -6148,25 +6191,25 @@ fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61486191 var node = try parseCShiftExpr(c, m, scope);
61496192 while (true) {
61506193 switch (m.peek().?) {
6151 .AngleBracketRight => {
6194 .angle_bracket_right => {
61526195 _ = m.next();
61536196 const lhs = try macroIntFromBool(c, node);
61546197 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
61556198 node = try Tag.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
61566199 },
6157 .AngleBracketRightEqual => {
6200 .angle_bracket_right_equal => {
61586201 _ = m.next();
61596202 const lhs = try macroIntFromBool(c, node);
61606203 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
61616204 node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
61626205 },
6163 .AngleBracketLeft => {
6206 .angle_bracket_left => {
61646207 _ = m.next();
61656208 const lhs = try macroIntFromBool(c, node);
61666209 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
61676210 node = try Tag.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
61686211 },
6169 .AngleBracketLeftEqual => {
6212 .angle_bracket_left_equal => {
61706213 _ = m.next();
61716214 const lhs = try macroIntFromBool(c, node);
61726215 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
......@@ -6181,13 +6224,13 @@ fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61816224 var node = try parseCAddSubExpr(c, m, scope);
61826225 while (true) {
61836226 switch (m.peek().?) {
6184 .AngleBracketAngleBracketLeft => {
6227 .angle_bracket_angle_bracket_left => {
61856228 _ = m.next();
61866229 const lhs = try macroIntFromBool(c, node);
61876230 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));
61886231 node = try Tag.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
61896232 },
6190 .AngleBracketAngleBracketRight => {
6233 .angle_bracket_angle_bracket_right => {
61916234 _ = m.next();
61926235 const lhs = try macroIntFromBool(c, node);
61936236 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));
......@@ -6202,13 +6245,13 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62026245 var node = try parseCMulExpr(c, m, scope);
62036246 while (true) {
62046247 switch (m.peek().?) {
6205 .Plus => {
6248 .plus => {
62066249 _ = m.next();
62076250 const lhs = try macroIntFromBool(c, node);
62086251 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));
62096252 node = try Tag.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
62106253 },
6211 .Minus => {
6254 .minus => {
62126255 _ = m.next();
62136256 const lhs = try macroIntFromBool(c, node);
62146257 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));
......@@ -6223,17 +6266,17 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62236266 var node = try parseCCastExpr(c, m, scope);
62246267 while (true) {
62256268 switch (m.next().?) {
6226 .Asterisk => {
6269 .asterisk => {
62276270 const lhs = try macroIntFromBool(c, node);
62286271 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
62296272 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
62306273 },
6231 .Slash => {
6274 .slash => {
62326275 const lhs = try macroIntFromBool(c, node);
62336276 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
62346277 node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .div, .lhs = lhs, .rhs = rhs });
62356278 },
6236 .Percent => {
6279 .percent => {
62376280 const lhs = try macroIntFromBool(c, node);
62386281 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
62396282 node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .rem, .lhs = lhs, .rhs = rhs });
......@@ -6248,17 +6291,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62486291
62496292fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62506293 switch (m.next().?) {
6251 .LParen => {
6294 .l_paren => {
62526295 if (try parseCTypeName(c, m, scope, true)) |type_name| {
62536296 while (true) {
62546297 const next_token = m.next().?;
62556298 switch (next_token) {
6256 .RParen => break,
6299 .r_paren => break,
62576300 else => |next_tag| {
62586301 // Skip trailing blank defined before the RParen.
6259 if (next_tag == .Identifier and c.global_scope.blank_macros.contains(m.slice())) {
6302 if ((next_tag == .identifier or next_tag == .extended_identifier) and
6303 c.global_scope.blank_macros.contains(m.slice()))
62606304 continue;
6261 }
6305
62626306 try m.fail(
62636307 c,
62646308 "unable to translate C expr: expected ')' instead got '{s}'",
......@@ -6268,7 +6312,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62686312 },
62696313 }
62706314 }
6271 if (m.peek().? == .LBrace) {
6315 if (m.peek().? == .l_brace) {
62726316 // initializer list
62736317 return parseCPostfixExpr(c, m, scope, type_name);
62746318 }
......@@ -6294,7 +6338,7 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa
62946338fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node {
62956339 const tok = m.next().?;
62966340 switch (tok) {
6297 .Identifier => {
6341 .identifier, .extended_identifier => {
62986342 if (c.global_scope.blank_macros.contains(m.slice())) {
62996343 return try parseCSpecifierQualifierList(c, m, scope, allow_fail);
63006344 }
......@@ -6304,25 +6348,25 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_
63046348 return try Tag.identifier.create(c.arena, mangled_name);
63056349 }
63066350 },
6307 .Keyword_void => return try Tag.type.create(c.arena, "anyopaque"),
6308 .Keyword_bool => return try Tag.type.create(c.arena, "bool"),
6309 .Keyword_char,
6310 .Keyword_int,
6311 .Keyword_short,
6312 .Keyword_long,
6313 .Keyword_float,
6314 .Keyword_double,
6315 .Keyword_signed,
6316 .Keyword_unsigned,
6317 .Keyword_complex,
6351 .keyword_void => return try Tag.type.create(c.arena, "anyopaque"),
6352 .keyword_bool => return try Tag.type.create(c.arena, "bool"),
6353 .keyword_char,
6354 .keyword_int,
6355 .keyword_short,
6356 .keyword_long,
6357 .keyword_float,
6358 .keyword_double,
6359 .keyword_signed,
6360 .keyword_unsigned,
6361 .keyword_complex,
63186362 => {
63196363 m.i -= 1;
63206364 return try parseCNumericType(c, m);
63216365 },
6322 .Keyword_enum, .Keyword_struct, .Keyword_union => {
6366 .keyword_enum, .keyword_struct, .keyword_union => {
63236367 // struct Foo will be declared as struct_Foo by transRecordDecl
63246368 const slice = m.slice();
6325 try m.skip(c, .Identifier);
6369 try m.skip(c, .identifier);
63266370
63276371 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
63286372 return try Tag.identifier.create(c.arena, name);
......@@ -6364,15 +6408,15 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {
63646408 var i: u8 = 0;
63656409 while (i < math.maxInt(u8)) : (i += 1) {
63666410 switch (m.next().?) {
6367 .Keyword_double => kw.double += 1,
6368 .Keyword_long => kw.long += 1,
6369 .Keyword_int => kw.int += 1,
6370 .Keyword_float => kw.float += 1,
6371 .Keyword_short => kw.short += 1,
6372 .Keyword_char => kw.char += 1,
6373 .Keyword_unsigned => kw.unsigned += 1,
6374 .Keyword_signed => kw.signed += 1,
6375 .Keyword_complex => kw.complex += 1,
6411 .keyword_double => kw.double += 1,
6412 .keyword_long => kw.long += 1,
6413 .keyword_int => kw.int += 1,
6414 .keyword_float => kw.float += 1,
6415 .keyword_short => kw.short += 1,
6416 .keyword_char => kw.char += 1,
6417 .keyword_unsigned => kw.unsigned += 1,
6418 .keyword_signed => kw.signed += 1,
6419 .keyword_complex => kw.complex += 1,
63766420 else => {
63776421 m.i -= 1;
63786422 break;
......@@ -6442,11 +6486,11 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {
64426486
64436487fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, node: Node) ParseError!Node {
64446488 switch (m.next().?) {
6445 .Asterisk => {
6489 .asterisk => {
64466490 // last token of `node`
64476491 const prev_id = m.list[m.i - 1].id;
64486492
6449 if (prev_id == .Keyword_void) {
6493 if (prev_id == .keyword_void) {
64506494 const ptr = try Tag.single_pointer.create(c.arena, .{
64516495 .is_const = false,
64526496 .is_volatile = false,
......@@ -6472,28 +6516,28 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
64726516 var node = type_name orelse try parseCPrimaryExpr(c, m, scope);
64736517 while (true) {
64746518 switch (m.next().?) {
6475 .Period => {
6476 try m.skip(c, .Identifier);
6519 .period => {
6520 try m.skip(c, .identifier);
64776521
64786522 node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });
64796523 },
6480 .Arrow => {
6481 try m.skip(c, .Identifier);
6524 .arrow => {
6525 try m.skip(c, .identifier);
64826526
64836527 const deref = try Tag.deref.create(c.arena, node);
64846528 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });
64856529 },
6486 .LBracket => {
6530 .l_bracket => {
64876531 const index_val = try macroIntFromBool(c, try parseCExpr(c, m, scope));
64886532 const index = try Tag.as.create(c.arena, .{
64896533 .lhs = try Tag.type.create(c.arena, "usize"),
64906534 .rhs = try Tag.int_cast.create(c.arena, index_val),
64916535 });
64926536 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });
6493 try m.skip(c, .RBracket);
6537 try m.skip(c, .r_bracket);
64946538 },
6495 .LParen => {
6496 if (m.peek().? == .RParen) {
6539 .l_paren => {
6540 if (m.peek().? == .r_paren) {
64976541 m.i += 1;
64986542 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &[0]Node{} });
64996543 } else {
......@@ -6504,8 +6548,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65046548 try args.append(arg);
65056549 const next_id = m.next().?;
65066550 switch (next_id) {
6507 .Comma => {},
6508 .RParen => break,
6551 .comma => {},
6552 .r_paren => break,
65096553 else => {
65106554 try m.fail(c, "unable to translate C expr: expected ',' or ')' instead got '{s}'", .{next_id.symbol()});
65116555 return error.ParseError;
......@@ -6515,24 +6559,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65156559 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });
65166560 }
65176561 },
6518 .LBrace => {
6562 .l_brace => {
65196563 // Check for designated field initializers
6520 if (m.peek().? == .Period) {
6564 if (m.peek().? == .period) {
65216565 var init_vals = std.ArrayList(ast.Payload.ContainerInitDot.Initializer).init(c.gpa);
65226566 defer init_vals.deinit();
65236567
65246568 while (true) {
6525 try m.skip(c, .Period);
6526 try m.skip(c, .Identifier);
6569 try m.skip(c, .period);
6570 try m.skip(c, .identifier);
65276571 const name = m.slice();
6528 try m.skip(c, .Equal);
6572 try m.skip(c, .equal);
65296573
65306574 const val = try parseCCondExpr(c, m, scope);
65316575 try init_vals.append(.{ .name = name, .value = val });
65326576 const next_id = m.next().?;
65336577 switch (next_id) {
6534 .Comma => {},
6535 .RBrace => break,
6578 .comma => {},
6579 .r_brace => break,
65366580 else => {
65376581 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});
65386582 return error.ParseError;
......@@ -6552,8 +6596,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65526596 try init_vals.append(val);
65536597 const next_id = m.next().?;
65546598 switch (next_id) {
6555 .Comma => {},
6556 .RBrace => break,
6599 .comma => {},
6600 .r_brace => break,
65576601 else => {
65586602 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});
65596603 return error.ParseError;
......@@ -6563,7 +6607,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65636607 const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items));
65646608 node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node });
65656609 },
6566 .PlusPlus, .MinusMinus => {
6610 .plus_plus, .minus_minus => {
65676611 try m.fail(c, "TODO postfix inc/dec expr", .{});
65686612 return error.ParseError;
65696613 },
......@@ -6577,47 +6621,47 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65776621
65786622fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
65796623 switch (m.next().?) {
6580 .Bang => {
6624 .bang => {
65816625 const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));
65826626 return Tag.not.create(c.arena, operand);
65836627 },
6584 .Minus => {
6628 .minus => {
65856629 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
65866630 return Tag.negate.create(c.arena, operand);
65876631 },
6588 .Plus => return try parseCCastExpr(c, m, scope),
6589 .Tilde => {
6632 .plus => return try parseCCastExpr(c, m, scope),
6633 .tilde => {
65906634 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
65916635 return Tag.bit_not.create(c.arena, operand);
65926636 },
6593 .Asterisk => {
6637 .asterisk => {
65946638 const operand = try parseCCastExpr(c, m, scope);
65956639 return Tag.deref.create(c.arena, operand);
65966640 },
6597 .Ampersand => {
6641 .ampersand => {
65986642 const operand = try parseCCastExpr(c, m, scope);
65996643 return Tag.address_of.create(c.arena, operand);
66006644 },
6601 .Keyword_sizeof => {
6602 const operand = if (m.peek().? == .LParen) blk: {
6645 .keyword_sizeof => {
6646 const operand = if (m.peek().? == .l_paren) blk: {
66036647 _ = m.next();
66046648 const inner = (try parseCTypeName(c, m, scope, false)).?;
6605 try m.skip(c, .RParen);
6649 try m.skip(c, .r_paren);
66066650 break :blk inner;
66076651 } else try parseCUnaryExpr(c, m, scope);
66086652
66096653 return Tag.helpers_sizeof.create(c.arena, operand);
66106654 },
6611 .Keyword_alignof => {
6655 .keyword_alignof => {
66126656 // TODO this won't work if using <stdalign.h>'s
66136657 // #define alignof _Alignof
6614 try m.skip(c, .LParen);
6658 try m.skip(c, .l_paren);
66156659 const operand = (try parseCTypeName(c, m, scope, false)).?;
6616 try m.skip(c, .RParen);
6660 try m.skip(c, .r_paren);
66176661
66186662 return Tag.alignof.create(c.arena, operand);
66196663 },
6620 .PlusPlus, .MinusMinus => {
6664 .plus_plus, .minus_minus => {
66216665 try m.fail(c, "TODO unary inc/dec expr", .{});
66226666 return error.ParseError;
66236667 },
test/translate_c.zig+7-7
......@@ -424,7 +424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
424424 \\ });
425425 \\}
426426 ,
427 \\pub const B = A(@as(f32, 0.0));
427 \\pub const B = A(@as(f32, 0));
428428 });
429429
430430 cases.add("complex switch",
......@@ -633,7 +633,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
633633 cases.add("#define hex literal with capital X",
634634 \\#define VAL 0XF00D
635635 , &[_][]const u8{
636 \\pub const VAL = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF00D, .hexadecimal);
636 \\pub const VAL = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF00D, .hex);
637637 });
638638
639639 cases.add("anonymous struct & unions",
......@@ -1243,12 +1243,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12431243 \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l;
12441244 , &([_][]const u8{
12451245 "pub const foo = @as(f32, 3.14);",
1246 "pub const bar = @as(c_longdouble, 16.0e-2);",
1246 "pub const bar = @as(c_longdouble, 16.e-2);",
12471247 "pub const FOO = @as(f64, 0.12345);",
12481248 "pub const BAR = @as(f64, 0.12345);",
12491249 "pub const baz = @as(f64, 1e1);",
12501250 "pub const BAZ = @as(f32, 42e-3);",
1251 "pub const foobar = -@as(c_longdouble, 73.0);",
1251 "pub const foobar = -@as(c_longdouble, 73);",
12521252 "pub export const my_float: f32 = 1.0;",
12531253 "pub export const my_double: f64 = 1.0;",
12541254 "pub export const my_longdouble: c_longdouble = 1.0;",
......@@ -1272,7 +1272,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12721272 "pub const BAR = -@as(f32, 0x8F.BP5);",
12731273 "pub const FOOBAR = @as(f64, 0x0P+0);",
12741274 "pub const BAZ = -@as(f64, 0x0.0a5dp+12);",
1275 "pub const FOOBAZ = @as(c_longdouble, 0xfE.0P-1);",
1275 "pub const FOOBAZ = @as(c_longdouble, 0xfE.P-1);",
12761276 });
12771277
12781278 cases.add("comments",
......@@ -3730,7 +3730,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
37303730 , &[_][]const u8{
37313731 \\pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0));
37323732 ,
3733 \\pub const FOO = @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hexadecimal));
3733 \\pub const FOO = @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hex));
37343734 });
37353735
37363736 if (builtin.abi == .msvc) {
......@@ -3812,7 +3812,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
38123812 \\pub const MAY_NEED_PROMOTION_1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 10241024, .decimal);
38133813 \\pub const MAY_NEED_PROMOTION_2 = @import("std").zig.c_translation.promoteIntLiteral(c_long, 307230723072, .decimal);
38143814 \\pub const MAY_NEED_PROMOTION_3 = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 819281928192, .decimal);
3815 \\pub const MAY_NEED_PROMOTION_HEX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000000, .hexadecimal);
3815 \\pub const MAY_NEED_PROMOTION_HEX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000000, .hex);
38163816 \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal);
38173817 });
38183818