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
signature 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...@@ -218,7 +218,6 @@ set(ZIG_STAGE2_SOURCES
218 "${CMAKE_SOURCE_DIR}/lib/std/builtin.zig"218 "${CMAKE_SOURCE_DIR}/lib/std/builtin.zig"
219 "${CMAKE_SOURCE_DIR}/lib/std/c.zig"219 "${CMAKE_SOURCE_DIR}/lib/std/c.zig"
220 "${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig"220 "${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig"
221 "${CMAKE_SOURCE_DIR}/lib/std/c/tokenizer.zig"
222 "${CMAKE_SOURCE_DIR}/lib/std/child_process.zig"221 "${CMAKE_SOURCE_DIR}/lib/std/child_process.zig"
223 "${CMAKE_SOURCE_DIR}/lib/std/coff.zig"222 "${CMAKE_SOURCE_DIR}/lib/std/coff.zig"
224 "${CMAKE_SOURCE_DIR}/lib/std/comptime_string_map.zig"223 "${CMAKE_SOURCE_DIR}/lib/std/comptime_string_map.zig"
deps/aro/aro/Builtins/Builtin.def+152
...@@ -17008,3 +17008,155 @@ wmemmove...@@ -17008,3 +17008,155 @@ wmemmove
17008 .param_str = "w*w*wC*z"17008 .param_str = "w*w*wC*z"
17009 .header = .wchar17009 .header = .wchar
17010 .attributes = .{ .lib_function_without_prefix = true, .const_evaluable = true }17010 .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 {...@@ -408,6 +408,17 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
408 \\408 \\
409 );409 );
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
411 // types422 // types
412 if (comp.getCharSignedness() == .unsigned) try w.writeAll("#define __CHAR_UNSIGNED__ 1\n");423 if (comp.getCharSignedness() == .unsigned) try w.writeAll("#define __CHAR_UNSIGNED__ 1\n");
413 try w.writeAll("#define __CHAR_BIT__ 8\n");424 try w.writeAll("#define __CHAR_BIT__ 8\n");
...@@ -445,6 +456,10 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {...@@ -445,6 +456,10 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
445 try comp.generateSizeofType(w, "__SIZEOF_WCHAR_T__", comp.types.wchar);456 try comp.generateSizeofType(w, "__SIZEOF_WCHAR_T__", comp.types.wchar);
446 // try comp.generateSizeofType(w, "__SIZEOF_WINT_T__", .{ .specifier = .pointer });457 // 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
448 // various int types463 // various int types
449 const mapper = comp.string_interner.getSlowTypeMapper();464 const mapper = comp.string_interner.getSlowTypeMapper();
450 try generateTypeMacro(w, mapper, "__INTPTR_TYPE__", comp.types.intptr, comp.langopts);465 try generateTypeMacro(w, mapper, "__INTPTR_TYPE__", comp.types.intptr, comp.langopts);
...@@ -461,6 +476,7 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {...@@ -461,6 +476,7 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
461 try generateTypeMacro(w, mapper, "__WCHAR_TYPE__", comp.types.wchar, comp.langopts);476 try generateTypeMacro(w, mapper, "__WCHAR_TYPE__", comp.types.wchar, comp.langopts);
462477
463 try comp.generateExactWidthTypes(w, mapper);478 try comp.generateExactWidthTypes(w, mapper);
479 try comp.generateFastAndLeastWidthTypes(w, mapper);
464480
465 if (target_util.FPSemantics.halfPrecisionType(comp.target)) |half| {481 if (target_util.FPSemantics.halfPrecisionType(comp.target)) |half| {
466 try generateFloatMacros(w, "FLT16", half, "F16");482 try generateFloatMacros(w, "FLT16", half, "F16");
...@@ -497,10 +513,11 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi...@@ -497,10 +513,11 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
497 );513 );
498 }514 }
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
500 // standard macros519 // standard macros
501 try buf.appendSlice(520 try buf.appendSlice(
502 \\#define __STDC__ 1
503 \\#define __STDC_HOSTED__ 1
504 \\#define __STDC_NO_ATOMICS__ 1521 \\#define __STDC_NO_ATOMICS__ 1
505 \\#define __STDC_NO_COMPLEX__ 1522 \\#define __STDC_NO_COMPLEX__ 1
506 \\#define __STDC_NO_THREADS__ 1523 \\#define __STDC_NO_THREADS__ 1
...@@ -678,6 +695,14 @@ fn generateBuiltinTypes(comp: *Compilation) !void {...@@ -678,6 +695,14 @@ fn generateBuiltinTypes(comp: *Compilation) !void {
678695
679/// Smallest integer type with at least N bits696/// Smallest integer type with at least N bits
680fn intLeastN(comp: *const Compilation, bits: usize, signedness: std.builtin.Signedness) Type {697fn 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 }
681 const candidates = switch (signedness) {706 const candidates = switch (signedness) {
682 .signed => &[_]Type.Specifier{ .schar, .short, .int, .long, .long_long },707 .signed => &[_]Type.Specifier{ .schar, .short, .int, .long, .long_long },
683 .unsigned => &[_]Type.Specifier{ .uchar, .ushort, .uint, .ulong, .ulong_long },708 .unsigned => &[_]Type.Specifier{ .uchar, .ushort, .uint, .ulong, .ulong_long },
...@@ -693,6 +718,52 @@ fn intSize(comp: *const Compilation, specifier: Type.Specifier) u64 {...@@ -693,6 +718,52 @@ fn intSize(comp: *const Compilation, specifier: Type.Specifier) u64 {
693 return ty.sizeof(comp).?;718 return ty.sizeof(comp).?;
694}719}
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
696fn generateExactWidthTypes(comp: *const Compilation, w: anytype, mapper: StrInt.TypeMapper) !void {767fn generateExactWidthTypes(comp: *const Compilation, w: anytype, mapper: StrInt.TypeMapper) !void {
697 try comp.generateExactWidthType(w, mapper, .schar);768 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 {...@@ -236,7 +236,7 @@ pub fn set(d: *Diagnostics, name: []const u8, to: Kind) !void {
236 try d.addExtra(.{}, .{236 try d.addExtra(.{}, .{
237 .tag = .unknown_warning,237 .tag = .unknown_warning,
238 .extra = .{ .str = name },238 .extra = .{ .str = name },
239 }, &.{});239 }, &.{}, true);
240}240}
241241
242pub fn init(gpa: Allocator) Diagnostics {242pub fn init(gpa: Allocator) Diagnostics {
...@@ -251,7 +251,7 @@ pub fn deinit(d: *Diagnostics) void {...@@ -251,7 +251,7 @@ pub fn deinit(d: *Diagnostics) void {
251}251}
252252
253pub fn add(comp: *Compilation, msg: Message, expansion_locs: []const Source.Location) Compilation.Error!void {253pub 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);
255}255}
256256
257pub fn addExtra(257pub fn addExtra(
...@@ -259,6 +259,7 @@ pub fn addExtra(...@@ -259,6 +259,7 @@ pub fn addExtra(
259 langopts: LangOpts,259 langopts: LangOpts,
260 msg: Message,260 msg: Message,
261 expansion_locs: []const Source.Location,261 expansion_locs: []const Source.Location,
262 note_msg_loc: bool,
262) Compilation.Error!void {263) Compilation.Error!void {
263 const kind = d.tagKind(msg.tag, langopts);264 const kind = d.tagKind(msg.tag, langopts);
264 if (kind == .off) return;265 if (kind == .off) return;
...@@ -301,7 +302,7 @@ pub fn addExtra(...@@ -301,7 +302,7 @@ pub fn addExtra(
301 }302 }
302 }303 }
303304
304 d.list.appendAssumeCapacity(.{305 if (note_msg_loc) d.list.appendAssumeCapacity(.{
305 .tag = .expanded_from_here,306 .tag = .expanded_from_here,
306 .kind = .note,307 .kind = .note,
307 .loc = msg.loc,308 .loc = msg.loc,
deps/aro/aro/Driver.zig+16
...@@ -98,8 +98,10 @@ pub const usage =...@@ -98,8 +98,10 @@ pub const usage =
98 \\ -fno-declspec Disable support for __declspec attributes98 \\ -fno-declspec Disable support for __declspec attributes
99 \\ -ffp-eval-method=[source|double|extended]99 \\ -ffp-eval-method=[source|double|extended]
100 \\ Evaluation method to use for floating-point arithmetic100 \\ Evaluation method to use for floating-point arithmetic
101 \\ -ffreestanding Compilation in a freestanding environment
101 \\ -fgnu-inline-asm Enable GNU style inline asm (default: enabled)102 \\ -fgnu-inline-asm Enable GNU style inline asm (default: enabled)
102 \\ -fno-gnu-inline-asm Disable GNU style inline asm103 \\ -fno-gnu-inline-asm Disable GNU style inline asm
104 \\ -fhosted Compilation in a hosted environment
103 \\ -fms-extensions Enable support for Microsoft extensions105 \\ -fms-extensions Enable support for Microsoft extensions
104 \\ -fno-ms-extensions Disable support for Microsoft extensions106 \\ -fno-ms-extensions Disable support for Microsoft extensions
105 \\ -fdollars-in-identifiers 107 \\ -fdollars-in-identifiers
...@@ -177,6 +179,7 @@ pub fn parseArgs(...@@ -177,6 +179,7 @@ pub fn parseArgs(
177) !bool {179) !bool {
178 var i: usize = 1;180 var i: usize = 1;
179 var comment_arg: []const u8 = "";181 var comment_arg: []const u8 = "";
182 var hosted: ?bool = null;
180 while (i < args.len) : (i += 1) {183 while (i < args.len) : (i += 1) {
181 const arg = args[i];184 const arg = args[i];
182 if (mem.startsWith(u8, arg, "-") and arg.len > 1) {185 if (mem.startsWith(u8, arg, "-") and arg.len > 1) {
...@@ -277,6 +280,10 @@ pub fn parseArgs(...@@ -277,6 +280,10 @@ pub fn parseArgs(
277 d.comp.langopts.declspec_attrs = true;280 d.comp.langopts.declspec_attrs = true;
278 } else if (mem.eql(u8, arg, "-fno-declspec")) {281 } else if (mem.eql(u8, arg, "-fno-declspec")) {
279 d.comp.langopts.declspec_attrs = false;282 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;
280 } else if (mem.eql(u8, arg, "-fms-extensions")) {287 } else if (mem.eql(u8, arg, "-fms-extensions")) {
281 d.comp.langopts.enableMSExtensions();288 d.comp.langopts.enableMSExtensions();
282 } else if (mem.eql(u8, arg, "-fno-ms-extensions")) {289 } else if (mem.eql(u8, arg, "-fno-ms-extensions")) {
...@@ -440,6 +447,15 @@ pub fn parseArgs(...@@ -440,6 +447,15 @@ pub fn parseArgs(
440 if (d.comp.langopts.preserve_comments and !d.only_preprocess) {447 if (d.comp.langopts.preserve_comments and !d.only_preprocess) {
441 return d.fatal("invalid argument '{s}' only allowed with '-E'", .{comment_arg});448 return d.fatal("invalid argument '{s}' only allowed with '-E'", .{comment_arg});
442 }449 }
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 }
443 return false;459 return false;
444}460}
445461
deps/aro/aro/Driver/Filesystem.zig+10-10
...@@ -121,7 +121,7 @@ pub const Filesystem = union(enum) {...@@ -121,7 +121,7 @@ pub const Filesystem = union(enum) {
121 base: []const u8,121 base: []const u8,
122 i: usize = 0,122 i: usize = 0,
123123
124 fn next(self: *@This()) !?std.fs.IterableDir.Entry {124 fn next(self: *@This()) !?std.fs.Dir.Entry {
125 while (self.i < self.entries.len) {125 while (self.i < self.entries.len) {
126 const entry = self.entries[self.i];126 const entry = self.entries[self.i];
127 self.i += 1;127 self.i += 1;
...@@ -130,7 +130,7 @@ pub const Filesystem = union(enum) {...@@ -130,7 +130,7 @@ pub const Filesystem = union(enum) {
130 const remaining = entry.path[self.base.len + 1 ..];130 const remaining = entry.path[self.base.len + 1 ..];
131 if (std.mem.indexOfScalar(u8, remaining, std.fs.path.sep) != null) continue;131 if (std.mem.indexOfScalar(u8, remaining, std.fs.path.sep) != null) continue;
132 const extension = std.fs.path.extension(remaining);132 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;
134 return .{ .name = remaining, .kind = kind };134 return .{ .name = remaining, .kind = kind };
135 }135 }
136 }136 }
...@@ -139,18 +139,18 @@ pub const Filesystem = union(enum) {...@@ -139,18 +139,18 @@ pub const Filesystem = union(enum) {
139 };139 };
140 };140 };
141141
142 const IterableDir = union(enum) {142 const Dir = union(enum) {
143 dir: std.fs.IterableDir,143 dir: std.fs.Dir,
144 fake: FakeDir,144 fake: FakeDir,
145145
146 pub fn iterate(self: IterableDir) Iterator {146 pub fn iterate(self: Dir) Iterator {
147 return switch (self) {147 return switch (self) {
148 .dir => |dir| .{ .iterator = dir.iterate() },148 .dir => |dir| .{ .iterator = dir.iterate() },
149 .fake => |fake| .{ .fake = fake.iterate() },149 .fake => |fake| .{ .fake = fake.iterate() },
150 };150 };
151 }151 }
152152
153 pub fn close(self: *IterableDir) void {153 pub fn close(self: *Dir) void {
154 switch (self.*) {154 switch (self.*) {
155 .dir => |*d| d.close(),155 .dir => |*d| d.close(),
156 .fake => {},156 .fake => {},
...@@ -159,10 +159,10 @@ pub const Filesystem = union(enum) {...@@ -159,10 +159,10 @@ pub const Filesystem = union(enum) {
159 };159 };
160160
161 const Iterator = union(enum) {161 const Iterator = union(enum) {
162 iterator: std.fs.IterableDir.Iterator,162 iterator: std.fs.Dir.Iterator,
163 fake: FakeDir.Iterator,163 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 {
166 return switch (self.*) {166 return switch (self.*) {
167 .iterator => |*it| it.next(),167 .iterator => |*it| it.next(),
168 .fake => |*it| it.next(),168 .fake => |*it| it.next(),
...@@ -221,9 +221,9 @@ pub const Filesystem = union(enum) {...@@ -221,9 +221,9 @@ pub const Filesystem = union(enum) {
221 };221 };
222 }222 }
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 {
225 return switch (fs) {225 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 }) },
227 .fake => |entries| .{ .fake = .{ .entries = entries, .path = dir_name } },227 .fake => |entries| .{ .fake = .{ .entries = entries, .path = dir_name } },
228 };228 };
229 }229 }
deps/aro/aro/Driver/GCCDetector.zig+1-1
...@@ -602,7 +602,7 @@ fn scanLibDirForGCCTriple(...@@ -602,7 +602,7 @@ fn scanLibDirForGCCTriple(
602 const lib_suffix = std.fs.path.join(suffix_buf_fib.allocator(), &.{ base, candidate_triple }) catch continue;602 const lib_suffix = std.fs.path.join(suffix_buf_fib.allocator(), &.{ base, candidate_triple }) catch continue;
603603
604 const dir_name = std.fs.path.join(fib.allocator(), &.{ lib_dir, lib_suffix }) catch continue;604 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;
606 defer parent_dir.close();606 defer parent_dir.close();
607607
608 var it = parent_dir.iterate();608 var it = parent_dir.iterate();
deps/aro/aro/Parser.zig+79-32
...@@ -9,6 +9,8 @@ const Tokenizer = @import("Tokenizer.zig");...@@ -9,6 +9,8 @@ const Tokenizer = @import("Tokenizer.zig");
9const Preprocessor = @import("Preprocessor.zig");9const Preprocessor = @import("Preprocessor.zig");
10const Tree = @import("Tree.zig");10const Tree = @import("Tree.zig");
11const Token = Tree.Token;11const Token = Tree.Token;
12const NumberPrefix = Token.NumberPrefix;
13const NumberSuffix = Token.NumberSuffix;
12const TokenIndex = Tree.TokenIndex;14const TokenIndex = Tree.TokenIndex;
13const NodeIndex = Tree.NodeIndex;15const NodeIndex = Tree.NodeIndex;
14const Type = @import("Type.zig");16const Type = @import("Type.zig");
...@@ -24,9 +26,6 @@ const Symbol = SymbolStack.Symbol;...@@ -24,9 +26,6 @@ const Symbol = SymbolStack.Symbol;
24const record_layout = @import("record_layout.zig");26const record_layout = @import("record_layout.zig");
25const StrInt = @import("StringInterner.zig");27const StrInt = @import("StringInterner.zig");
26const StringId = StrInt.StringId;28const StringId = StrInt.StringId;
27const number_affixes = @import("number_affixes.zig");
28const NumberPrefix = number_affixes.Prefix;
29const NumberSuffix = number_affixes.Suffix;
30const Builtins = @import("Builtins.zig");29const Builtins = @import("Builtins.zig");
31const Builtin = Builtins.Builtin;30const Builtin = Builtins.Builtin;
32const target_util = @import("target.zig");31const target_util = @import("target.zig");
...@@ -323,7 +322,7 @@ fn expectIdentifier(p: *Parser) Error!TokenIndex {...@@ -323,7 +322,7 @@ fn expectIdentifier(p: *Parser) Error!TokenIndex {
323 return p.errExpectedToken(.identifier, actual);322 return p.errExpectedToken(.identifier, actual);
324 }323 }
325324
326 return (try p.eatIdentifier()) orelse unreachable;325 return (try p.eatIdentifier()) orelse error.ParsingFailed;
327}326}
328327
329fn eatToken(p: *Parser, id: Token.Id) ?TokenIndex {328fn eatToken(p: *Parser, id: Token.Id) ?TokenIndex {
...@@ -347,7 +346,7 @@ pub fn tokSlice(p: *Parser, tok: TokenIndex) []const u8 {...@@ -347,7 +346,7 @@ pub fn tokSlice(p: *Parser, tok: TokenIndex) []const u8 {
347 const loc = p.pp.tokens.items(.loc)[tok];346 const loc = p.pp.tokens.items(.loc)[tok];
348 var tmp_tokenizer = Tokenizer{347 var tmp_tokenizer = Tokenizer{
349 .buf = p.comp.getSource(loc.id).buf,348 .buf = p.comp.getSource(loc.id).buf,
350 .comp = p.comp,349 .langopts = p.comp.langopts,
351 .index = loc.byte_offset,350 .index = loc.byte_offset,
352 .source = .generated,351 .source = .generated,
353 };352 };
...@@ -715,6 +714,9 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {...@@ -715,6 +714,9 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {
715 p.field_attr_buf.deinit();714 p.field_attr_buf.deinit();
716 }715 }
717716
717 try p.syms.pushScope(&p);
718 defer p.syms.popScope();
719
718 // NodeIndex 0 must be invalid720 // NodeIndex 0 must be invalid
719 _ = try p.addNode(.{ .tag = .invalid, .ty = undefined, .data = undefined });721 _ = try p.addNode(.{ .tag = .invalid, .ty = undefined, .data = undefined });
720722
...@@ -1010,7 +1012,7 @@ fn decl(p: *Parser) Error!bool {...@@ -1010,7 +1012,7 @@ fn decl(p: *Parser) Error!bool {
1010 // Collect old style parameter declarations.1012 // Collect old style parameter declarations.
1011 if (init_d.d.old_style_func != null) {1013 if (init_d.d.old_style_func != null) {
1012 const attrs = init_d.d.ty.getAttributes();1014 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;
1014 base_ty.specifier = .func;1016 base_ty.specifier = .func;
1015 init_d.d.ty = try base_ty.withAttributes(p.arena, attrs);1017 init_d.d.ty = try base_ty.withAttributes(p.arena, attrs);
10161018
...@@ -1066,7 +1068,7 @@ fn decl(p: *Parser) Error!bool {...@@ -1066,7 +1068,7 @@ fn decl(p: *Parser) Error!bool {
1066 d.ty = try Attribute.applyParameterAttributes(p, d.ty, attr_buf_top_declarator, .alignas_on_param);1068 d.ty = try Attribute.applyParameterAttributes(p, d.ty, attr_buf_top_declarator, .alignas_on_param);
10671069
1068 // bypass redefinition check to avoid duplicate errors1070 // bypass redefinition check to avoid duplicate errors
1069 try p.syms.syms.append(p.gpa, .{1071 try p.syms.define(p.gpa, .{
1070 .kind = .def,1072 .kind = .def,
1071 .name = interned_name,1073 .name = interned_name,
1072 .tok = d.name,1074 .tok = d.name,
...@@ -1088,7 +1090,7 @@ fn decl(p: *Parser) Error!bool {...@@ -1088,7 +1090,7 @@ fn decl(p: *Parser) Error!bool {
1088 }1090 }
10891091
1090 // bypass redefinition check to avoid duplicate errors1092 // bypass redefinition check to avoid duplicate errors
1091 try p.syms.syms.append(p.gpa, .{1093 try p.syms.define(p.gpa, .{
1092 .kind = .def,1094 .kind = .def,
1093 .name = param.name,1095 .name = param.name,
1094 .tok = param.name_tok,1096 .tok = param.name_tok,
...@@ -1428,12 +1430,14 @@ fn typeof(p: *Parser) Error!?Type {...@@ -1428,12 +1430,14 @@ fn typeof(p: *Parser) Error!?Type {
1428 .data = typeof_expr.ty.data,1430 .data = typeof_expr.ty.data,
1429 .qual = if (unqual) .{} else typeof_expr.ty.qual.inheritFromTypeof(),1431 .qual = if (unqual) .{} else typeof_expr.ty.qual.inheritFromTypeof(),
1430 .specifier = typeof_expr.ty.specifier,1432 .specifier = typeof_expr.ty.specifier,
1433 .decayed = typeof_expr.ty.decayed,
1431 },1434 },
1432 };1435 };
14331436
1434 return Type{1437 return Type{
1435 .data = .{ .expr = inner },1438 .data = .{ .expr = inner },
1436 .specifier = .typeof_expr,1439 .specifier = .typeof_expr,
1440 .decayed = typeof_expr.ty.decayed,
1437 };1441 };
1438}1442}
14391443
...@@ -1814,6 +1818,7 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?...@@ -1814,6 +1818,7 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
1814 } else {1818 } else {
1815 init_d.d.ty.specifier = init_d.initializer.ty.specifier;1819 init_d.d.ty.specifier = init_d.initializer.ty.specifier;
1816 init_d.d.ty.data = init_d.initializer.ty.data;1820 init_d.d.ty.data = init_d.initializer.ty.data;
1821 init_d.d.ty.decayed = init_d.initializer.ty.decayed;
1817 }1822 }
1818 }1823 }
1819 if (apply_var_attributes) {1824 if (apply_var_attributes) {
...@@ -2105,7 +2110,7 @@ fn recordSpec(p: *Parser) Error!Type {...@@ -2105,7 +2110,7 @@ fn recordSpec(p: *Parser) Error!Type {
2105 .specifier = if (is_struct) .@"struct" else .@"union",2110 .specifier = if (is_struct) .@"struct" else .@"union",
2106 .data = .{ .record = record_ty },2111 .data = .{ .record = record_ty },
2107 }, attr_buf_top, null);2112 }, attr_buf_top, null);
2108 try p.syms.syms.append(p.gpa, .{2113 try p.syms.define(p.gpa, .{
2109 .kind = if (is_struct) .@"struct" else .@"union",2114 .kind = if (is_struct) .@"struct" else .@"union",
2110 .name = interned_name,2115 .name = interned_name,
2111 .tok = ident,2116 .tok = ident,
...@@ -2151,10 +2156,8 @@ fn recordSpec(p: *Parser) Error!Type {...@@ -2151,10 +2156,8 @@ fn recordSpec(p: *Parser) Error!Type {
21512156
2152 // declare a symbol for the type2157 // declare a symbol for the type
2153 // We need to replace the symbol's type if it has attributes2158 // We need to replace the symbol's type if it has attributes
2154 var symbol_index: ?usize = null;
2155 if (maybe_ident != null and !defined) {2159 if (maybe_ident != null and !defined) {
2156 symbol_index = p.syms.syms.len;2160 try p.syms.define(p.gpa, .{
2157 try p.syms.syms.append(p.gpa, .{
2158 .kind = if (is_struct) .@"struct" else .@"union",2161 .kind = if (is_struct) .@"struct" else .@"union",
2159 .name = record_ty.name,2162 .name = record_ty.name,
2160 .tok = maybe_ident.?,2163 .tok = maybe_ident.?,
...@@ -2216,8 +2219,11 @@ fn recordSpec(p: *Parser) Error!Type {...@@ -2216,8 +2219,11 @@ fn recordSpec(p: *Parser) Error!Type {
2216 .specifier = if (is_struct) .@"struct" else .@"union",2219 .specifier = if (is_struct) .@"struct" else .@"union",
2217 .data = .{ .record = record_ty },2220 .data = .{ .record = record_ty },
2218 }, attr_buf_top, null);2221 }, attr_buf_top, null);
2219 if (ty.specifier == .attributed and symbol_index != null) {2222 if (ty.specifier == .attributed and maybe_ident != null) {
2220 p.syms.syms.items(.ty)[symbol_index.?] = ty;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;
2221 }2227 }
22222228
2223 if (!ty.hasIncompleteSize()) {2229 if (!ty.hasIncompleteSize()) {
...@@ -2474,7 +2480,7 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2474,7 +2480,7 @@ fn enumSpec(p: *Parser) Error!Type {
2474 .specifier = .@"enum",2480 .specifier = .@"enum",
2475 .data = .{ .@"enum" = enum_ty },2481 .data = .{ .@"enum" = enum_ty },
2476 }, attr_buf_top, null);2482 }, attr_buf_top, null);
2477 try p.syms.syms.append(p.gpa, .{2483 try p.syms.define(p.gpa, .{
2478 .kind = .@"enum",2484 .kind = .@"enum",
2479 .name = interned_name,2485 .name = interned_name,
2480 .tok = ident,2486 .tok = ident,
...@@ -2525,7 +2531,6 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2525,7 +2531,6 @@ fn enumSpec(p: *Parser) Error!Type {
2525 p.enum_buf.items.len = enum_buf_top;2531 p.enum_buf.items.len = enum_buf_top;
2526 }2532 }
25272533
2528 const sym_stack_top = p.syms.syms.len;
2529 var e = Enumerator.init(fixed_ty);2534 var e = Enumerator.init(fixed_ty);
2530 while (try p.enumerator(&e)) |field_and_node| {2535 while (try p.enumerator(&e)) |field_and_node| {
2531 try p.enum_buf.append(field_and_node.field);2536 try p.enum_buf.append(field_and_node.field);
...@@ -2551,13 +2556,12 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2551,13 +2556,12 @@ fn enumSpec(p: *Parser) Error!Type {
2551 const field_nodes = p.list_buf.items[list_buf_top..];2556 const field_nodes = p.list_buf.items[list_buf_top..];
25522557
2553 if (fixed_ty == null) {2558 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
2557 for (enum_fields, 0..) |*field, i| {2559 for (enum_fields, 0..) |*field, i| {
2558 if (field.ty.eql(Type.int, p.comp, false)) continue;2560 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 };
2561 const dest_ty = if (p.comp.fixedEnumTagSpecifier()) |some|2565 const dest_ty = if (p.comp.fixedEnumTagSpecifier()) |some|
2562 Type{ .specifier = some }2566 Type{ .specifier = some }
2563 else if (try res.intFitsInType(p, Type.int))2567 else if (try res.intFitsInType(p, Type.int))
...@@ -2567,8 +2571,9 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2567,8 +2571,9 @@ fn enumSpec(p: *Parser) Error!Type {
2567 else2571 else
2568 continue;2572 continue;
25692573
2570 try vals[i].intCast(dest_ty, p.comp);2574 const symbol = p.syms.getPtr(field.name, .vars);
2571 types[i] = dest_ty;2575 try symbol.val.intCast(dest_ty, p.comp);
2576 symbol.ty = dest_ty;
2572 p.nodes.items(.ty)[@intFromEnum(field_nodes[i])] = dest_ty;2577 p.nodes.items(.ty)[@intFromEnum(field_nodes[i])] = dest_ty;
2573 field.ty = dest_ty;2578 field.ty = dest_ty;
2574 res.ty = dest_ty;2579 res.ty = dest_ty;
...@@ -2585,7 +2590,7 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2585,7 +2590,7 @@ fn enumSpec(p: *Parser) Error!Type {
25852590
2586 // declare a symbol for the type2591 // declare a symbol for the type
2587 if (maybe_ident != null and !defined) {2592 if (maybe_ident != null and !defined) {
2588 try p.syms.syms.append(p.gpa, .{2593 try p.syms.define(p.gpa, .{
2589 .kind = .@"enum",2594 .kind = .@"enum",
2590 .name = enum_ty.name,2595 .name = enum_ty.name,
2591 .ty = ty,2596 .ty = ty,
...@@ -2885,7 +2890,7 @@ fn declarator(...@@ -2885,7 +2890,7 @@ fn declarator(
2885 try res.ty.combine(outer);2890 try res.ty.combine(outer);
2886 try res.ty.validateCombinedType(p, suffix_start);2891 try res.ty.validateCombinedType(p, suffix_start);
2887 res.old_style_func = d.old_style_func;2892 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;
2889 return res;2894 return res;
2890 }2895 }
28912896
...@@ -4376,7 +4381,7 @@ fn stmt(p: *Parser) Error!NodeIndex {...@@ -4376,7 +4381,7 @@ fn stmt(p: *Parser) Error!NodeIndex {
4376/// | keyword_default ':' stmt4381/// | keyword_default ':' stmt
4377fn labeledStmt(p: *Parser) Error!?NodeIndex {4382fn labeledStmt(p: *Parser) Error!?NodeIndex {
4378 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) {4383 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();
4380 const str = p.tokSlice(name_tok);4385 const str = p.tokSlice(name_tok);
4381 if (p.findLabel(str)) |some| {4386 if (p.findLabel(str)) |some| {
4382 try p.errStr(.duplicate_label, name_tok, str);4387 try p.errStr(.duplicate_label, name_tok, str);
...@@ -4814,10 +4819,23 @@ const CallExpr = union(enum) {...@@ -4814,10 +4819,23 @@ const CallExpr = union(enum) {
4814 /// of arguments, `paramCountOverride` is used to tell us how many arguments we should actually expect to see for4819 /// of arguments, `paramCountOverride` is used to tell us how many arguments we should actually expect to see for
4815 /// these custom-typechecked functions.4820 /// these custom-typechecked functions.
4816 fn paramCountOverride(self: CallExpr) ?u32 {4821 fn paramCountOverride(self: CallExpr) ?u32 {
4822 @setEvalBranchQuota(10_000);
4817 return switch (self) {4823 return switch (self) {
4818 .standard => null,4824 .standard => null,
4819 .builtin => |builtin| switch (builtin.tag) {4825 .builtin => |builtin| switch (builtin.tag) {
4820 Builtin.tagFromName("__builtin_complex").? => 2,4826 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,
4821 else => null,4839 else => null,
4822 },4840 },
4823 };4841 };
...@@ -4827,10 +4845,25 @@ const CallExpr = union(enum) {...@@ -4827,10 +4845,25 @@ const CallExpr = union(enum) {
4827 return switch (self) {4845 return switch (self) {
4828 .standard => callable_ty.returnType(),4846 .standard => callable_ty.returnType(),
4829 .builtin => |builtin| switch (builtin.tag) {4847 .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 },
4830 Builtin.tagFromName("__builtin_complex").? => {4859 Builtin.tagFromName("__builtin_complex").? => {
4860 if (p.list_buf.items.len < 1) return Type.invalid; // not enough arguments; already an error
4831 const last_param = p.list_buf.items[p.list_buf.items.len - 1];4861 const last_param = p.list_buf.items[p.list_buf.items.len - 1];
4832 return p.nodes.items(.ty)[@intFromEnum(last_param)].makeComplex();4862 return p.nodes.items(.ty)[@intFromEnum(last_param)].makeComplex();
4833 },4863 },
4864 Builtin.tagFromName("__atomic_compare_exchange").?,
4865 Builtin.tagFromName("__atomic_compare_exchange_n").?,
4866 => .{ .specifier = .bool },
4834 else => callable_ty.returnType(),4867 else => callable_ty.returnType(),
4835 },4868 },
4836 };4869 };
...@@ -7458,7 +7491,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7458,7 +7491,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7458 }7491 }
7459 switch (p.tok_ids[p.tok_i]) {7492 switch (p.tok_ids[p.tok_i]) {
7460 .identifier, .extended_identifier => {7493 .identifier, .extended_identifier => {
7461 const name_tok = p.expectIdentifier() catch unreachable;7494 const name_tok = try p.expectIdentifier();
7462 const name = p.tokSlice(name_tok);7495 const name = p.tokSlice(name_tok);
7463 const interned_name = try StrInt.intern(p.comp, name);7496 const interned_name = try StrInt.intern(p.comp, name);
7464 if (p.syms.findSymbol(interned_name)) |sym| {7497 if (p.syms.findSymbol(interned_name)) |sym| {
...@@ -7938,6 +7971,8 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {...@@ -7938,6 +7971,8 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {
7938 .F, .IF => .float,7971 .F, .IF => .float,
7939 .F16 => .float16,7972 .F16 => .float16,
7940 .L, .IL => .long_double,7973 .L, .IL => .long_double,
7974 .W, .IW => .float80,
7975 .Q, .IQ, .F128, .IF128 => .float128,
7941 else => unreachable,7976 else => unreachable,
7942 } };7977 } };
7943 const val = try Value.intern(p.comp, key: {7978 const val = try Value.intern(p.comp, key: {
...@@ -7946,7 +7981,7 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {...@@ -7946,7 +7981,7 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {
7946 const strings_top = p.strings.items.len;7981 const strings_top = p.strings.items.len;
7947 defer p.strings.items.len = strings_top;7982 defer p.strings.items.len = strings_top;
7948 for (buf) |c| {7983 for (buf) |c| {
7949 if (c != '_') p.strings.appendAssumeCapacity(c);7984 if (c != '\'') p.strings.appendAssumeCapacity(c);
7950 }7985 }
79517986
7952 const float = std.fmt.parseFloat(f128, p.strings.items[strings_top..]) catch unreachable;7987 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 {...@@ -7971,6 +8006,8 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {
7971 .I => .complex_double,8006 .I => .complex_double,
7972 .IF => .complex_float,8007 .IF => .complex_float,
7973 .IL => .complex_long_double,8008 .IL => .complex_long_double,
8009 .IW => .complex_float80,
8010 .IQ, .IF128 => .complex_float128,
7974 else => unreachable,8011 else => unreachable,
7975 } };8012 } };
7976 res.val = .{}; // TODO add complex values8013 res.val = .{}; // TODO add complex values
...@@ -8123,11 +8160,21 @@ fn bitInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok_i: To...@@ -8123,11 +8160,21 @@ fn bitInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok_i: To
8123 var managed = try big.int.Managed.init(p.gpa);8160 var managed = try big.int.Managed.init(p.gpa);
8124 defer managed.deinit();8161 defer managed.deinit();
81258162
8126 managed.setString(base, buf) catch |e| switch (e) {8163 {
8127 error.InvalidBase => unreachable, // `base` is one of 2, 8, 10, 168164 try p.strings.ensureUnusedCapacity(buf.len);
8128 error.InvalidCharacter => unreachable, // digits validated by Tokenizer8165
8129 else => |er| return er,8166 const strings_top = p.strings.items.len;
8130 };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 }
8131 const c = managed.toConst();8178 const c = managed.toConst();
8132 const bits_needed: std.math.IntFittingRange(0, Compilation.bit_int_max_bits) = blk: {8179 const bits_needed: std.math.IntFittingRange(0, Compilation.bit_int_max_bits) = blk: {
8133 // Literal `0` requires at least 1 bit8180 // 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 {...@@ -315,7 +315,7 @@ fn invalidTokenDiagnostic(tok_id: Token.Id) Diagnostics.Tag {
315fn findIncludeGuard(pp: *Preprocessor, source: Source) ?[]const u8 {315fn findIncludeGuard(pp: *Preprocessor, source: Source) ?[]const u8 {
316 var tokenizer = Tokenizer{316 var tokenizer = Tokenizer{
317 .buf = source.buf,317 .buf = source.buf,
318 .comp = pp.comp,318 .langopts = pp.comp.langopts,
319 .source = source.id,319 .source = source.id,
320 };320 };
321 var hash = tokenizer.nextNoWS();321 var hash = tokenizer.nextNoWS();
...@@ -334,7 +334,7 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {...@@ -334,7 +334,7 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
334 pp.preprocess_count += 1;334 pp.preprocess_count += 1;
335 var tokenizer = Tokenizer{335 var tokenizer = Tokenizer{
336 .buf = source.buf,336 .buf = source.buf,
337 .comp = pp.comp,337 .langopts = pp.comp.langopts,
338 .source = source.id,338 .source = source.id,
339 };339 };
340340
...@@ -747,6 +747,17 @@ fn fatal(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anyty...@@ -747,6 +747,17 @@ fn fatal(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anyty
747 return error.FatalError;747 return error.FatalError;
748}748}
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
750fn verboseLog(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anytype) void {761fn verboseLog(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anytype) void {
751 const source = pp.comp.getSource(raw.source);762 const source = pp.comp.getSource(raw.source);
752 const line_col = source.lineCol(.{ .id = raw.source, .line = raw.line, .byte_offset = raw.start });763 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...@@ -1185,7 +1196,7 @@ fn pragmaOperator(pp: *Preprocessor, arg_tok: Token, operator_loc: Source.Locati
1185 try pp.comp.generated_buf.appendSlice(pp.gpa, pp.char_buf.items);1196 try pp.comp.generated_buf.appendSlice(pp.gpa, pp.char_buf.items);
1186 var tmp_tokenizer = Tokenizer{1197 var tmp_tokenizer = Tokenizer{
1187 .buf = pp.comp.generated_buf.items,1198 .buf = pp.comp.generated_buf.items,
1188 .comp = pp.comp,1199 .langopts = pp.comp.langopts,
1189 .index = @intCast(start),1200 .index = @intCast(start),
1190 .source = .generated,1201 .source = .generated,
1191 .line = pp.generated_line,1202 .line = pp.generated_line,
...@@ -1864,7 +1875,7 @@ fn expandVaOpt(...@@ -1864,7 +1875,7 @@ fn expandVaOpt(
1864 .buf = source.buf,1875 .buf = source.buf,
1865 .index = raw.start,1876 .index = raw.start,
1866 .source = raw.source,1877 .source = raw.source,
1867 .comp = pp.comp,1878 .langopts = pp.comp.langopts,
1868 .line = raw.line,1879 .line = raw.line,
1869 };1880 };
1870 while (tokenizer.index < raw.end) {1881 while (tokenizer.index < raw.end) {
...@@ -2282,11 +2293,11 @@ fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, raw: RawToken) MacroErr...@@ -2282,11 +2293,11 @@ fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, raw: RawToken) MacroErr
22822293
2283fn expandedSliceExtra(pp: *const Preprocessor, tok: Token, macro_ws_handling: enum { single_macro_ws, preserve_macro_ws }) []const u8 {2294fn expandedSliceExtra(pp: *const Preprocessor, tok: Token, macro_ws_handling: enum { single_macro_ws, preserve_macro_ws }) []const u8 {
2284 if (tok.id.lexeme()) |some| {2295 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;
2286 }2297 }
2287 var tmp_tokenizer = Tokenizer{2298 var tmp_tokenizer = Tokenizer{
2288 .buf = pp.comp.getSource(tok.loc.id).buf,2299 .buf = pp.comp.getSource(tok.loc.id).buf,
2289 .comp = pp.comp,2300 .langopts = pp.comp.langopts,
2290 .index = tok.loc.byte_offset,2301 .index = tok.loc.byte_offset,
2291 .source = .generated,2302 .source = .generated,
2292 };2303 };
...@@ -2340,7 +2351,7 @@ fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token)...@@ -2340,7 +2351,7 @@ fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token)
2340 // Try to tokenize the result.2351 // Try to tokenize the result.
2341 var tmp_tokenizer = Tokenizer{2352 var tmp_tokenizer = Tokenizer{
2342 .buf = pp.comp.generated_buf.items,2353 .buf = pp.comp.generated_buf.items,
2343 .comp = pp.comp,2354 .langopts = pp.comp.langopts,
2344 .index = @intCast(start),2355 .index = @intCast(start),
2345 .source = .generated,2356 .source = .generated,
2346 };2357 };
...@@ -2703,6 +2714,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {...@@ -2703,6 +2714,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
2703 error.InvalidInclude => return,2714 error.InvalidInclude => return,
2704 else => |e| return e,2715 else => |e| return e,
2705 };2716 };
2717 defer Token.free(filename_tok.expansion_locs, pp.gpa);
27062718
2707 // Check for empty filename.2719 // Check for empty filename.
2708 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);2720 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);
...@@ -2836,7 +2848,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {...@@ -2836,7 +2848,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
2836 }2848 }
28372849
2838 const embed_bytes = (try pp.comp.findEmbed(filename, first.source, include_type, limit)) orelse2850 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);
2840 defer pp.comp.gpa.free(embed_bytes);2852 defer pp.comp.gpa.free(embed_bytes);
28412853
2842 try Range.expand(prefix, pp, tokenizer);2854 try Range.expand(prefix, pp, tokenizer);
...@@ -2984,8 +2996,6 @@ fn findIncludeFilenameToken(...@@ -2984,8 +2996,6 @@ fn findIncludeFilenameToken(
2984 tokenizer: *Tokenizer,2996 tokenizer: *Tokenizer,
2985 trailing_token_behavior: enum { ignore_trailing_tokens, expect_nl_eof },2997 trailing_token_behavior: enum { ignore_trailing_tokens, expect_nl_eof },
2986) !Token {2998) !Token {
2987 const start = pp.tokens.len;
2988 defer pp.tokens.len = start;
2989 var first = first_token;2999 var first = first_token;
29903000
2991 if (first.id == .angle_bracket_left) to_end: {3001 if (first.id == .angle_bracket_left) to_end: {
...@@ -3008,35 +3018,60 @@ fn findIncludeFilenameToken(...@@ -3008,35 +3018,60 @@ fn findIncludeFilenameToken(
3008 }, &.{});3018 }, &.{});
3009 try pp.err(first, .header_str_match);3019 try pp.err(first, .header_str_match);
3010 }3020 }
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.3022 const source_tok = tokFromRaw(first);
3015 const filename_tok = pp.tokens.get(start);3023 const filename_tok, const expanded_trailing = switch (source_tok.id) {
3016 switch (filename_tok.id) {3024 .string_literal, .macro_string => .{ source_tok, false },
3017 .string_literal, .macro_string => {},3025 else => expanded: {
3018 else => {3026 // Try to expand if the argument is a macro.
3019 try pp.err(first, .expected_filename);3027 pp.top_expansion_buf.items.len = 0;
3020 try pp.expectNl(tokenizer);3028 defer for (pp.top_expansion_buf.items) |tok| Token.free(tok.expansion_locs, pp.gpa);
3021 return error.InvalidInclude;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 };
3022 },3047 },
3023 }3048 };
3049
3024 switch (trailing_token_behavior) {3050 switch (trailing_token_behavior) {
3025 .expect_nl_eof => {3051 .expect_nl_eof => {
3026 // Error on extra tokens.3052 // Error on extra tokens.
3027 const nl = tokenizer.nextNoWS();3053 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) {
3029 skipToNl(tokenizer);3055 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);
3031 }3060 }
3032 },3061 },
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 },
3034 }3068 }
3035 return filename_tok;3069 return filename_tok;
3036}3070}
30373071
3038fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken, which: Compilation.WhichInclude) !Source {3072fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken, which: Compilation.WhichInclude) !Source {
3039 const filename_tok = try pp.findIncludeFilenameToken(first, tokenizer, .expect_nl_eof);3073 const filename_tok = try pp.findIncludeFilenameToken(first, tokenizer, .expect_nl_eof);
3074 defer Token.free(filename_tok.expansion_locs, pp.gpa);
30403075
3041 // Check for empty filename.3076 // Check for empty filename.
3042 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);3077 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);
...@@ -3054,7 +3089,7 @@ fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken,...@@ -3054,7 +3089,7 @@ fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken,
3054 };3089 };
30553090
3056 return (try pp.comp.findInclude(filename, first, include_type, which)) orelse3091 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);
3058}3093}
30593094
3060fn printLinemarker(3095fn printLinemarker(
deps/aro/aro/SymbolStack.zig+201-184
...@@ -11,6 +11,8 @@ const Parser = @import("Parser.zig");...@@ -11,6 +11,8 @@ const Parser = @import("Parser.zig");
11const Value = @import("Value.zig");11const Value = @import("Value.zig");
12const StringId = @import("StringInterner.zig").StringId;12const StringId = @import("StringInterner.zig").StringId;
1313
14const SymbolStack = @This();
15
14pub const Symbol = struct {16pub const Symbol = struct {
15 name: StringId,17 name: StringId,
16 ty: Type,18 ty: Type,
...@@ -31,72 +33,74 @@ pub const Kind = enum {...@@ -31,72 +33,74 @@ pub const Kind = enum {
31 constexpr,33 constexpr,
32};34};
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) = .{},41const Scope = struct {
37scopes: std.ArrayListUnmanaged(u32) = .{},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
39pub fn deinit(s: *SymbolStack, gpa: Allocator) void {56pub 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 }
41 s.scopes.deinit(gpa);61 s.scopes.deinit(gpa);
42 s.* = undefined;62 s.* = undefined;
43}63}
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
50pub fn pushScope(s: *SymbolStack, p: *Parser) !void {65pub 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 }
52}73}
5374
54pub fn popScope(s: *SymbolStack) void {75pub fn popScope(s: *SymbolStack) void {
55 s.syms.len = s.scopes.pop();76 s.active_len -= 1;
56}77}
5778
58pub fn findTypedef(s: *SymbolStack, p: *Parser, name: StringId, name_tok: TokenIndex, no_type_yet: bool) !?Symbol {79pub fn findTypedef(s: *SymbolStack, p: *Parser, name: StringId, name_tok: TokenIndex, no_type_yet: bool) !?Symbol {
59 const kinds = s.syms.items(.kind);80 const prev = s.lookup(name, .vars) orelse s.lookup(name, .tags) orelse return null;
60 const names = s.syms.items(.name);81 switch (prev.kind) {
61 var i = s.syms.len;82 .typedef => return prev,
62 while (i > 0) {83 .@"struct" => {
63 i -= 1;84 if (no_type_yet) return null;
64 switch (kinds[i]) {85 try p.errStr(.must_use_struct, name_tok, p.tokSlice(name_tok));
65 .typedef => if (names[i] == name) return s.syms.get(i),86 return prev;
66 .@"struct" => if (names[i] == name) {87 },
67 if (no_type_yet) return null;88 .@"union" => {
68 try p.errStr(.must_use_struct, name_tok, p.tokSlice(name_tok));89 if (no_type_yet) return null;
69 return s.syms.get(i);90 try p.errStr(.must_use_union, name_tok, p.tokSlice(name_tok));
70 },91 return prev;
71 .@"union" => if (names[i] == name) {92 },
72 if (no_type_yet) return null;93 .@"enum" => {
73 try p.errStr(.must_use_union, name_tok, p.tokSlice(name_tok));94 if (no_type_yet) return null;
74 return s.syms.get(i);95 try p.errStr(.must_use_enum, name_tok, p.tokSlice(name_tok));
75 },96 return prev;
76 .@"enum" => if (names[i] == name) {97 },
77 if (no_type_yet) return null;98 else => 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 }
84 }99 }
85 return null;
86}100}
87101
88pub fn findSymbol(s: *SymbolStack, name: StringId) ?Symbol {102pub fn findSymbol(s: *SymbolStack, name: StringId) ?Symbol {
89 const kinds = s.syms.items(.kind);103 return s.lookup(name, .vars);
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;
100}104}
101105
102pub fn findTag(106pub fn findTag(
...@@ -107,36 +111,62 @@ pub fn findTag(...@@ -107,36 +111,62 @@ pub fn findTag(
107 name_tok: TokenIndex,111 name_tok: TokenIndex,
108 next_tok_id: Token.Id,112 next_tok_id: Token.Id,
109) !?Symbol {113) !?Symbol {
110 const kinds = s.syms.items(.kind);
111 const names = s.syms.items(.name);
112 // `tag Name;` should always result in a new type if in a new scope.114 // `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;115 const prev = (if (next_tok_id == .semicolon) s.get(name, .tags) else s.lookup(name, .tags)) orelse return null;
114 var i = s.syms.len;116 switch (prev.kind) {
115 while (i > end) {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) {
116 i -= 1;148 i -= 1;
117 switch (kinds[i]) {149 switch (kind) {
118 .@"enum" => if (names[i] == name) {150 .vars => if (s.scopes.items[i].vars.get(name)) |sym| return sym,
119 if (kind == .keyword_enum) return s.syms.get(i);151 .tags => if (s.scopes.items[i].tags.get(name)) |sym| return sym,
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 => {},
131 }152 }
132 } else return null;153 }
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]);
137 return null;154 return null;
138}155}
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
140pub fn defineTypedef(170pub fn defineTypedef(
141 s: *SymbolStack,171 s: *SymbolStack,
142 p: *Parser,172 p: *Parser,
...@@ -145,25 +175,22 @@ pub fn defineTypedef(...@@ -145,25 +175,22 @@ pub fn defineTypedef(
145 tok: TokenIndex,175 tok: TokenIndex,
146 node: NodeIndex,176 node: NodeIndex,
147) !void {177) !void {
148 const kinds = s.syms.items(.kind);178 if (s.get(name, .vars)) |prev| {
149 const names = s.syms.items(.name);179 switch (prev.kind) {
150 const end = s.scopeEnd();180 .typedef => {
151 var i = s.syms.len;181 if (!ty.eql(prev.ty, p.comp, true)) {
152 while (i > end) {182 try p.errStr(.redefinition_of_typedef, tok, try p.typePairStrExtra(ty, " vs ", prev.ty));
153 i -= 1;183 if (prev.tok != 0) try p.errTok(.previous_definition, prev.tok);
154 switch (kinds[i]) {184 }
155 .typedef => if (names[i] == name) {185 },
156 const prev_ty = s.syms.items(.ty)[i];186 .enumeration, .decl, .def, .constexpr => {
157 if (ty.eql(prev_ty, p.comp, true)) break;187 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
158 try p.errStr(.redefinition_of_typedef, tok, try p.typePairStrExtra(ty, " vs ", prev_ty));188 try p.errTok(.previous_definition, prev.tok);
159 const previous_tok = s.syms.items(.tok)[i];
160 if (previous_tok != 0) try p.errTok(.previous_definition, previous_tok);
161 break;
162 },189 },
163 else => {},190 else => unreachable,
164 }191 }
165 }192 }
166 try s.syms.append(p.gpa, .{193 try s.define(p.gpa, .{
167 .kind = .typedef,194 .kind = .typedef,
168 .name = name,195 .name = name,
169 .tok = tok,196 .tok = tok,
...@@ -183,35 +210,31 @@ pub fn defineSymbol(...@@ -183,35 +210,31 @@ pub fn defineSymbol(
183 val: Value,210 val: Value,
184 constexpr: bool,211 constexpr: bool,
185) !void {212) !void {
186 const kinds = s.syms.items(.kind);213 if (s.get(name, .vars)) |prev| {
187 const names = s.syms.items(.name);214 switch (prev.kind) {
188 const end = s.scopeEnd();215 .enumeration => {
189 var i = s.syms.len;
190 while (i > end) {
191 i -= 1;
192 switch (kinds[i]) {
193 .enumeration => if (names[i] == name) {
194 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));216 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
195 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);217 try p.errTok(.previous_definition, prev.tok);
196 break;
197 },218 },
198 .decl => if (names[i] == name) {219 .decl => {
199 const prev_ty = s.syms.items(.ty)[i];220 if (!ty.eql(prev.ty, p.comp, true)) {
200 if (!ty.eql(prev_ty, p.comp, true)) {
201 try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok));221 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);
203 }223 }
204 break;
205 },224 },
206 .def, .constexpr => if (names[i] == name) {225 .def, .constexpr => {
207 try p.errStr(.redefinition, tok, p.tokSlice(tok));226 try p.errStr(.redefinition, tok, p.tokSlice(tok));
208 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);227 try p.errTok(.previous_definition, prev.tok);
209 break;
210 },228 },
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,
212 }234 }
213 }235 }
214 try s.syms.append(p.gpa, .{236
237 try s.define(p.gpa, .{
215 .kind = if (constexpr) .constexpr else .def,238 .kind = if (constexpr) .constexpr else .def,
216 .name = name,239 .name = name,
217 .tok = tok,240 .tok = tok,
...@@ -221,6 +244,15 @@ pub fn defineSymbol(...@@ -221,6 +244,15 @@ pub fn defineSymbol(
221 });244 });
222}245}
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
224pub fn declareSymbol(256pub fn declareSymbol(
225 s: *SymbolStack,257 s: *SymbolStack,
226 p: *Parser,258 p: *Parser,
...@@ -229,39 +261,34 @@ pub fn declareSymbol(...@@ -229,39 +261,34 @@ pub fn declareSymbol(
229 tok: TokenIndex,261 tok: TokenIndex,
230 node: NodeIndex,262 node: NodeIndex,
231) !void {263) !void {
232 const kinds = s.syms.items(.kind);264 if (s.get(name, .vars)) |prev| {
233 const names = s.syms.items(.name);265 switch (prev.kind) {
234 const end = s.scopeEnd();266 .enumeration => {
235 var i = s.syms.len;
236 while (i > end) {
237 i -= 1;
238 switch (kinds[i]) {
239 .enumeration => if (names[i] == name) {
240 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));267 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
241 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);268 try p.errTok(.previous_definition, prev.tok);
242 break;
243 },269 },
244 .decl => if (names[i] == name) {270 .decl => {
245 const prev_ty = s.syms.items(.ty)[i];271 if (!ty.eql(prev.ty, p.comp, true)) {
246 if (!ty.eql(prev_ty, p.comp, true)) {
247 try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok));272 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);
249 }274 }
250 break;
251 },275 },
252 .def, .constexpr => if (names[i] == name) {276 .def, .constexpr => {
253 const prev_ty = s.syms.items(.ty)[i];277 if (!ty.eql(prev.ty, p.comp, true)) {
254 if (!ty.eql(prev_ty, p.comp, true)) {
255 try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok));278 try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok));
256 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);279 try p.errTok(.previous_definition, prev.tok);
257 break;280 } else {
281 return;
258 }282 }
259 return;
260 },283 },
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,
262 }289 }
263 }290 }
264 try s.syms.append(p.gpa, .{291 try s.define(p.gpa, .{
265 .kind = .decl,292 .kind = .decl,
266 .name = name,293 .name = name,
267 .tok = tok,294 .tok = tok,
...@@ -272,25 +299,23 @@ pub fn declareSymbol(...@@ -272,25 +299,23 @@ pub fn declareSymbol(
272}299}
273300
274pub fn defineParam(s: *SymbolStack, p: *Parser, name: StringId, ty: Type, tok: TokenIndex) !void {301pub fn defineParam(s: *SymbolStack, p: *Parser, name: StringId, ty: Type, tok: TokenIndex) !void {
275 const kinds = s.syms.items(.kind);302 if (s.get(name, .vars)) |prev| {
276 const names = s.syms.items(.name);303 switch (prev.kind) {
277 const end = s.scopeEnd();304 .enumeration, .decl, .def, .constexpr => {
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) {
283 try p.errStr(.redefinition_of_parameter, tok, p.tokSlice(tok));305 try p.errStr(.redefinition_of_parameter, tok, p.tokSlice(tok));
284 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);306 try p.errTok(.previous_definition, prev.tok);
285 break;307 },
308 .typedef => {
309 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));
310 try p.errTok(.previous_definition, prev.tok);
286 },311 },
287 else => {},312 else => unreachable,
288 }313 }
289 }314 }
290 if (ty.is(.fp16) and !p.comp.hasHalfPrecisionFloatABI()) {315 if (ty.is(.fp16) and !p.comp.hasHalfPrecisionFloatABI()) {
291 try p.errStr(.suggest_pointer_for_invalid_fp16, tok, "parameters");316 try p.errStr(.suggest_pointer_for_invalid_fp16, tok, "parameters");
292 }317 }
293 try s.syms.append(p.gpa, .{318 try s.define(p.gpa, .{
294 .kind = .def,319 .kind = .def,
295 .name = name,320 .name = name,
296 .tok = tok,321 .tok = tok,
...@@ -306,35 +331,28 @@ pub fn defineTag(...@@ -306,35 +331,28 @@ pub fn defineTag(
306 kind: Token.Id,331 kind: Token.Id,
307 tok: TokenIndex,332 tok: TokenIndex,
308) !?Symbol {333) !?Symbol {
309 const kinds = s.syms.items(.kind);334 const prev = s.get(name, .tags) orelse return null;
310 const names = s.syms.items(.name);335 switch (prev.kind) {
311 const end = s.scopeEnd();336 .@"enum" => {
312 var i = s.syms.len;337 if (kind == .keyword_enum) return prev;
313 while (i > end) {338 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
314 i -= 1;339 try p.errTok(.previous_definition, prev.tok);
315 switch (kinds[i]) {340 return null;
316 .@"enum" => if (names[i] == name) {341 },
317 if (kind == .keyword_enum) return s.syms.get(i);342 .@"struct" => {
318 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));343 if (kind == .keyword_struct) return prev;
319 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);344 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
320 return null;345 try p.errTok(.previous_definition, prev.tok);
321 },346 return null;
322 .@"struct" => if (names[i] == name) {347 },
323 if (kind == .keyword_struct) return s.syms.get(i);348 .@"union" => {
324 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));349 if (kind == .keyword_union) return prev;
325 try p.errTok(.previous_definition, s.syms.items(.tok)[i]);350 try p.errStr(.wrong_tag, tok, p.tokSlice(tok));
326 return null;351 try p.errTok(.previous_definition, prev.tok);
327 },352 return null;
328 .@"union" => if (names[i] == name) {353 },
329 if (kind == .keyword_union) return s.syms.get(i);354 else => unreachable,
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 }
336 }355 }
337 return null;
338}356}
339357
340pub fn defineEnumeration(358pub fn defineEnumeration(
...@@ -345,27 +363,26 @@ pub fn defineEnumeration(...@@ -345,27 +363,26 @@ pub fn defineEnumeration(
345 tok: TokenIndex,363 tok: TokenIndex,
346 val: Value,364 val: Value,
347) !void {365) !void {
348 const kinds = s.syms.items(.kind);366 if (s.get(name, .vars)) |prev| {
349 const names = s.syms.items(.name);367 switch (prev.kind) {
350 const end = s.scopeEnd();368 .enumeration => {
351 var i = s.syms.len;
352 while (i > end) {
353 i -= 1;
354 switch (kinds[i]) {
355 .enumeration => if (names[i] == name) {
356 try p.errStr(.redefinition, tok, p.tokSlice(tok));369 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);
358 return;371 return;
359 },372 },
360 .decl, .def, .constexpr => if (names[i] == name) {373 .decl, .def, .constexpr => {
361 try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok));374 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);
363 return;376 return;
364 },377 },
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,
366 }383 }
367 }384 }
368 try s.syms.append(p.gpa, .{385 try s.define(p.gpa, .{
369 .kind = .enumeration,386 .kind = .enumeration,
370 .name = name,387 .name = name,
371 .tok = tok,388 .tok = tok,
deps/aro/aro/Tokenizer.zig+26-23
...@@ -749,12 +749,15 @@ pub const Token = struct {...@@ -749,12 +749,15 @@ pub const Token = struct {
749 .string_literal_utf_8,749 .string_literal_utf_8,
750 .string_literal_utf_32,750 .string_literal_utf_32,
751 .string_literal_wide,751 .string_literal_wide,
752 .unterminated_string_literal,
752 => "a string literal",753 => "a string literal",
753 .char_literal,754 .char_literal,
754 .char_literal_utf_8,755 .char_literal_utf_8,
755 .char_literal_utf_16,756 .char_literal_utf_16,
756 .char_literal_utf_32,757 .char_literal_utf_32,
757 .char_literal_wide,758 .char_literal_wide,
759 .unterminated_char_literal,
760 .empty_char_literal,
758 => "a character literal",761 => "a character literal",
759 .pp_num, .embed_byte => "A number",762 .pp_num, .embed_byte => "A number",
760 else => id.lexeme().?,763 else => id.lexeme().?,
...@@ -798,7 +801,7 @@ pub const Token = struct {...@@ -798,7 +801,7 @@ pub const Token = struct {
798 };801 };
799 }802 }
800803
801 pub fn allowsDigraphs(id: Id, comp: *const Compilation) bool {804 pub fn allowsDigraphs(id: Id, langopts: LangOpts) bool {
802 return switch (id) {805 return switch (id) {
803 .l_bracket,806 .l_bracket,
804 .r_bracket,807 .r_bracket,
...@@ -806,7 +809,7 @@ pub const Token = struct {...@@ -806,7 +809,7 @@ pub const Token = struct {
806 .r_brace,809 .r_brace,
807 .hash,810 .hash,
808 .hash_hash,811 .hash_hash,
809 => comp.langopts.hasDigraphs(),812 => langopts.hasDigraphs(),
810 else => false,813 else => false,
811 };814 };
812 }815 }
...@@ -829,15 +832,15 @@ pub const Token = struct {...@@ -829,15 +832,15 @@ pub const Token = struct {
829 /// double underscore and underscore + capital letter identifiers832 /// double underscore and underscore + capital letter identifiers
830 /// belong to the implementation namespace, so we always convert them833 /// belong to the implementation namespace, so we always convert them
831 /// to keywords.834 /// 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 {
833 const kw = all_kws.get(str) orelse return .identifier;836 const kw = all_kws.get(str) orelse return .identifier;
834 const standard = comp.langopts.standard;837 const standard = langopts.standard;
835 return switch (kw) {838 return switch (kw) {
836 .keyword_inline => if (standard.isGNU() or standard.atLeast(.c99)) kw else .identifier,839 .keyword_inline => if (standard.isGNU() or standard.atLeast(.c99)) kw else .identifier,
837 .keyword_restrict => if (standard.atLeast(.c99)) kw else .identifier,840 .keyword_restrict => if (standard.atLeast(.c99)) kw else .identifier,
838 .keyword_typeof => if (standard.isGNU() or standard.atLeast(.c23)) kw else .identifier,841 .keyword_typeof => if (standard.isGNU() or standard.atLeast(.c23)) kw else .identifier,
839 .keyword_asm => if (standard.isGNU()) kw else .identifier,842 .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
842 .keyword_c23_alignas,845 .keyword_c23_alignas,
843 .keyword_c23_alignof,846 .keyword_c23_alignof,
...@@ -864,7 +867,7 @@ pub const Token = struct {...@@ -864,7 +867,7 @@ pub const Token = struct {
864 .keyword_stdcall2,867 .keyword_stdcall2,
865 .keyword_thiscall2,868 .keyword_thiscall2,
866 .keyword_vectorcall2,869 .keyword_vectorcall2,
867 => if (comp.langopts.ms_extensions) kw else .identifier,870 => if (langopts.ms_extensions) kw else .identifier,
868 else => kw,871 else => kw,
869 };872 };
870 }873 }
...@@ -1023,7 +1026,7 @@ const Tokenizer = @This();...@@ -1023,7 +1026,7 @@ const Tokenizer = @This();
1023buf: []const u8,1026buf: []const u8,
1024index: u32 = 0,1027index: u32 = 0,
1025source: Source.Id,1028source: Source.Id,
1026comp: *const Compilation,1029langopts: LangOpts,
1027line: u32 = 1,1030line: u32 = 1,
10281031
1029pub fn next(self: *Tokenizer) Token {1032pub fn next(self: *Tokenizer) Token {
...@@ -1162,14 +1165,14 @@ pub fn next(self: *Tokenizer) Token {...@@ -1162,14 +1165,14 @@ pub fn next(self: *Tokenizer) Token {
1162 '#' => state = .hash,1165 '#' => state = .hash,
1163 '0'...'9' => state = .pp_num,1166 '0'...'9' => state = .pp_num,
1164 '\t', '\x0B', '\x0C', ' ' => state = .whitespace,1167 '\t', '\x0B', '\x0C', ' ' => state = .whitespace,
1165 '$' => if (self.comp.langopts.dollars_in_identifiers) {1168 '$' => if (self.langopts.dollars_in_identifiers) {
1166 state = .extended_identifier;1169 state = .extended_identifier;
1167 } else {1170 } else {
1168 id = .invalid;1171 id = .invalid;
1169 self.index += 1;1172 self.index += 1;
1170 break;1173 break;
1171 },1174 },
1172 0x1A => if (self.comp.langopts.ms_extensions) {1175 0x1A => if (self.langopts.ms_extensions) {
1173 id = .eof;1176 id = .eof;
1174 break;1177 break;
1175 } else {1178 } else {
...@@ -1306,15 +1309,15 @@ pub fn next(self: *Tokenizer) Token {...@@ -1306,15 +1309,15 @@ pub fn next(self: *Tokenizer) Token {
1306 },1309 },
1307 .identifier, .extended_identifier => switch (c) {1310 .identifier, .extended_identifier => switch (c) {
1308 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},1311 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
1309 '$' => if (self.comp.langopts.dollars_in_identifiers) {1312 '$' => if (self.langopts.dollars_in_identifiers) {
1310 state = .extended_identifier;1313 state = .extended_identifier;
1311 } else {1314 } 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;
1313 break;1316 break;
1314 },1317 },
1315 0x80...0xFF => state = .extended_identifier,1318 0x80...0xFF => state = .extended_identifier,
1316 else => {1319 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;
1318 break;1321 break;
1319 },1322 },
1320 },1323 },
...@@ -1358,7 +1361,7 @@ pub fn next(self: *Tokenizer) Token {...@@ -1358,7 +1361,7 @@ pub fn next(self: *Tokenizer) Token {
1358 },1361 },
1359 .colon => switch (c) {1362 .colon => switch (c) {
1360 '>' => {1363 '>' => {
1361 if (self.comp.langopts.hasDigraphs()) {1364 if (self.langopts.hasDigraphs()) {
1362 id = .r_bracket;1365 id = .r_bracket;
1363 self.index += 1;1366 self.index += 1;
1364 } else {1367 } else {
...@@ -1367,7 +1370,7 @@ pub fn next(self: *Tokenizer) Token {...@@ -1367,7 +1370,7 @@ pub fn next(self: *Tokenizer) Token {
1367 break;1370 break;
1368 },1371 },
1369 ':' => {1372 ':' => {
1370 if (self.comp.langopts.standard.atLeast(.c23)) {1373 if (self.langopts.standard.atLeast(.c23)) {
1371 id = .colon_colon;1374 id = .colon_colon;
1372 self.index += 1;1375 self.index += 1;
1373 break;1376 break;
...@@ -1388,7 +1391,7 @@ pub fn next(self: *Tokenizer) Token {...@@ -1388,7 +1391,7 @@ pub fn next(self: *Tokenizer) Token {
1388 break;1391 break;
1389 },1392 },
1390 '>' => {1393 '>' => {
1391 if (self.comp.langopts.hasDigraphs()) {1394 if (self.langopts.hasDigraphs()) {
1392 id = .r_brace;1395 id = .r_brace;
1393 self.index += 1;1396 self.index += 1;
1394 } else {1397 } else {
...@@ -1397,7 +1400,7 @@ pub fn next(self: *Tokenizer) Token {...@@ -1397,7 +1400,7 @@ pub fn next(self: *Tokenizer) Token {
1397 break;1400 break;
1398 },1401 },
1399 ':' => {1402 ':' => {
1400 if (self.comp.langopts.hasDigraphs()) {1403 if (self.langopts.hasDigraphs()) {
1401 state = .hash_digraph;1404 state = .hash_digraph;
1402 } else {1405 } else {
1403 id = .percent;1406 id = .percent;
...@@ -1444,7 +1447,7 @@ pub fn next(self: *Tokenizer) Token {...@@ -1444,7 +1447,7 @@ pub fn next(self: *Tokenizer) Token {
1444 break;1447 break;
1445 },1448 },
1446 ':' => {1449 ':' => {
1447 if (self.comp.langopts.hasDigraphs()) {1450 if (self.langopts.hasDigraphs()) {
1448 id = .l_bracket;1451 id = .l_bracket;
1449 self.index += 1;1452 self.index += 1;
1450 } else {1453 } else {
...@@ -1453,7 +1456,7 @@ pub fn next(self: *Tokenizer) Token {...@@ -1453,7 +1456,7 @@ pub fn next(self: *Tokenizer) Token {
1453 break;1456 break;
1454 },1457 },
1455 '%' => {1458 '%' => {
1456 if (self.comp.langopts.hasDigraphs()) {1459 if (self.langopts.hasDigraphs()) {
1457 id = .l_brace;1460 id = .l_brace;
1458 self.index += 1;1461 self.index += 1;
1459 } else {1462 } else {
...@@ -1613,7 +1616,7 @@ pub fn next(self: *Tokenizer) Token {...@@ -1613,7 +1616,7 @@ pub fn next(self: *Tokenizer) Token {
1613 },1616 },
1614 .line_comment => switch (c) {1617 .line_comment => switch (c) {
1615 '\n' => {1618 '\n' => {
1616 if (self.comp.langopts.preserve_comments) {1619 if (self.langopts.preserve_comments) {
1617 id = .comment;1620 id = .comment;
1618 break;1621 break;
1619 }1622 }
...@@ -1629,7 +1632,7 @@ pub fn next(self: *Tokenizer) Token {...@@ -1629,7 +1632,7 @@ pub fn next(self: *Tokenizer) Token {
1629 },1632 },
1630 .multi_line_comment_asterisk => switch (c) {1633 .multi_line_comment_asterisk => switch (c) {
1631 '/' => {1634 '/' => {
1632 if (self.comp.langopts.preserve_comments) {1635 if (self.langopts.preserve_comments) {
1633 self.index += 1;1636 self.index += 1;
1634 id = .comment;1637 id = .comment;
1635 break;1638 break;
...@@ -1673,7 +1676,7 @@ pub fn next(self: *Tokenizer) Token {...@@ -1673,7 +1676,7 @@ pub fn next(self: *Tokenizer) Token {
1673 '.',1676 '.',
1674 => {},1677 => {},
1675 'e', 'E', 'p', 'P' => state = .pp_num_exponent,1678 'e', 'E', 'p', 'P' => state = .pp_num_exponent,
1676 '\'' => if (self.comp.langopts.standard.atLeast(.c23)) {1679 '\'' => if (self.langopts.standard.atLeast(.c23)) {
1677 state = .pp_num_digit_separator;1680 state = .pp_num_digit_separator;
1678 } else {1681 } else {
1679 id = .pp_num;1682 id = .pp_num;
...@@ -1721,7 +1724,7 @@ pub fn next(self: *Tokenizer) Token {...@@ -1721,7 +1724,7 @@ pub fn next(self: *Tokenizer) Token {
1721 } else if (self.index == self.buf.len) {1724 } else if (self.index == self.buf.len) {
1722 switch (state) {1725 switch (state) {
1723 .start, .line_comment => {},1726 .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]),
1725 .extended_identifier => id = .extended_identifier,1728 .extended_identifier => id = .extended_identifier,
17261729
1727 .period2 => {1730 .period2 => {
...@@ -2149,7 +2152,7 @@ fn expectTokensExtra(contents: []const u8, expected_tokens: []const Token.Id, st...@@ -2149,7 +2152,7 @@ fn expectTokensExtra(contents: []const u8, expected_tokens: []const Token.Id, st
2149 var tokenizer = Tokenizer{2152 var tokenizer = Tokenizer{
2150 .buf = source.buf,2153 .buf = source.buf,
2151 .source = source.id,2154 .source = source.id,
2152 .comp = &comp,2155 .langopts = comp.langopts,
2153 };2156 };
2154 var i: usize = 0;2157 var i: usize = 0;
2155 while (i < expected_tokens.len) {2158 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 {...@@ -183,18 +183,15 @@ pub fn getLinkerPath(tc: *const Toolchain, buf: []u8) ![]const u8 {
183 return tc.getProgramPath(default_linker, buf);183 return tc.getProgramPath(default_linker, buf);
184}184}
185185
186const TargetSpecificToolName = std.BoundedArray(u8, 64);
187
188/// If an explicit target is provided, also check the prefixed tool-specific name186/// If an explicit target is provided, also check the prefixed tool-specific name
189/// TODO: this isn't exactly right since our target names don't necessarily match up187/// TODO: this isn't exactly right since our target names don't necessarily match up
190/// with GCC's.188/// with GCC's.
191/// For example the Zig target `arm-freestanding-eabi` would need the `arm-none-eabi` tools189/// 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) {
193 var possible_names: std.BoundedArray([]const u8, 2) = .{};191 var possible_names: std.BoundedArray([]const u8, 2) = .{};
194 if (raw_triple) |triple| {192 if (raw_triple) |triple| {
195 const w = target_specific.writer();193 if (std.fmt.bufPrint(buf, "{s}-{s}", .{ triple, name })) |res| {
196 if (w.print("{s}-{s}", .{ triple, name })) {194 possible_names.appendAssumeCapacity(res);
197 possible_names.appendAssumeCapacity(target_specific.constSlice());
198 } else |_| {}195 } else |_| {}
199 }196 }
200 possible_names.appendAssumeCapacity(name);197 possible_names.appendAssumeCapacity(name);
...@@ -227,8 +224,8 @@ fn getProgramPath(tc: *const Toolchain, name: []const u8, buf: []u8) []const u8...@@ -227,8 +224,8 @@ fn getProgramPath(tc: *const Toolchain, name: []const u8, buf: []u8) []const u8
227 var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;224 var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
228 var fib = std.heap.FixedBufferAllocator.init(&path_buf);225 var fib = std.heap.FixedBufferAllocator.init(&path_buf);
229226
230 var tool_specific_name: TargetSpecificToolName = .{};227 var tool_specific_buf: [64]u8 = undefined;
231 const possible_names = possibleProgramNames(tc.driver.raw_target_triple, name, &tool_specific_name);228 const possible_names = possibleProgramNames(tc.driver.raw_target_triple, name, &tool_specific_buf);
232229
233 for (possible_names.constSlice()) |tool_name| {230 for (possible_names.constSlice()) |tool_name| {
234 for (tc.program_paths.items) |program_path| {231 for (tc.program_paths.items) |program_path| {
deps/aro/aro/Tree.zig+7-4
...@@ -1,11 +1,12 @@...@@ -1,11 +1,12 @@
1const std = @import("std");1const std = @import("std");
2const Interner = @import("backend").Interner;2const Interner = @import("backend").Interner;
3const Type = @import("Type.zig");3const Attribute = @import("Attribute.zig");
4const Tokenizer = @import("Tokenizer.zig");
5const CodeGen = @import("CodeGen.zig");4const CodeGen = @import("CodeGen.zig");
6const Compilation = @import("Compilation.zig");5const Compilation = @import("Compilation.zig");
6const number_affixes = @import("Tree/number_affixes.zig");
7const Source = @import("Source.zig");7const Source = @import("Source.zig");
8const Attribute = @import("Attribute.zig");8const Tokenizer = @import("Tokenizer.zig");
9const Type = @import("Type.zig");
9const Value = @import("Value.zig");10const Value = @import("Value.zig");
10const StringInterner = @import("StringInterner.zig");11const StringInterner = @import("StringInterner.zig");
1112
...@@ -92,6 +93,8 @@ pub const Token = struct {...@@ -92,6 +93,8 @@ pub const Token = struct {
9293
93 pub const List = std.MultiArrayList(Token);94 pub const List = std.MultiArrayList(Token);
94 pub const Id = Tokenizer.Token.Id;95 pub const Id = Tokenizer.Token.Id;
96 pub const NumberPrefix = number_affixes.Prefix;
97 pub const NumberSuffix = number_affixes.Suffix;
95};98};
9699
97pub const TokenIndex = u32;100pub const TokenIndex = u32;
...@@ -669,7 +672,7 @@ pub fn tokSlice(tree: *const Tree, tok_i: TokenIndex) []const u8 {...@@ -669,7 +672,7 @@ pub fn tokSlice(tree: *const Tree, tok_i: TokenIndex) []const u8 {
669 const loc = tree.tokens.items(.loc)[tok_i];672 const loc = tree.tokens.items(.loc)[tok_i];
670 var tmp_tokenizer = Tokenizer{673 var tmp_tokenizer = Tokenizer{
671 .buf = tree.comp.getSource(loc.id).buf,674 .buf = tree.comp.getSource(loc.id).buf,
672 .comp = tree.comp,675 .langopts = tree.comp.langopts,
673 .index = loc.byte_offset,676 .index = loc.byte_offset,
674 .source = .generated,677 .source = .generated,
675 };678 };
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 {...@@ -363,7 +363,6 @@ pub const Specifier = enum {
363 // data.sub_type363 // data.sub_type
364 pointer,364 pointer,
365 unspecified_variable_len_array,365 unspecified_variable_len_array,
366 decayed_unspecified_variable_len_array,
367 // data.func366 // data.func
368 /// int foo(int bar, char baz) and int (void)367 /// int foo(int bar, char baz) and int (void)
369 func,368 func,
...@@ -375,15 +374,11 @@ pub const Specifier = enum {...@@ -375,15 +374,11 @@ pub const Specifier = enum {
375374
376 // data.array375 // data.array
377 array,376 array,
378 decayed_array,
379 static_array,377 static_array,
380 decayed_static_array,
381 incomplete_array,378 incomplete_array,
382 decayed_incomplete_array,
383 vector,379 vector,
384 // data.expr380 // data.expr
385 variable_len_array,381 variable_len_array,
386 decayed_variable_len_array,
387382
388 // data.record383 // data.record
389 @"struct",384 @"struct",
...@@ -394,13 +389,9 @@ pub const Specifier = enum {...@@ -394,13 +389,9 @@ pub const Specifier = enum {
394389
395 /// typeof(type-name)390 /// typeof(type-name)
396 typeof_type,391 typeof_type,
397 /// decayed array created with typeof(type-name)
398 decayed_typeof_type,
399392
400 /// typeof(expression)393 /// typeof(expression)
401 typeof_expr,394 typeof_expr,
402 /// decayed array created with typeof(expression)
403 decayed_typeof_expr,
404395
405 /// data.attributed396 /// data.attributed
406 attributed,397 attributed,
...@@ -428,6 +419,7 @@ data: union {...@@ -428,6 +419,7 @@ data: union {
428} = .{ .none = {} },419} = .{ .none = {} },
429specifier: Specifier,420specifier: Specifier,
430qual: Qualifiers = .{},421qual: Qualifiers = .{},
422decayed: bool = false,
431423
432pub const int = Type{ .specifier = .int };424pub const int = Type{ .specifier = .int };
433pub const invalid = Type{ .specifier = .invalid };425pub const invalid = Type{ .specifier = .invalid };
...@@ -442,7 +434,7 @@ pub fn is(ty: Type, specifier: Specifier) bool {...@@ -442,7 +434,7 @@ pub fn is(ty: Type, specifier: Specifier) bool {
442pub fn withAttributes(self: Type, allocator: std.mem.Allocator, attributes: []const Attribute) !Type {434pub fn withAttributes(self: Type, allocator: std.mem.Allocator, attributes: []const Attribute) !Type {
443 if (attributes.len == 0) return self;435 if (attributes.len == 0) return self;
444 const attributed_type = try Type.Attributed.create(allocator, self, self.getAttributes(), attributes);436 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 };
446}438}
447439
448pub fn isCallable(ty: Type) ?Type {440pub fn isCallable(ty: Type) ?Type {
...@@ -468,10 +460,10 @@ pub fn isFunc(ty: Type) bool {...@@ -468,10 +460,10 @@ pub fn isFunc(ty: Type) bool {
468460
469pub fn isArray(ty: Type) bool {461pub fn isArray(ty: Type) bool {
470 return switch (ty.specifier) {462 return switch (ty.specifier) {
471 .array, .static_array, .incomplete_array, .variable_len_array, .unspecified_variable_len_array => true,463 .array, .static_array, .incomplete_array, .variable_len_array, .unspecified_variable_len_array => !ty.isDecayed(),
472 .typeof_type => ty.data.sub_type.isArray(),464 .typeof_type => !ty.isDecayed() and ty.data.sub_type.isArray(),
473 .typeof_expr => ty.data.expr.ty.isArray(),465 .typeof_expr => !ty.isDecayed() and ty.data.expr.ty.isArray(),
474 .attributed => ty.data.attributed.base.isArray(),466 .attributed => !ty.isDecayed() and ty.data.attributed.base.isArray(),
475 else => false,467 else => false,
476 };468 };
477}469}
...@@ -502,35 +494,22 @@ pub fn isScalarNonInt(ty: Type) bool {...@@ -502,35 +494,22 @@ pub fn isScalarNonInt(ty: Type) bool {
502}494}
503495
504pub fn isDecayed(ty: Type) bool {496pub fn isDecayed(ty: Type) bool {
505 const decayed = switch (ty.specifier) {497 return ty.decayed;
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;
518}498}
519499
520pub fn isPtr(ty: Type) bool {500pub fn isPtr(ty: Type) bool {
521 return switch (ty.specifier) {501 return switch (ty.specifier) {
522 .pointer,502 .pointer => true,
523 .decayed_array,503
524 .decayed_static_array,504 .array,
525 .decayed_incomplete_array,505 .static_array,
526 .decayed_variable_len_array,506 .incomplete_array,
527 .decayed_unspecified_variable_len_array,507 .variable_len_array,
528 .decayed_typeof_type,508 .unspecified_variable_len_array,
529 .decayed_typeof_expr,509 => ty.isDecayed(),
530 => true,510 .typeof_type => ty.isDecayed() or ty.data.sub_type.isPtr(),
531 .typeof_type => ty.data.sub_type.isPtr(),511 .typeof_expr => ty.isDecayed() or ty.data.expr.ty.isPtr(),
532 .typeof_expr => ty.data.expr.ty.isPtr(),512 .attributed => ty.isDecayed() or ty.data.attributed.base.isPtr(),
533 .attributed => ty.data.attributed.base.isPtr(),
534 else => false,513 else => false,
535 };514 };
536}515}
...@@ -608,15 +587,15 @@ pub fn isVoidStar(ty: Type) bool {...@@ -608,15 +587,15 @@ pub fn isVoidStar(ty: Type) bool {
608587
609pub fn isTypeof(ty: Type) bool {588pub fn isTypeof(ty: Type) bool {
610 return switch (ty.specifier) {589 return switch (ty.specifier) {
611 .typeof_type, .typeof_expr, .decayed_typeof_type, .decayed_typeof_expr => true,590 .typeof_type, .typeof_expr => true,
612 else => false,591 else => false,
613 };592 };
614}593}
615594
616pub fn isConst(ty: Type) bool {595pub fn isConst(ty: Type) bool {
617 return switch (ty.specifier) {596 return switch (ty.specifier) {
618 .typeof_type, .decayed_typeof_type => ty.qual.@"const" or ty.data.sub_type.isConst(),597 .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(),598 .typeof_expr => ty.qual.@"const" or ty.data.expr.ty.isConst(),
620 .attributed => ty.data.attributed.base.isConst(),599 .attributed => ty.data.attributed.base.isConst(),
621 else => ty.qual.@"const",600 else => ty.qual.@"const",
622 };601 };
...@@ -630,7 +609,7 @@ pub fn signedness(ty: Type, comp: *const Compilation) std.builtin.Signedness {...@@ -630,7 +609,7 @@ pub fn signedness(ty: Type, comp: *const Compilation) std.builtin.Signedness {
630 return switch (ty.specifier) {609 return switch (ty.specifier) {
631 // zig fmt: off610 // zig fmt: off
632 .char, .complex_char => return comp.getCharSignedness(),611 .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,
634 .complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128 => .unsigned,613 .complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128 => .unsigned,
635 // zig fmt: on614 // zig fmt: on
636 .bit_int, .complex_bit_int => ty.data.int.signedness,615 .bit_int, .complex_bit_int => ty.data.int.signedness,
...@@ -678,16 +657,16 @@ pub fn isAnonymousRecord(ty: Type, comp: *const Compilation) bool {...@@ -678,16 +657,16 @@ pub fn isAnonymousRecord(ty: Type, comp: *const Compilation) bool {
678657
679pub fn elemType(ty: Type) Type {658pub fn elemType(ty: Type) Type {
680 return switch (ty.specifier) {659 return switch (ty.specifier) {
681 .pointer, .unspecified_variable_len_array, .decayed_unspecified_variable_len_array => ty.data.sub_type.*,660 .pointer, .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,661 .array, .static_array, .incomplete_array, .vector => ty.data.array.elem,
683 .variable_len_array, .decayed_variable_len_array => ty.data.expr.ty,662 .variable_len_array => ty.data.expr.ty,
684 .typeof_type, .decayed_typeof_type, .typeof_expr, .decayed_typeof_expr => {663 .typeof_type, .typeof_expr => {
685 const unwrapped = ty.canonicalize(.preserve_quals);664 const unwrapped = ty.canonicalize(.preserve_quals);
686 var elem = unwrapped.elemType();665 var elem = unwrapped.elemType();
687 elem.qual = elem.qual.mergeAll(unwrapped.qual);666 elem.qual = elem.qual.mergeAll(unwrapped.qual);
688 return elem;667 return elem;
689 },668 },
690 .attributed => ty.data.attributed.base,669 .attributed => ty.data.attributed.base.elemType(),
691 .invalid => Type.invalid,670 .invalid => Type.invalid,
692 // zig fmt: off671 // zig fmt: off
693 .complex_float, .complex_double, .complex_long_double, .complex_float80,672 .complex_float, .complex_double, .complex_long_double, .complex_float80,
...@@ -703,8 +682,8 @@ pub fn elemType(ty: Type) Type {...@@ -703,8 +682,8 @@ pub fn elemType(ty: Type) Type {
703pub fn returnType(ty: Type) Type {682pub fn returnType(ty: Type) Type {
704 return switch (ty.specifier) {683 return switch (ty.specifier) {
705 .func, .var_args_func, .old_style_func => ty.data.func.return_type,684 .func, .var_args_func, .old_style_func => ty.data.func.return_type,
706 .typeof_type, .decayed_typeof_type => ty.data.sub_type.returnType(),685 .typeof_type => ty.data.sub_type.returnType(),
707 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.returnType(),686 .typeof_expr => ty.data.expr.ty.returnType(),
708 .attributed => ty.data.attributed.base.returnType(),687 .attributed => ty.data.attributed.base.returnType(),
709 .invalid => Type.invalid,688 .invalid => Type.invalid,
710 else => unreachable,689 else => unreachable,
...@@ -714,8 +693,8 @@ pub fn returnType(ty: Type) Type {...@@ -714,8 +693,8 @@ pub fn returnType(ty: Type) Type {
714pub fn params(ty: Type) []Func.Param {693pub fn params(ty: Type) []Func.Param {
715 return switch (ty.specifier) {694 return switch (ty.specifier) {
716 .func, .var_args_func, .old_style_func => ty.data.func.params,695 .func, .var_args_func, .old_style_func => ty.data.func.params,
717 .typeof_type, .decayed_typeof_type => ty.data.sub_type.params(),696 .typeof_type => ty.data.sub_type.params(),
718 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.params(),697 .typeof_expr => ty.data.expr.ty.params(),
719 .attributed => ty.data.attributed.base.params(),698 .attributed => ty.data.attributed.base.params(),
720 .invalid => &.{},699 .invalid => &.{},
721 else => unreachable,700 else => unreachable,
...@@ -724,9 +703,9 @@ pub fn params(ty: Type) []Func.Param {...@@ -724,9 +703,9 @@ pub fn params(ty: Type) []Func.Param {
724703
725pub fn arrayLen(ty: Type) ?u64 {704pub fn arrayLen(ty: Type) ?u64 {
726 return switch (ty.specifier) {705 return switch (ty.specifier) {
727 .array, .static_array, .decayed_array, .decayed_static_array => ty.data.array.len,706 .array, .static_array => ty.data.array.len,
728 .typeof_type, .decayed_typeof_type => ty.data.sub_type.arrayLen(),707 .typeof_type => ty.data.sub_type.arrayLen(),
729 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.arrayLen(),708 .typeof_expr => ty.data.expr.ty.arrayLen(),
730 .attributed => ty.data.attributed.base.arrayLen(),709 .attributed => ty.data.attributed.base.arrayLen(),
731 else => null,710 else => null,
732 };711 };
...@@ -748,8 +727,8 @@ pub fn anyQual(ty: Type) bool {...@@ -748,8 +727,8 @@ pub fn anyQual(ty: Type) bool {
748pub fn getAttributes(ty: Type) []const Attribute {727pub fn getAttributes(ty: Type) []const Attribute {
749 return switch (ty.specifier) {728 return switch (ty.specifier) {
750 .attributed => ty.data.attributed.attributes,729 .attributed => ty.data.attributed.attributes,
751 .typeof_type, .decayed_typeof_type => ty.data.sub_type.getAttributes(),730 .typeof_type => ty.data.sub_type.getAttributes(),
752 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.getAttributes(),731 .typeof_expr => ty.data.expr.ty.getAttributes(),
753 else => &.{},732 else => &.{},
754 };733 };
755}734}
...@@ -757,8 +736,8 @@ pub fn getAttributes(ty: Type) []const Attribute {...@@ -757,8 +736,8 @@ pub fn getAttributes(ty: Type) []const Attribute {
757pub fn getRecord(ty: Type) ?*const Type.Record {736pub fn getRecord(ty: Type) ?*const Type.Record {
758 return switch (ty.specifier) {737 return switch (ty.specifier) {
759 .attributed => ty.data.attributed.base.getRecord(),738 .attributed => ty.data.attributed.base.getRecord(),
760 .typeof_type, .decayed_typeof_type => ty.data.sub_type.getRecord(),739 .typeof_type => ty.data.sub_type.getRecord(),
761 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.getRecord(),740 .typeof_expr => ty.data.expr.ty.getRecord(),
762 .@"struct", .@"union" => ty.data.record,741 .@"struct", .@"union" => ty.data.record,
763 else => null,742 else => null,
764 };743 };
...@@ -901,6 +880,7 @@ pub fn bitfieldPromotion(ty: Type, comp: *Compilation, width: u32) ?Type {...@@ -901,6 +880,7 @@ pub fn bitfieldPromotion(ty: Type, comp: *Compilation, width: u32) ?Type {
901}880}
902881
903pub fn hasIncompleteSize(ty: Type) bool {882pub fn hasIncompleteSize(ty: Type) bool {
883 if (ty.isDecayed()) return false;
904 return switch (ty.specifier) {884 return switch (ty.specifier) {
905 .void, .incomplete_array => true,885 .void, .incomplete_array => true,
906 .@"enum" => ty.data.@"enum".isIncomplete() and !ty.data.@"enum".fixed,886 .@"enum" => ty.data.@"enum".isIncomplete() and !ty.data.@"enum".fixed,
...@@ -917,20 +897,14 @@ pub fn hasUnboundVLA(ty: Type) bool {...@@ -917,20 +897,14 @@ pub fn hasUnboundVLA(ty: Type) bool {
917 var cur = ty;897 var cur = ty;
918 while (true) {898 while (true) {
919 switch (cur.specifier) {899 switch (cur.specifier) {
920 .unspecified_variable_len_array,900 .unspecified_variable_len_array => return true,
921 .decayed_unspecified_variable_len_array,
922 => return true,
923 .array,901 .array,
924 .static_array,902 .static_array,
925 .incomplete_array,903 .incomplete_array,
926 .variable_len_array,904 .variable_len_array,
927 .decayed_array,
928 .decayed_static_array,
929 .decayed_incomplete_array,
930 .decayed_variable_len_array,
931 => cur = cur.elemType(),905 => cur = cur.elemType(),
932 .typeof_type, .decayed_typeof_type => cur = cur.data.sub_type.*,906 .typeof_type => cur = cur.data.sub_type.*,
933 .typeof_expr, .decayed_typeof_expr => cur = cur.data.expr.ty,907 .typeof_expr => cur = cur.data.expr.ty,
934 .attributed => cur = cur.data.attributed.base,908 .attributed => cur = cur.data.attributed.base,
935 else => return false,909 else => return false,
936 }910 }
...@@ -1006,9 +980,11 @@ pub fn sizeCompare(a: Type, b: Type, comp: *Compilation) TypeSizeOrder {...@@ -1006,9 +980,11 @@ pub fn sizeCompare(a: Type, b: Type, comp: *Compilation) TypeSizeOrder {
1006980
1007/// Size of type as reported by sizeof981/// Size of type as reported by sizeof
1008pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {982pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {
983 if (ty.isPtr()) return comp.target.ptrBitWidth() / 8;
984
1009 return switch (ty.specifier) {985 return switch (ty.specifier) {
1010 .auto_type, .c23_auto => unreachable,986 .auto_type, .c23_auto => unreachable,
1011 .variable_len_array, .unspecified_variable_len_array => return null,987 .variable_len_array, .unspecified_variable_len_array => null,
1012 .incomplete_array => return if (comp.langopts.emulate == .msvc) @as(?u64, 0) else null,988 .incomplete_array => return if (comp.langopts.emulate == .msvc) @as(?u64, 0) else null,
1013 .func, .var_args_func, .old_style_func, .void, .bool => 1,989 .func, .var_args_func, .old_style_func, .void, .bool => 1,
1014 .char, .schar, .uchar => 1,990 .char, .schar, .uchar => 1,
...@@ -1037,14 +1013,7 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {...@@ -1037,14 +1013,7 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {
1037 .complex_long_double, .complex_float80, .complex_float128, .complex_bit_int,1013 .complex_long_double, .complex_float80, .complex_float128, .complex_bit_int,
1038 => return 2 * ty.makeReal().sizeof(comp).?,1014 => return 2 * ty.makeReal().sizeof(comp).?,
1039 // zig fmt: on1015 // zig fmt: on
1040 .pointer,1016 .pointer => unreachable,
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,
1048 .static_array,1017 .static_array,
1049 .nullptr_t,1018 .nullptr_t,
1050 => comp.target.ptrBitWidth() / 8,1019 => comp.target.ptrBitWidth() / 8,
...@@ -1073,8 +1042,8 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {...@@ -1073,8 +1042,8 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {
1073pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 {1042pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 {
1074 return switch (ty.specifier) {1043 return switch (ty.specifier) {
1075 .bool => if (comp.langopts.emulate == .msvc) @as(u64, 8) else 1,1044 .bool => if (comp.langopts.emulate == .msvc) @as(u64, 8) else 1,
1076 .typeof_type, .decayed_typeof_type => ty.data.sub_type.bitSizeof(comp),1045 .typeof_type => ty.data.sub_type.bitSizeof(comp),
1077 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.bitSizeof(comp),1046 .typeof_expr => ty.data.expr.ty.bitSizeof(comp),
1078 .attributed => ty.data.attributed.base.bitSizeof(comp),1047 .attributed => ty.data.attributed.base.bitSizeof(comp),
1079 .bit_int => return ty.data.int.bits,1048 .bit_int => return ty.data.int.bits,
1080 .long_double => comp.target.c_type_bit_size(.longdouble),1049 .long_double => comp.target.c_type_bit_size(.longdouble),
...@@ -1117,7 +1086,10 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {...@@ -1117,7 +1086,10 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
1117 .unspecified_variable_len_array,1086 .unspecified_variable_len_array,
1118 .array,1087 .array,
1119 .vector,1088 .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),
1121 .func, .var_args_func, .old_style_func => target_util.defaultFunctionAlignment(comp.target),1093 .func, .var_args_func, .old_style_func => target_util.defaultFunctionAlignment(comp.target),
1122 .char, .schar, .uchar, .void, .bool => 1,1094 .char, .schar, .uchar, .void, .bool => 1,
11231095
...@@ -1153,11 +1125,6 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {...@@ -1153,11 +1125,6 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
11531125
1154 .float80, .float128 => 16,1126 .float80, .float128 => 16,
1155 .pointer,1127 .pointer,
1156 .decayed_array,
1157 .decayed_static_array,
1158 .decayed_incomplete_array,
1159 .decayed_variable_len_array,
1160 .decayed_unspecified_variable_len_array,
1161 .static_array,1128 .static_array,
1162 .nullptr_t,1129 .nullptr_t,
1163 => switch (comp.target.cpu.arch) {1130 => switch (comp.target.cpu.arch) {
...@@ -1166,8 +1133,8 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {...@@ -1166,8 +1133,8 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
1166 },1133 },
1167 .@"struct", .@"union" => if (ty.data.record.isIncomplete()) 0 else @intCast(ty.data.record.type_layout.field_alignment_bits / 8),1134 .@"struct", .@"union" => if (ty.data.record.isIncomplete()) 0 else @intCast(ty.data.record.type_layout.field_alignment_bits / 8),
1168 .@"enum" => if (ty.data.@"enum".isIncomplete() and !ty.data.@"enum".fixed) 0 else ty.data.@"enum".tag_ty.alignof(comp),1135 .@"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),1136 .typeof_type => ty.data.sub_type.alignof(comp),
1170 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.alignof(comp),1137 .typeof_expr => ty.data.expr.ty.alignof(comp),
1171 .attributed => ty.data.attributed.base.alignof(comp),1138 .attributed => ty.data.attributed.base.alignof(comp),
1172 };1139 };
1173}1140}
...@@ -1179,7 +1146,10 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {...@@ -1179,7 +1146,10 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
1179/// arrays and pointers.1146/// arrays and pointers.
1180pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals }) Type {1147pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals }) Type {
1181 var cur = ty;1148 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 }
1183 if (!cur.isTypeof()) return cur;1153 if (!cur.isTypeof()) return cur;
11841154
1185 var qual = cur.qual;1155 var qual = cur.qual;
...@@ -1187,14 +1157,6 @@ pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals })...@@ -1187,14 +1157,6 @@ pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals })
1187 switch (cur.specifier) {1157 switch (cur.specifier) {
1188 .typeof_type => cur = cur.data.sub_type.*,1158 .typeof_type => cur = cur.data.sub_type.*,
1189 .typeof_expr => cur = cur.data.expr.ty,1159 .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 },
1198 else => break,1160 else => break,
1199 }1161 }
1200 qual = qual.mergeAll(cur.qual);1162 qual = qual.mergeAll(cur.qual);
...@@ -1204,6 +1166,7 @@ pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals })...@@ -1204,6 +1166,7 @@ pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals })
1204 } else {1166 } else {
1205 cur.qual = qual;1167 cur.qual = qual;
1206 }1168 }
1169 cur.decayed = ty.decayed;
1207 return cur;1170 return cur;
1208}1171}
12091172
...@@ -1219,8 +1182,8 @@ pub fn get(ty: *const Type, specifier: Specifier) ?*const Type {...@@ -1219,8 +1182,8 @@ pub fn get(ty: *const Type, specifier: Specifier) ?*const Type {
12191182
1220pub fn requestedAlignment(ty: Type, comp: *const Compilation) ?u29 {1183pub fn requestedAlignment(ty: Type, comp: *const Compilation) ?u29 {
1221 return switch (ty.specifier) {1184 return switch (ty.specifier) {
1222 .typeof_type, .decayed_typeof_type => ty.data.sub_type.requestedAlignment(comp),1185 .typeof_type => ty.data.sub_type.requestedAlignment(comp),
1223 .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.requestedAlignment(comp),1186 .typeof_expr => ty.data.expr.ty.requestedAlignment(comp),
1224 .attributed => annotationAlignment(comp, ty.data.attributed.attributes),1187 .attributed => annotationAlignment(comp, ty.data.attributed.attributes),
1225 else => null,1188 else => null,
1226 };1189 };
...@@ -1265,14 +1228,11 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi...@@ -1265,14 +1228,11 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi
1265 if (a.qual.@"volatile" != b.qual.@"volatile") return false;1228 if (a.qual.@"volatile" != b.qual.@"volatile") return false;
1266 }1229 }
12671230
1231 if (a.isPtr()) {
1232 return a_param.elemType().eql(b_param.elemType(), comp, check_qualifiers);
1233 }
1268 switch (a.specifier) {1234 switch (a.specifier) {
1269 .pointer,1235 .pointer => unreachable,
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,
12761236
1277 .func,1237 .func,
1278 .var_args_func,1238 .var_args_func,
...@@ -1293,8 +1253,9 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi...@@ -1293,8 +1253,9 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi
1293 }1253 }
1294 if (!a.elemType().eql(b.elemType(), comp, false)) return false;1254 if (!a.elemType().eql(b.elemType(), comp, false)) return false;
1295 },1255 },
1296 .variable_len_array => if (!a.elemType().eql(b.elemType(), comp, check_qualifiers)) return false,1256 .variable_len_array => {
12971257 if (!a.elemType().eql(b.elemType(), comp, check_qualifiers)) return false;
1258 },
1298 .@"struct", .@"union" => if (a.data.record != b.data.record) return false,1259 .@"struct", .@"union" => if (a.data.record != b.data.record) return false,
1299 .@"enum" => if (a.data.@"enum" != b.data.@"enum") return false,1260 .@"enum" => if (a.data.@"enum" != b.data.@"enum") return false,
1300 .bit_int, .complex_bit_int => return a.data.int.bits == b.data.int.bits and a.data.int.signedness == b.data.int.signedness,1261 .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...@@ -1306,14 +1267,14 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi
13061267
1307/// Decays an array to a pointer1268/// Decays an array to a pointer
1308pub fn decayArray(ty: *Type) void {1269pub fn decayArray(ty: *Type) void {
1309 // the decayed array type is the current specifier +11270 std.debug.assert(ty.isArray());
1310 ty.specifier = @enumFromInt(@intFromEnum(ty.specifier) + 1);1271 ty.decayed = true;
1311}1272}
13121273
1313pub fn originalTypeOfDecayedArray(ty: Type) Type {1274pub fn originalTypeOfDecayedArray(ty: Type) Type {
1314 std.debug.assert(ty.isDecayed());1275 std.debug.assert(ty.isDecayed());
1315 var copy = ty;1276 var copy = ty;
1316 copy.specifier = @enumFromInt(@intFromEnum(ty.specifier) - 1);1277 copy.decayed = false;
1317 return copy;1278 return copy;
1318}1279}
13191280
...@@ -1405,25 +1366,23 @@ pub fn combine(inner: *Type, outer: Type) Parser.Error!void {...@@ -1405,25 +1366,23 @@ pub fn combine(inner: *Type, outer: Type) Parser.Error!void {
1405 switch (inner.specifier) {1366 switch (inner.specifier) {
1406 .pointer => return inner.data.sub_type.combine(outer),1367 .pointer => return inner.data.sub_type.combine(outer),
1407 .unspecified_variable_len_array => {1368 .unspecified_variable_len_array => {
1369 std.debug.assert(!inner.isDecayed());
1408 try inner.data.sub_type.combine(outer);1370 try inner.data.sub_type.combine(outer);
1409 },1371 },
1410 .variable_len_array => {1372 .variable_len_array => {
1373 std.debug.assert(!inner.isDecayed());
1411 try inner.data.expr.ty.combine(outer);1374 try inner.data.expr.ty.combine(outer);
1412 },1375 },
1413 .array, .static_array, .incomplete_array => {1376 .array, .static_array, .incomplete_array => {
1377 std.debug.assert(!inner.isDecayed());
1414 try inner.data.array.elem.combine(outer);1378 try inner.data.array.elem.combine(outer);
1415 },1379 },
1416 .func, .var_args_func, .old_style_func => {1380 .func, .var_args_func, .old_style_func => {
1417 try inner.data.func.return_type.combine(outer);1381 try inner.data.func.return_type.combine(outer);
1418 },1382 },
1419 .decayed_array,1383 .typeof_type,
1420 .decayed_static_array,1384 .typeof_expr,
1421 .decayed_incomplete_array,1385 => std.debug.assert(!inner.isDecayed()),
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
1427 .void, .invalid => inner.* = outer,1386 .void, .invalid => inner.* = outer,
1428 else => unreachable,1387 else => unreachable,
1429 }1388 }
...@@ -1474,8 +1433,8 @@ pub fn validateCombinedType(ty: Type, p: *Parser, source_tok: TokenIndex) Parser...@@ -1474,8 +1433,8 @@ pub fn validateCombinedType(ty: Type, p: *Parser, source_tok: TokenIndex) Parser
1474 try p.errStr(.suggest_pointer_for_invalid_fp16, source_tok, "function return value");1433 try p.errStr(.suggest_pointer_for_invalid_fp16, source_tok, "function return value");
1475 }1434 }
1476 },1435 },
1477 .typeof_type, .decayed_typeof_type => return ty.data.sub_type.validateCombinedType(p, source_tok),1436 .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),1437 .typeof_expr => return ty.data.expr.ty.validateCombinedType(p, source_tok),
1479 .attributed => return ty.data.attributed.base.validateCombinedType(p, source_tok),1438 .attributed => return ty.data.attributed.base.validateCombinedType(p, source_tok),
1480 else => {},1439 else => {},
1481 }1440 }
...@@ -1610,6 +1569,7 @@ pub const Builder = struct {...@@ -1610,6 +1569,7 @@ pub const Builder = struct {
1610 decayed_typeof_expr: *Expr,1569 decayed_typeof_expr: *Expr,
16111570
1612 attributed: *Attributed,1571 attributed: *Attributed,
1572 decayed_attributed: *Attributed,
16131573
1614 pub fn str(spec: Builder.Specifier, langopts: LangOpts) ?[]const u8 {1574 pub fn str(spec: Builder.Specifier, langopts: LangOpts) ?[]const u8 {
1615 return switch (spec) {1575 return switch (spec) {
...@@ -1835,13 +1795,10 @@ pub const Builder = struct {...@@ -1835,13 +1795,10 @@ pub const Builder = struct {
1835 ty.specifier = .pointer;1795 ty.specifier = .pointer;
1836 ty.data = .{ .sub_type = data };1796 ty.data = .{ .sub_type = data };
1837 },1797 },
1838 .unspecified_variable_len_array => |data| {1798 .unspecified_variable_len_array, .decayed_unspecified_variable_len_array => |data| {
1839 ty.specifier = .unspecified_variable_len_array;1799 ty.specifier = .unspecified_variable_len_array;
1840 ty.data = .{ .sub_type = data };1800 ty.data = .{ .sub_type = data };
1841 },1801 ty.decayed = b.specifier == .decayed_unspecified_variable_len_array;
1842 .decayed_unspecified_variable_len_array => |data| {
1843 ty.specifier = .decayed_unspecified_variable_len_array;
1844 ty.data = .{ .sub_type = data };
1845 },1802 },
1846 .func => |data| {1803 .func => |data| {
1847 ty.specifier = .func;1804 ty.specifier = .func;
...@@ -1855,41 +1812,29 @@ pub const Builder = struct {...@@ -1855,41 +1812,29 @@ pub const Builder = struct {
1855 ty.specifier = .old_style_func;1812 ty.specifier = .old_style_func;
1856 ty.data = .{ .func = data };1813 ty.data = .{ .func = data };
1857 },1814 },
1858 .array => |data| {1815 .array, .decayed_array => |data| {
1859 ty.specifier = .array;1816 ty.specifier = .array;
1860 ty.data = .{ .array = data };1817 ty.data = .{ .array = data };
1818 ty.decayed = b.specifier == .decayed_array;
1861 },1819 },
1862 .decayed_array => |data| {1820 .static_array, .decayed_static_array => |data| {
1863 ty.specifier = .decayed_array;
1864 ty.data = .{ .array = data };
1865 },
1866 .static_array => |data| {
1867 ty.specifier = .static_array;1821 ty.specifier = .static_array;
1868 ty.data = .{ .array = data };1822 ty.data = .{ .array = data };
1823 ty.decayed = b.specifier == .decayed_static_array;
1869 },1824 },
1870 .decayed_static_array => |data| {1825 .incomplete_array, .decayed_incomplete_array => |data| {
1871 ty.specifier = .decayed_static_array;
1872 ty.data = .{ .array = data };
1873 },
1874 .incomplete_array => |data| {
1875 ty.specifier = .incomplete_array;1826 ty.specifier = .incomplete_array;
1876 ty.data = .{ .array = data };1827 ty.data = .{ .array = data };
1877 },1828 ty.decayed = b.specifier == .decayed_incomplete_array;
1878 .decayed_incomplete_array => |data| {
1879 ty.specifier = .decayed_incomplete_array;
1880 ty.data = .{ .array = data };
1881 },1829 },
1882 .vector => |data| {1830 .vector => |data| {
1883 ty.specifier = .vector;1831 ty.specifier = .vector;
1884 ty.data = .{ .array = data };1832 ty.data = .{ .array = data };
1885 },1833 },
1886 .variable_len_array => |data| {1834 .variable_len_array, .decayed_variable_len_array => |data| {
1887 ty.specifier = .variable_len_array;1835 ty.specifier = .variable_len_array;
1888 ty.data = .{ .expr = data };1836 ty.data = .{ .expr = data };
1889 },1837 ty.decayed = b.specifier == .decayed_variable_len_array;
1890 .decayed_variable_len_array => |data| {
1891 ty.specifier = .decayed_variable_len_array;
1892 ty.data = .{ .expr = data };
1893 },1838 },
1894 .@"struct" => |data| {1839 .@"struct" => |data| {
1895 ty.specifier = .@"struct";1840 ty.specifier = .@"struct";
...@@ -1903,25 +1848,20 @@ pub const Builder = struct {...@@ -1903,25 +1848,20 @@ pub const Builder = struct {
1903 ty.specifier = .@"enum";1848 ty.specifier = .@"enum";
1904 ty.data = .{ .@"enum" = data };1849 ty.data = .{ .@"enum" = data };
1905 },1850 },
1906 .typeof_type => |data| {1851 .typeof_type, .decayed_typeof_type => |data| {
1907 ty.specifier = .typeof_type;1852 ty.specifier = .typeof_type;
1908 ty.data = .{ .sub_type = data };1853 ty.data = .{ .sub_type = data };
1854 ty.decayed = b.specifier == .decayed_typeof_type;
1909 },1855 },
1910 .decayed_typeof_type => |data| {1856 .typeof_expr, .decayed_typeof_expr => |data| {
1911 ty.specifier = .decayed_typeof_type;
1912 ty.data = .{ .sub_type = data };
1913 },
1914 .typeof_expr => |data| {
1915 ty.specifier = .typeof_expr;1857 ty.specifier = .typeof_expr;
1916 ty.data = .{ .expr = data };1858 ty.data = .{ .expr = data };
1859 ty.decayed = b.specifier == .decayed_typeof_expr;
1917 },1860 },
1918 .decayed_typeof_expr => |data| {1861 .attributed, .decayed_attributed => |data| {
1919 ty.specifier = .decayed_typeof_expr;
1920 ty.data = .{ .expr = data };
1921 },
1922 .attributed => |data| {
1923 ty.specifier = .attributed;1862 ty.specifier = .attributed;
1924 ty.data = .{ .attributed = data };1863 ty.data = .{ .attributed = data };
1864 ty.decayed = b.specifier == .decayed_attributed;
1925 },1865 },
1926 }1866 }
1927 if (!ty.isReal() and ty.isInt()) {1867 if (!ty.isReal() and ty.isInt()) {
...@@ -2359,30 +2299,47 @@ pub const Builder = struct {...@@ -2359,30 +2299,47 @@ pub const Builder = struct {
2359 .complex_float128 => .complex_float128,2299 .complex_float128 => .complex_float128,
23602300
2361 .pointer => .{ .pointer = ty.data.sub_type },2301 .pointer => .{ .pointer = ty.data.sub_type },
2362 .unspecified_variable_len_array => .{ .unspecified_variable_len_array = ty.data.sub_type },2302 .unspecified_variable_len_array => if (ty.isDecayed())
2363 .decayed_unspecified_variable_len_array => .{ .decayed_unspecified_variable_len_array = ty.data.sub_type },2303 .{ .decayed_unspecified_variable_len_array = ty.data.sub_type }
2304 else
2305 .{ .unspecified_variable_len_array = ty.data.sub_type },
2364 .func => .{ .func = ty.data.func },2306 .func => .{ .func = ty.data.func },
2365 .var_args_func => .{ .var_args_func = ty.data.func },2307 .var_args_func => .{ .var_args_func = ty.data.func },
2366 .old_style_func => .{ .old_style_func = ty.data.func },2308 .old_style_func => .{ .old_style_func = ty.data.func },
2367 .array => .{ .array = ty.data.array },2309 .array => if (ty.isDecayed())
2368 .decayed_array => .{ .decayed_array = ty.data.array },2310 .{ .decayed_array = ty.data.array }
2369 .static_array => .{ .static_array = ty.data.array },2311 else
2370 .decayed_static_array => .{ .decayed_static_array = ty.data.array },2312 .{ .array = ty.data.array },
2371 .incomplete_array => .{ .incomplete_array = ty.data.array },2313 .static_array => if (ty.isDecayed())
2372 .decayed_incomplete_array => .{ .decayed_incomplete_array = ty.data.array },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 },
2373 .vector => .{ .vector = ty.data.array },2321 .vector => .{ .vector = ty.data.array },
2374 .variable_len_array => .{ .variable_len_array = ty.data.expr },2322 .variable_len_array => if (ty.isDecayed())
2375 .decayed_variable_len_array => .{ .decayed_variable_len_array = ty.data.expr },2323 .{ .decayed_variable_len_array = ty.data.expr }
2324 else
2325 .{ .variable_len_array = ty.data.expr },
2376 .@"struct" => .{ .@"struct" = ty.data.record },2326 .@"struct" => .{ .@"struct" = ty.data.record },
2377 .@"union" => .{ .@"union" = ty.data.record },2327 .@"union" => .{ .@"union" = ty.data.record },
2378 .@"enum" => .{ .@"enum" = ty.data.@"enum" },2328 .@"enum" => .{ .@"enum" = ty.data.@"enum" },
23792329
2380 .typeof_type => .{ .typeof_type = ty.data.sub_type },2330 .typeof_type => if (ty.isDecayed())
2381 .decayed_typeof_type => .{ .decayed_typeof_type = ty.data.sub_type },2331 .{ .decayed_typeof_type = ty.data.sub_type }
2382 .typeof_expr => .{ .typeof_expr = ty.data.expr },2332 else
2383 .decayed_typeof_expr => .{ .decayed_typeof_expr = ty.data.expr },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 },
2386 else => unreachable,2343 else => unreachable,
2387 };2344 };
2388 }2345 }
...@@ -2472,24 +2429,17 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts...@@ -2472,24 +2429,17 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts
2472 try w.writeAll(")");2429 try w.writeAll(")");
2473 return true;2430 return true;
2474 }2431 }
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 }
2475 switch (ty.specifier) {2441 switch (ty.specifier) {
2476 .pointer,2442 .pointer => unreachable,
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 },
2493 .func, .var_args_func, .old_style_func => {2443 .func, .var_args_func, .old_style_func => {
2494 const ret_ty = ty.data.func.return_type;2444 const ret_ty = ty.data.func.return_type;
2495 const simple = try ret_ty.printPrologue(mapper, langopts, w);2445 const simple = try ret_ty.printPrologue(mapper, langopts, w);
...@@ -2541,20 +2491,14 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts...@@ -2541,20 +2491,14 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts
25412491
2542fn printEpilogue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: anytype) @TypeOf(w).Error!void {2492fn printEpilogue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: anytype) @TypeOf(w).Error!void {
2543 if (ty.qual.atomic) return;2493 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 }
2544 switch (ty.specifier) {2500 switch (ty.specifier) {
2545 .pointer,2501 .pointer => unreachable, // handled above
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 },
2558 .func, .var_args_func, .old_style_func => {2502 .func, .var_args_func, .old_style_func => {
2559 try w.writeByte('(');2503 try w.writeByte('(');
2560 for (ty.data.func.params, 0..) |param, i| {2504 for (ty.data.func.params, 0..) |param, i| {
...@@ -2637,10 +2581,10 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:...@@ -2637,10 +2581,10 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
2637 try w.writeAll(") ");2581 try w.writeAll(") ");
2638 try ty.data.func.return_type.dump(mapper, langopts, w);2582 try ty.data.func.return_type.dump(mapper, langopts, w);
2639 },2583 },
2640 .array, .static_array, .decayed_array, .decayed_static_array => {2584 .array, .static_array => {
2641 if (ty.specifier == .decayed_array or ty.specifier == .decayed_static_array) try w.writeAll("*d");2585 if (ty.isDecayed()) try w.writeAll("*d");
2642 try w.writeByte('[');2586 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 ");
2644 try w.print("{d}]", .{ty.data.array.len});2588 try w.print("{d}]", .{ty.data.array.len});
2645 try ty.data.array.elem.dump(mapper, langopts, w);2589 try ty.data.array.elem.dump(mapper, langopts, w);
2646 },2590 },
...@@ -2649,8 +2593,8 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:...@@ -2649,8 +2593,8 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
2649 try ty.data.array.elem.dump(mapper, langopts, w);2593 try ty.data.array.elem.dump(mapper, langopts, w);
2650 try w.writeAll(")");2594 try w.writeAll(")");
2651 },2595 },
2652 .incomplete_array, .decayed_incomplete_array => {2596 .incomplete_array => {
2653 if (ty.specifier == .decayed_incomplete_array) try w.writeAll("*d");2597 if (ty.isDecayed()) try w.writeAll("*d");
2654 try w.writeAll("[]");2598 try w.writeAll("[]");
2655 try ty.data.array.elem.dump(mapper, langopts, w);2599 try ty.data.array.elem.dump(mapper, langopts, w);
2656 },2600 },
...@@ -2672,27 +2616,28 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:...@@ -2672,27 +2616,28 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
2672 try w.print("union {s}", .{mapper.lookup(ty.data.record.name)});2616 try w.print("union {s}", .{mapper.lookup(ty.data.record.name)});
2673 if (dump_detailed_containers) try dumpRecord(ty.data.record, mapper, langopts, w);2617 if (dump_detailed_containers) try dumpRecord(ty.data.record, mapper, langopts, w);
2674 },2618 },
2675 .unspecified_variable_len_array, .decayed_unspecified_variable_len_array => {2619 .unspecified_variable_len_array => {
2676 if (ty.specifier == .decayed_unspecified_variable_len_array) try w.writeAll("*d");2620 if (ty.isDecayed()) try w.writeAll("*d");
2677 try w.writeAll("[*]");2621 try w.writeAll("[*]");
2678 try ty.data.sub_type.dump(mapper, langopts, w);2622 try ty.data.sub_type.dump(mapper, langopts, w);
2679 },2623 },
2680 .variable_len_array, .decayed_variable_len_array => {2624 .variable_len_array => {
2681 if (ty.specifier == .decayed_variable_len_array) try w.writeAll("*d");2625 if (ty.isDecayed()) try w.writeAll("*d");
2682 try w.writeAll("[<expr>]");2626 try w.writeAll("[<expr>]");
2683 try ty.data.expr.ty.dump(mapper, langopts, w);2627 try ty.data.expr.ty.dump(mapper, langopts, w);
2684 },2628 },
2685 .typeof_type, .decayed_typeof_type => {2629 .typeof_type => {
2686 try w.writeAll("typeof(");2630 try w.writeAll("typeof(");
2687 try ty.data.sub_type.dump(mapper, langopts, w);2631 try ty.data.sub_type.dump(mapper, langopts, w);
2688 try w.writeAll(")");2632 try w.writeAll(")");
2689 },2633 },
2690 .typeof_expr, .decayed_typeof_expr => {2634 .typeof_expr => {
2691 try w.writeAll("typeof(<expr>: ");2635 try w.writeAll("typeof(<expr>: ");
2692 try ty.data.expr.ty.dump(mapper, langopts, w);2636 try ty.data.expr.ty.dump(mapper, langopts, w);
2693 try w.writeAll(")");2637 try w.writeAll(")");
2694 },2638 },
2695 .attributed => {2639 .attributed => {
2640 if (ty.isDecayed()) try w.writeAll("*d:");
2696 try w.writeAll("attributed(");2641 try w.writeAll("attributed(");
2697 try ty.data.attributed.base.dump(mapper, langopts, w);2642 try ty.data.attributed.base.dump(mapper, langopts, w);
2698 try w.writeAll(")");2643 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 {...@@ -215,7 +215,7 @@ pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
215215
216 const limbs = try comp.gpa.alloc(216 const limbs = try comp.gpa.alloc(
217 std.math.big.Limb,217 std.math.big.Limb,
218 std.math.big.int.calcTwosCompLimbCount(bits),218 std.math.big.int.calcTwosCompLimbCount(@max(big.bitCountTwosComp(), bits)),
219 );219 );
220 defer comp.gpa.free(limbs);220 defer comp.gpa.free(limbs);
221 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };221 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 @@...@@ -1,7 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const LangOpts = @import("LangOpts.zig");2const LangOpts = @import("LangOpts.zig");
3const Type = @import("Type.zig");3const Type = @import("Type.zig");
4const llvm = @import("root").codegen.llvm;
5const TargetSet = @import("Builtins/Properties.zig").TargetSet;4const TargetSet = @import("Builtins/Properties.zig").TargetSet;
65
7/// intmax_t for this target6/// intmax_t for this target
lib/std/c.zig-8
...@@ -5,14 +5,6 @@ const page_size = std.mem.page_size;...@@ -5,14 +5,6 @@ const page_size = std.mem.page_size;
5const iovec = std.os.iovec;5const iovec = std.os.iovec;
6const iovec_const = std.os.iovec_const;6const 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
16/// The return type is `type` to force comptime function call execution.8/// The return type is `type` to force comptime function call execution.
17/// TODO: https://github.com/ziglang/zig/issues/4259/// TODO: https://github.com/ziglang/zig/issues/425
18/// If not linking libc, returns struct{pub const ok = false;}10/// 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" {...@@ -252,7 +252,7 @@ test "sizeof" {
252 try testing.expect(sizeof(anyopaque) == 1);252 try testing.expect(sizeof(anyopaque) == 1);
253}253}
254254
255pub const CIntLiteralBase = enum { decimal, octal, hexadecimal };255pub const CIntLiteralBase = enum { decimal, octal, hex };
256256
257/// Deprecated: use `CIntLiteralBase`257/// Deprecated: use `CIntLiteralBase`
258pub const CIntLiteralRadix = CIntLiteralBase;258pub const CIntLiteralRadix = CIntLiteralBase;
...@@ -289,13 +289,13 @@ pub fn promoteIntLiteral(...@@ -289,13 +289,13 @@ pub fn promoteIntLiteral(
289}289}
290290
291test "promoteIntLiteral" {291test "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);
293 try testing.expectEqual(c_uint, @TypeOf(signed_hex));293 try testing.expectEqual(c_uint, @TypeOf(signed_hex));
294294
295 if (math.maxInt(c_longlong) == math.maxInt(c_int)) return;295 if (math.maxInt(c_longlong) == math.maxInt(c_int)) return;
296296
297 const signed_decimal = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .decimal);297 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
300 if (math.maxInt(c_long) > math.maxInt(c_int)) {300 if (math.maxInt(c_long) > math.maxInt(c_int)) {
301 try testing.expectEqual(c_long, @TypeOf(signed_decimal));301 try testing.expectEqual(c_long, @TypeOf(signed_decimal));
src/Compilation.zig+1-1
...@@ -4205,7 +4205,7 @@ pub const CImportResult = struct {...@@ -4205,7 +4205,7 @@ pub const CImportResult = struct {
4205/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked4205/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked
4206/// a bit when we want to start using it from self-hosted.4206/// a bit when we want to start using it from self-hosted.
4207pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {4207pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
4208 if (build_options.only_c) unreachable; // @cImport is not needed for bootstrapping4208 if (build_options.only_core_functionality) @panic("@cImport is not available in a zig2.c build");
4209 const tracy_trace = trace(@src());4209 const tracy_trace = trace(@src());
4210 defer tracy_trace.end();4210 defer tracy_trace.end();
42114211
src/main.zig+1-1
...@@ -4293,7 +4293,7 @@ fn updateModule(comp: *Compilation) !void {...@@ -4293,7 +4293,7 @@ fn updateModule(comp: *Compilation) !void {
4293}4293}
42944294
4295fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilation.CImportResult) !void {4295fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilation.CImportResult) !void {
4296 if (build_options.only_c) unreachable; // translate-c is not needed for bootstrapping4296 if (build_options.only_core_functionality) @panic("@translate-c is not available in a zig2.c build");
4297 assert(comp.c_source_files.len == 1);4297 assert(comp.c_source_files.len == 1);
4298 const c_source_file = comp.c_source_files[0];4298 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 {...@@ -22,7 +22,9 @@ pub fn with(comptime Properties: type) type {
22 return .{};22 return .{};
23 }23 }
24 pub fn tagFromName(name: []const u8) ?Tag {24 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);
26 }28 }
27 pub const NameBuf = struct {29 pub const NameBuf = struct {
28 pub fn span(_: *const NameBuf) []const u8 {30 pub fn span(_: *const NameBuf) []const u8 {
src/translate_c.zig+305-261
...@@ -1,13 +1,13 @@...@@ -1,13 +1,13 @@
1const std = @import("std");1const std = @import("std");
2const testing = std.testing;2const testing = std.testing;
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const clang = @import("clang.zig");
5const ctok = std.c.tokenizer;
6const CToken = std.c.Token;
7const mem = std.mem;4const mem = std.mem;
8const math = std.math;5const math = std.math;
9const meta = std.meta;6const meta = std.meta;
10const CallingConvention = std.builtin.CallingConvention;7const CallingConvention = std.builtin.CallingConvention;
8const clang = @import("clang.zig");
9const aro = @import("aro");
10const CToken = aro.Tokenizer.Token;
11const ast = @import("translate_c/ast.zig");11const ast = @import("translate_c/ast.zig");
12const Node = ast.Node;12const Node = ast.Node;
13const Tag = Node.Tag;13const Tag = Node.Tag;
...@@ -190,19 +190,21 @@ pub fn translate(...@@ -190,19 +190,21 @@ pub fn translate(
190190
191/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)191/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)
192/// Macros of this form will not be translated.192/// Macros of this form will not be translated.
193fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) bool {193fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) !bool {
194 const source = getMacroText(unit, c, macro);194 const source = try getMacroText(unit, c, macro);
195 var tokenizer = std.c.Tokenizer{195 var tokenizer: aro.Tokenizer = .{
196 .buffer = source,196 .buf = source,
197 .source = .unused,
198 .langopts = .{},
197 };199 };
198 const name_tok = tokenizer.next();200 const name_tok = tokenizer.nextNoWS();
199 const name = source[name_tok.start..name_tok.end];201 const name = source[name_tok.start..name_tok.end];
200202
201 const first_tok = tokenizer.next();203 const first_tok = tokenizer.nextNoWS();
202 // We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by204 // We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by
203 // the tokenizer.205 // the tokenizer.
204 // In other words we would miss `#define inline inline` (`inline` is a valid c89 identifier)206 // 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;
206 return mem.eql(u8, name, source[first_tok.start..first_tok.end]);208 return mem.eql(u8, name, source[first_tok.start..first_tok.end]);
207}209}
208210
...@@ -223,7 +225,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {...@@ -223,7 +225,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
223 const raw_name = macro.getName_getNameStart();225 const raw_name = macro.getName_getNameStart();
224 const name = try c.str(raw_name);226 const name = try c.str(raw_name);
225227
226 if (!isSelfDefinedMacro(ast_unit, c, macro)) {228 if (!try isSelfDefinedMacro(ast_unit, c, macro)) {
227 try c.global_names.put(c.gpa, name, {});229 try c.global_names.put(c.gpa, name, {});
228 }230 }
229 },231 },
...@@ -5159,16 +5161,16 @@ pub const PatternList = struct {...@@ -5159,16 +5161,16 @@ pub const PatternList = struct {
5159 /// Assumes that `ms` represents a tokenized function-like macro.5161 /// Assumes that `ms` represents a tokenized function-like macro.
5160 fn buildArgsHash(allocator: mem.Allocator, ms: MacroSlicer, hash: *ArgsPositionMap) MacroProcessingError!void {5162 fn buildArgsHash(allocator: mem.Allocator, ms: MacroSlicer, hash: *ArgsPositionMap) MacroProcessingError!void {
5161 assert(ms.tokens.len > 2);5163 assert(ms.tokens.len > 2);
5162 assert(ms.tokens[0].id == .Identifier);5164 assert(ms.tokens[0].id == .identifier or ms.tokens[0].id == .extended_identifier);
5163 assert(ms.tokens[1].id == .LParen);5165 assert(ms.tokens[1].id == .l_paren);
51645166
5165 var i: usize = 2;5167 var i: usize = 2;
5166 while (true) : (i += 1) {5168 while (true) : (i += 1) {
5167 const token = ms.tokens[i];5169 const token = ms.tokens[i];
5168 switch (token.id) {5170 switch (token.id) {
5169 .RParen => break,5171 .r_paren => break,
5170 .Comma => continue,5172 .comma => continue,
5171 .Identifier => {5173 .identifier, .extended_identifier => {
5172 const identifier = ms.slice(token);5174 const identifier = ms.slice(token);
5173 try hash.put(allocator, identifier, i);5175 try hash.put(allocator, identifier, i);
5174 },5176 },
...@@ -5220,18 +5222,18 @@ pub const PatternList = struct {...@@ -5220,18 +5222,18 @@ pub const PatternList = struct {
5220 if (args_hash.count() != self.args_hash.count()) return false;5222 if (args_hash.count() != self.args_hash.count()) return false;
52215223
5222 var i: usize = 2;5224 var i: usize = 2;
5223 while (self.tokens[i].id != .RParen) : (i += 1) {}5225 while (self.tokens[i].id != .r_paren) : (i += 1) {}
52245226
5225 const pattern_slicer = MacroSlicer{ .source = self.source, .tokens = self.tokens };5227 const pattern_slicer = MacroSlicer{ .source = self.source, .tokens = self.tokens };
5226 while (i < self.tokens.len) : (i += 1) {5228 while (i < self.tokens.len) : (i += 1) {
5227 const pattern_token = self.tokens[i];5229 const pattern_token = self.tokens[i];
5228 const macro_token = ms.tokens[i];5230 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
5231 const pattern_bytes = pattern_slicer.slice(pattern_token);5233 const pattern_bytes = pattern_slicer.slice(pattern_token);
5232 const macro_bytes = ms.slice(macro_token);5234 const macro_bytes = ms.slice(macro_token);
5233 switch (pattern_token.id) {5235 switch (pattern_token.id) {
5234 .Identifier => {5236 .identifier, .extended_identifier => {
5235 const pattern_arg_index = self.args_hash.get(pattern_bytes);5237 const pattern_arg_index = self.args_hash.get(pattern_bytes);
5236 const macro_arg_index = args_hash.get(macro_bytes);5238 const macro_arg_index = args_hash.get(macro_bytes);
52375239
...@@ -5243,7 +5245,7 @@ pub const PatternList = struct {...@@ -5243,7 +5245,7 @@ pub const PatternList = struct {
5243 return false;5245 return false;
5244 }5246 }
5245 },5247 },
5246 .MacroString, .StringLiteral, .CharLiteral, .IntegerLiteral, .FloatLiteral => {5248 .string_literal, .char_literal, .pp_num => {
5247 if (!mem.eql(u8, pattern_bytes, macro_bytes)) return false;5249 if (!mem.eql(u8, pattern_bytes, macro_bytes)) return false;
5248 },5250 },
5249 else => {5251 else => {
...@@ -5359,13 +5361,13 @@ const MacroCtx = struct {...@@ -5359,13 +5361,13 @@ const MacroCtx = struct {
5359 return self.list[self.i].id;5361 return self.list[self.i].id;
5360 }5362 }
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 {
5363 const next_id = self.next().?;5365 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)) {
5365 try self.fail(5367 try self.fail(
5366 c,5368 c,
5367 "unable to translate C expr: expected '{s}' instead got '{s}'",5369 "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() },
5369 );5371 );
5370 return error.ParseError;5372 return error.ParseError;
5371 }5373 }
...@@ -5396,12 +5398,12 @@ const MacroCtx = struct {...@@ -5396,12 +5398,12 @@ const MacroCtx = struct {
5396 while (i < self.list.len) : (i += 1) {5398 while (i < self.list.len) : (i += 1) {
5397 const token = self.list[i];5399 const token = self.list[i];
5398 switch (token.id) {5400 switch (token.id) {
5399 .Period, .Arrow => i += 1, // skip next token since field identifiers can be unknown5401 .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) {5402 .keyword_struct, .keyword_union, .keyword_enum => if (!last_is_type_kw) {
5401 last_is_type_kw = true;5403 last_is_type_kw = true;
5402 continue;5404 continue;
5403 },5405 },
5404 .Identifier => {5406 .identifier, .extended_identifier => {
5405 const identifier = slicer.slice(token);5407 const identifier = slicer.slice(token);
5406 const is_param = for (params) |param| {5408 const is_param = for (params) |param| {
5407 if (param.name != null and mem.eql(u8, identifier, param.name.?)) break true;5409 if (param.name != null and mem.eql(u8, identifier, param.name.?)) break true;
...@@ -5422,31 +5424,38 @@ const MacroCtx = struct {...@@ -5422,31 +5424,38 @@ const MacroCtx = struct {
5422};5424};
54235425
5424fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!void {5426fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!void {
5425 var tokenizer = std.c.Tokenizer{5427 var tokenizer: aro.Tokenizer = .{
5426 .buffer = source,5428 .buf = source,
5429 .source = .unused,
5430 .langopts = .{},
5427 };5431 };
5428 while (true) {5432 while (true) {
5429 const tok = tokenizer.next();5433 const tok = tokenizer.next();
5430 switch (tok.id) {5434 switch (tok.id) {
5431 .Nl, .Eof => {5435 .whitespace => continue,
5436 .nl, .eof => {
5432 try tok_list.append(tok);5437 try tok_list.append(tok);
5433 break;5438 break;
5434 },5439 },
5435 .LineComment, .MultiLineComment => continue,
5436 else => {},5440 else => {},
5437 }5441 }
5438 try tok_list.append(tok);5442 try tok_list.append(tok);
5439 }5443 }
5440}5444}
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 {
5443 const begin_loc = macro.getSourceRange_getBegin();5447 const begin_loc = macro.getSourceRange_getBegin();
5444 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);5448 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
54455449
5446 const begin_c = c.source_manager.getCharacterData(begin_loc);5450 const begin_c = c.source_manager.getCharacterData(begin_loc);
5447 const end_c = c.source_manager.getCharacterData(end_loc);5451 const end_c = c.source_manager.getCharacterData(end_loc);
5448 const slice_len = @intFromPtr(end_c) - @intFromPtr(begin_c);5452 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);
5450}5459}
54515460
5452fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {5461fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
...@@ -5471,7 +5480,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5471,7 +5480,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5471 continue;5480 continue;
5472 }5481 }
54735482
5474 const source = getMacroText(unit, c, macro);5483 const source = try getMacroText(unit, c, macro);
54755484
5476 try tokenizeMacro(source, &tok_list);5485 try tokenizeMacro(source, &tok_list);
54775486
...@@ -5485,7 +5494,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5485,7 +5494,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54855494
5486 var macro_fn = false;5495 var macro_fn = false;
5487 switch (macro_ctx.peek().?) {5496 switch (macro_ctx.peek().?) {
5488 .Identifier => {5497 .identifier, .extended_identifier => {
5489 // if it equals itself, ignore. for example, from stdio.h:5498 // if it equals itself, ignore. for example, from stdio.h:
5490 // #define stdin stdin5499 // #define stdin stdin
5491 const tok = macro_ctx.list[1];5500 const tok = macro_ctx.list[1];
...@@ -5494,7 +5503,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5494,7 +5503,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5494 continue;5503 continue;
5495 }5504 }
5496 },5505 },
5497 .Nl, .Eof => {5506 .nl, .eof => {
5498 // this means it is a macro without a value5507 // this means it is a macro without a value
5499 // We define it as an empty string so that it can still be used with ++5508 // We define it as an empty string so that it can still be used with ++
5500 const str_node = try Tag.string_literal.create(c.arena, "\"\"");5509 const str_node = try Tag.string_literal.create(c.arena, "\"\"");
...@@ -5503,7 +5512,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5503,7 +5512,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5503 try c.global_scope.blank_macros.put(name, {});5512 try c.global_scope.blank_macros.put(name, {});
5504 continue;5513 continue;
5505 },5514 },
5506 .LParen => {5515 .l_paren => {
5507 // if the name is immediately followed by a '(' then it is a function5516 // if the name is immediately followed by a '(' then it is a function
5508 macro_fn = macro_ctx.list[0].end == macro_ctx.list[1].start;5517 macro_fn = macro_ctx.list[0].end == macro_ctx.list[1].start;
5509 },5518 },
...@@ -5534,7 +5543,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5534,7 +5543,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
5534 // Check if the macro only uses other blank macros.5543 // Check if the macro only uses other blank macros.
5535 while (true) {5544 while (true) {
5536 switch (m.peek().?) {5545 switch (m.peek().?) {
5537 .Identifier => {5546 .identifier, .extended_identifier => {
5538 const tok = m.list[m.i + 1];5547 const tok = m.list[m.i + 1];
5539 const slice = m.source[tok.start..tok.end];5548 const slice = m.source[tok.start..tok.end];
5540 if (c.global_scope.blank_macros.contains(slice)) {5549 if (c.global_scope.blank_macros.contains(slice)) {
...@@ -5542,7 +5551,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5542,7 +5551,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
5542 continue;5551 continue;
5543 }5552 }
5544 },5553 },
5545 .Eof, .Nl => {5554 .eof, .nl => {
5546 try c.global_scope.blank_macros.put(m.name, {});5555 try c.global_scope.blank_macros.put(m.name, {});
5547 const init_node = try Tag.string_literal.create(c.arena, "\"\"");5556 const init_node = try Tag.string_literal.create(c.arena, "\"\"");
5548 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });5557 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 {...@@ -5556,7 +5565,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
55565565
5557 const init_node = try parseCExpr(c, m, scope);5566 const init_node = try parseCExpr(c, m, scope);
5558 const last = m.next().?;5567 const last = m.next().?;
5559 if (last != .Eof and last != .Nl)5568 if (last != .eof and last != .nl)
5560 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});5569 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
55615570
5562 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });5571 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 {...@@ -5578,14 +5587,16 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5578 defer block_scope.deinit();5587 defer block_scope.deinit();
5579 const scope = &block_scope.base;5588 const scope = &block_scope.base;
55805589
5581 try m.skip(c, .LParen);5590 try m.skip(c, .l_paren);
55825591
5583 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);5592 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
5584 defer fn_params.deinit();5593 defer fn_params.deinit();
55855594
5586 while (true) {5595 while (true) {
5587 if (m.peek().? != .Identifier) break;5596 switch (m.peek().?) {
5588 _ = m.next();5597 .identifier, .extended_identifier => _ = m.next(),
5598 else => break,
5599 }
55895600
5590 const mangled_name = try block_scope.makeMangledName(c, m.slice());5601 const mangled_name = try block_scope.makeMangledName(c, m.slice());
5591 try fn_params.append(.{5602 try fn_params.append(.{
...@@ -5594,11 +5605,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5594,11 +5605,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5594 .type = Tag.@"anytype".init(),5605 .type = Tag.@"anytype".init(),
5595 });5606 });
5596 try block_scope.discardVariable(c, mangled_name);5607 try block_scope.discardVariable(c, mangled_name);
5597 if (m.peek().? != .Comma) break;5608 if (m.peek().? != .comma) break;
5598 _ = m.next();5609 _ = m.next();
5599 }5610 }
56005611
5601 try m.skip(c, .RParen);5612 try m.skip(c, .r_paren);
56025613
5603 if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) {5614 if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) {
5604 .undefined_identifier => |ident| return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}),5615 .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 {...@@ -5607,7 +5618,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
56075618
5608 const expr = try parseCExpr(c, m, scope);5619 const expr = try parseCExpr(c, m, scope);
5609 const last = m.next().?;5620 const last = m.next().?;
5610 if (last != .Eof and last != .Nl)5621 if (last != .eof and last != .nl)
5611 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});5622 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
56125623
5613 const typeof_arg = if (expr.castTag(.block)) |some| blk: {5624 const typeof_arg = if (expr.castTag(.block)) |some| blk: {
...@@ -5644,7 +5655,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5644,7 +5655,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5644 defer block_scope.deinit();5655 defer block_scope.deinit();
56455656
5646 const node = try parseCCondExpr(c, m, &block_scope.base);5657 const node = try parseCCondExpr(c, m, &block_scope.base);
5647 if (m.next().? != .Comma) {5658 if (m.next().? != .comma) {
5648 m.i -= 1;5659 m.i -= 1;
5649 return node;5660 return node;
5650 }5661 }
...@@ -5656,7 +5667,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5656,7 +5667,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5656 try block_scope.statements.append(ignore);5667 try block_scope.statements.append(ignore);
56575668
5658 last = try parseCCondExpr(c, m, &block_scope.base);5669 last = try parseCCondExpr(c, m, &block_scope.base);
5659 if (m.next().? != .Comma) {5670 if (m.next().? != .comma) {
5660 m.i -= 1;5671 m.i -= 1;
5661 break;5672 break;
5662 }5673 }
...@@ -5670,118 +5681,135 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5670,118 +5681,135 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5670 return try block_scope.complete(c);5681 return try block_scope.complete(c);
5671}5682}
56725683
5673fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {5684fn parseCNumLit(ctx: *Context, m: *MacroCtx) ParseError!Node {
5674 var lit_bytes = m.slice();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) {5688 const prefix = aro.Tree.Token.NumberPrefix.fromString(lit_bytes);
5677 .IntegerLiteral => |suffix| {5689 switch (prefix) {
5678 var base: []const u8 = "decimal";5690 .binary => bytes.appendSliceAssumeCapacity("0b"),
5679 if (lit_bytes.len >= 2 and lit_bytes[0] == '0') {5691 .octal => bytes.appendSliceAssumeCapacity("0o"),
5680 switch (lit_bytes[1]) {5692 .hex => bytes.appendSliceAssumeCapacity("0x"),
5681 '0'...'7' => {5693 .decimal => {},
5682 // Octal5694 }
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);
57305695
5731 if (guaranteed_to_fit) {5696 const after_prefix = lit_bytes[prefix.stringLen()..];
5732 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = literal_node });5697 const after_int = for (after_prefix, 0..) |c, i| switch (c) {
5733 } else {5698 '.' => {
5734 return Tag.helpers_promoteIntLiteral.create(c.arena, .{5699 if (i == 0) {
5735 .type = type_node,5700 bytes.appendAssumeCapacity('0');
5736 .value = literal_node,
5737 .base = try Tag.enum_literal.create(c.arena, base),
5738 });
5739 }5701 }
5702 break after_prefix[i..];
5740 },5703 },
5741 .FloatLiteral => |suffix| {5704 'e', 'E' => {
5742 if (suffix != .none) lit_bytes = lit_bytes[0 .. lit_bytes.len - 1];5705 if (prefix != .hex) break after_prefix[i..];
57435706 bytes.appendAssumeCapacity(c);
5744 if (lit_bytes.len >= 2 and std.ascii.eqlIgnoreCase(lit_bytes[0..2], "0x")) {5707 },
5745 if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| {5708 'p', 'P' => break after_prefix[i..],
5746 if (dot_index == 2) {5709 '0'...'9', 'a'...'d', 'A'...'D', 'f', 'F' => {
5747 lit_bytes = try std.fmt.allocPrint(c.arena, "0x0{s}", .{lit_bytes[2..]});5710 if (!prefix.digitAllowed(c)) break after_prefix[i..];
5748 } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isHex(lit_bytes[dot_index + 1])) {5711 bytes.appendAssumeCapacity(c);
5749 // If the literal lacks a digit after the `.`, we need to5712 },
5750 // add one since `0x1.p10` would be invalid syntax in Zig.5713 '\'' => {
5751 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}0{s}", .{5714 bytes.appendAssumeCapacity('_');
5752 lit_bytes[2 .. dot_index + 1],5715 },
5753 lit_bytes[dot_index + 1 ..],5716 else => break after_prefix[i..],
5754 });5717 } else "";
5755 }
5756 }
57575718
5758 if (lit_bytes[1] == 'X') {5719 const after_frac = frac: {
5759 // Hexadecimal with capital X, valid in C but not in Zig5720 if (after_int.len == 0 or after_int[0] != '.') break :frac after_int;
5760 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]});5721 bytes.appendAssumeCapacity('.');
5761 }5722 for (after_int[1..], 1..) |c, i| {
5762 } else if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| {5723 if (c == '\'') {
5763 if (dot_index == 0) {5724 bytes.appendAssumeCapacity('_');
5764 lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes});5725 continue;
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 }
5773 }5726 }
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) {5803 const literal_node = try Tag.integer_literal.create(ctx.arena, bytes.items);
5776 .f => "f32",5804 if (guaranteed_to_fit) {
5777 .none => "f64",5805 return Tag.as.create(ctx.arena, .{ .lhs = type_node, .rhs = literal_node });
5778 .l => "c_longdouble",5806 } else {
5779 else => unreachable,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)),
5780 });5811 });
5781 const rhs = try transCreateNodeNumber(c, lit_bytes, .float);5812 }
5782 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
5783 },
5784 else => unreachable,
5785 }5813 }
5786}5814}
57875815
...@@ -5800,17 +5828,17 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5800,17 +5828,17 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5800 } else return source;5828 } else return source;
5801 var bytes = try ctx.arena.alloc(u8, source.len * 2);5829 var bytes = try ctx.arena.alloc(u8, source.len * 2);
5802 var state: enum {5830 var state: enum {
5803 Start,5831 start,
5804 Escape,5832 escape,
5805 Hex,5833 hex,
5806 Octal,5834 octal,
5807 } = .Start;5835 } = .start;
5808 var i: usize = 0;5836 var i: usize = 0;
5809 var count: u8 = 0;5837 var count: u8 = 0;
5810 var num: u8 = 0;5838 var num: u8 = 0;
5811 for (source) |c| {5839 for (source) |c| {
5812 switch (state) {5840 switch (state) {
5813 .Escape => {5841 .escape => {
5814 switch (c) {5842 switch (c) {
5815 'n', 'r', 't', '\\', '\'', '\"' => {5843 'n', 'r', 't', '\\', '\'', '\"' => {
5816 bytes[i] = c;5844 bytes[i] = c;
...@@ -5818,11 +5846,11 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5818,11 +5846,11 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5818 '0'...'7' => {5846 '0'...'7' => {
5819 count += 1;5847 count += 1;
5820 num += c - '0';5848 num += c - '0';
5821 state = .Octal;5849 state = .octal;
5822 bytes[i] = 'x';5850 bytes[i] = 'x';
5823 },5851 },
5824 'x' => {5852 'x' => {
5825 state = .Hex;5853 state = .hex;
5826 bytes[i] = 'x';5854 bytes[i] = 'x';
5827 },5855 },
5828 'a' => {5856 'a' => {
...@@ -5867,10 +5895,10 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5867,10 +5895,10 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5867 },5895 },
5868 }5896 }
5869 i += 1;5897 i += 1;
5870 if (state == .Escape)5898 if (state == .escape)
5871 state = .Start;5899 state = .start;
5872 },5900 },
5873 .Start => {5901 .start => {
5874 if (c == '\t') {5902 if (c == '\t') {
5875 bytes[i] = '\\';5903 bytes[i] = '\\';
5876 i += 1;5904 i += 1;
...@@ -5879,12 +5907,12 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5879,12 +5907,12 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5879 continue;5907 continue;
5880 }5908 }
5881 if (c == '\\') {5909 if (c == '\\') {
5882 state = .Escape;5910 state = .escape;
5883 }5911 }
5884 bytes[i] = c;5912 bytes[i] = c;
5885 i += 1;5913 i += 1;
5886 },5914 },
5887 .Hex => {5915 .hex => {
5888 switch (c) {5916 switch (c) {
5889 '0'...'9' => {5917 '0'...'9' => {
5890 num = std.math.mul(u8, num, 16) catch {5918 num = std.math.mul(u8, num, 16) catch {
...@@ -5911,15 +5939,15 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5911,15 +5939,15 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5911 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });5939 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
5912 num = 0;5940 num = 0;
5913 if (c == '\\')5941 if (c == '\\')
5914 state = .Escape5942 state = .escape
5915 else5943 else
5916 state = .Start;5944 state = .start;
5917 bytes[i] = c;5945 bytes[i] = c;
5918 i += 1;5946 i += 1;
5919 },5947 },
5920 }5948 }
5921 },5949 },
5922 .Octal => {5950 .octal => {
5923 const accept_digit = switch (c) {5951 const accept_digit = switch (c) {
5924 // The maximum length of a octal literal is 3 digits5952 // The maximum length of a octal literal is 3 digits
5925 '0'...'7' => count < 3,5953 '0'...'7' => count < 3,
...@@ -5938,16 +5966,16 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5938,16 +5966,16 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5938 num = 0;5966 num = 0;
5939 count = 0;5967 count = 0;
5940 if (c == '\\')5968 if (c == '\\')
5941 state = .Escape5969 state = .escape
5942 else5970 else
5943 state = .Start;5971 state = .start;
5944 bytes[i] = c;5972 bytes[i] = c;
5945 i += 1;5973 i += 1;
5946 }5974 }
5947 },5975 },
5948 }5976 }
5949 }5977 }
5950 if (state == .Hex or state == .Octal)5978 if (state == .hex or state == .octal)
5951 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });5979 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
5952 return bytes[0..i];5980 return bytes[0..i];
5953}5981}
...@@ -5972,7 +6000,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N...@@ -5972,7 +6000,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
5972 const tok = m.next().?;6000 const tok = m.next().?;
5973 const slice = m.slice();6001 const slice = m.slice();
5974 switch (tok) {6002 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 => {
5976 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {6009 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
5977 return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m));6010 return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m));
5978 } else {6011 } else {
...@@ -5980,13 +6013,18 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N...@@ -5980,13 +6013,18 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
5980 return Tag.integer_literal.create(c.arena, str);6013 return Tag.integer_literal.create(c.arena, str);
5981 }6014 }
5982 },6015 },
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 => {
5984 return Tag.string_literal.create(c.arena, try escapeUnprintables(c, m));6022 return Tag.string_literal.create(c.arena, try escapeUnprintables(c, m));
5985 },6023 },
5986 .IntegerLiteral, .FloatLiteral => {6024 .pp_num => {
5987 return parseCNumLit(c, m);6025 return parseCNumLit(c, m);
5988 },6026 },
5989 .Identifier => {6027 .identifier, .extended_identifier => {
5990 if (c.global_scope.blank_macros.contains(slice)) {6028 if (c.global_scope.blank_macros.contains(slice)) {
5991 return parseCPrimaryExprInner(c, m, scope);6029 return parseCPrimaryExprInner(c, m, scope);
5992 }6030 }
...@@ -5996,10 +6034,10 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N...@@ -5996,10 +6034,10 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
5996 scope.skipVariableDiscard(identifier.castTag(.identifier).?.data);6034 scope.skipVariableDiscard(identifier.castTag(.identifier).?.data);
5997 return identifier;6035 return identifier;
5998 },6036 },
5999 .LParen => {6037 .l_paren => {
6000 const inner_node = try parseCExpr(c, m, scope);6038 const inner_node = try parseCExpr(c, m, scope);
60016039
6002 try m.skip(c, .RParen);6040 try m.skip(c, .r_paren);
6003 return inner_node;6041 return inner_node;
6004 },6042 },
6005 else => {6043 else => {
...@@ -6022,8 +6060,13 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6022,8 +6060,13 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6022 // after a primary expression.6060 // after a primary expression.
6023 while (true) {6061 while (true) {
6024 switch (m.peek().?) {6062 switch (m.peek().?) {
6025 .StringLiteral => {},6063 .string_literal,
6026 .Identifier => {6064 .string_literal_utf_16,
6065 .string_literal_utf_8,
6066 .string_literal_utf_32,
6067 .string_literal_wide,
6068 => {},
6069 .identifier, .extended_identifier => {
6027 const tok = m.list[m.i + 1];6070 const tok = m.list[m.i + 1];
6028 const slice = m.source[tok.start..tok.end];6071 const slice = m.source[tok.start..tok.end];
6029 if (c.global_scope.blank_macros.contains(slice)) {6072 if (c.global_scope.blank_macros.contains(slice)) {
...@@ -6057,20 +6100,20 @@ fn macroIntToBool(c: *Context, node: Node) !Node {...@@ -6057,20 +6100,20 @@ fn macroIntToBool(c: *Context, node: Node) !Node {
60576100
6058fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6101fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6059 const node = try parseCOrExpr(c, m, scope);6102 const node = try parseCOrExpr(c, m, scope);
6060 if (m.peek().? != .QuestionMark) {6103 if (m.peek().? != .question_mark) {
6061 return node;6104 return node;
6062 }6105 }
6063 _ = m.next();6106 _ = m.next();
60646107
6065 const then_body = try parseCOrExpr(c, m, scope);6108 const then_body = try parseCOrExpr(c, m, scope);
6066 try m.skip(c, .Colon);6109 try m.skip(c, .colon);
6067 const else_body = try parseCCondExpr(c, m, scope);6110 const else_body = try parseCCondExpr(c, m, scope);
6068 return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });6111 return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });
6069}6112}
60706113
6071fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6114fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6072 var node = try parseCAndExpr(c, m, scope);6115 var node = try parseCAndExpr(c, m, scope);
6073 while (m.next().? == .PipePipe) {6116 while (m.next().? == .pipe_pipe) {
6074 const lhs = try macroIntToBool(c, node);6117 const lhs = try macroIntToBool(c, node);
6075 const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope));6118 const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope));
6076 node = try Tag.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs });6119 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 {...@@ -6081,7 +6124,7 @@ fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60816124
6082fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6125fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6083 var node = try parseCBitOrExpr(c, m, scope);6126 var node = try parseCBitOrExpr(c, m, scope);
6084 while (m.next().? == .AmpersandAmpersand) {6127 while (m.next().? == .ampersand_ampersand) {
6085 const lhs = try macroIntToBool(c, node);6128 const lhs = try macroIntToBool(c, node);
6086 const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope));6129 const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope));
6087 node = try Tag.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs });6130 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 {...@@ -6092,7 +6135,7 @@ fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60926135
6093fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6136fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6094 var node = try parseCBitXorExpr(c, m, scope);6137 var node = try parseCBitXorExpr(c, m, scope);
6095 while (m.next().? == .Pipe) {6138 while (m.next().? == .pipe) {
6096 const lhs = try macroIntFromBool(c, node);6139 const lhs = try macroIntFromBool(c, node);
6097 const rhs = try macroIntFromBool(c, try parseCBitXorExpr(c, m, scope));6140 const rhs = try macroIntFromBool(c, try parseCBitXorExpr(c, m, scope));
6098 node = try Tag.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6141 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 {...@@ -6103,7 +6146,7 @@ fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61036146
6104fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6147fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6105 var node = try parseCBitAndExpr(c, m, scope);6148 var node = try parseCBitAndExpr(c, m, scope);
6106 while (m.next().? == .Caret) {6149 while (m.next().? == .caret) {
6107 const lhs = try macroIntFromBool(c, node);6150 const lhs = try macroIntFromBool(c, node);
6108 const rhs = try macroIntFromBool(c, try parseCBitAndExpr(c, m, scope));6151 const rhs = try macroIntFromBool(c, try parseCBitAndExpr(c, m, scope));
6109 node = try Tag.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6152 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 {...@@ -6114,7 +6157,7 @@ fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61146157
6115fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6158fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6116 var node = try parseCEqExpr(c, m, scope);6159 var node = try parseCEqExpr(c, m, scope);
6117 while (m.next().? == .Ampersand) {6160 while (m.next().? == .ampersand) {
6118 const lhs = try macroIntFromBool(c, node);6161 const lhs = try macroIntFromBool(c, node);
6119 const rhs = try macroIntFromBool(c, try parseCEqExpr(c, m, scope));6162 const rhs = try macroIntFromBool(c, try parseCEqExpr(c, m, scope));
6120 node = try Tag.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6163 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 {...@@ -6127,13 +6170,13 @@ fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6127 var node = try parseCRelExpr(c, m, scope);6170 var node = try parseCRelExpr(c, m, scope);
6128 while (true) {6171 while (true) {
6129 switch (m.peek().?) {6172 switch (m.peek().?) {
6130 .BangEqual => {6173 .bang_equal => {
6131 _ = m.next();6174 _ = m.next();
6132 const lhs = try macroIntFromBool(c, node);6175 const lhs = try macroIntFromBool(c, node);
6133 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));6176 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));
6134 node = try Tag.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6177 node = try Tag.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6135 },6178 },
6136 .EqualEqual => {6179 .equal_equal => {
6137 _ = m.next();6180 _ = m.next();
6138 const lhs = try macroIntFromBool(c, node);6181 const lhs = try macroIntFromBool(c, node);
6139 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));6182 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));
...@@ -6148,25 +6191,25 @@ fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6148,25 +6191,25 @@ fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6148 var node = try parseCShiftExpr(c, m, scope);6191 var node = try parseCShiftExpr(c, m, scope);
6149 while (true) {6192 while (true) {
6150 switch (m.peek().?) {6193 switch (m.peek().?) {
6151 .AngleBracketRight => {6194 .angle_bracket_right => {
6152 _ = m.next();6195 _ = m.next();
6153 const lhs = try macroIntFromBool(c, node);6196 const lhs = try macroIntFromBool(c, node);
6154 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));6197 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
6155 node = try Tag.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6198 node = try Tag.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6156 },6199 },
6157 .AngleBracketRightEqual => {6200 .angle_bracket_right_equal => {
6158 _ = m.next();6201 _ = m.next();
6159 const lhs = try macroIntFromBool(c, node);6202 const lhs = try macroIntFromBool(c, node);
6160 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));6203 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
6161 node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6204 node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6162 },6205 },
6163 .AngleBracketLeft => {6206 .angle_bracket_left => {
6164 _ = m.next();6207 _ = m.next();
6165 const lhs = try macroIntFromBool(c, node);6208 const lhs = try macroIntFromBool(c, node);
6166 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));6209 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
6167 node = try Tag.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6210 node = try Tag.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6168 },6211 },
6169 .AngleBracketLeftEqual => {6212 .angle_bracket_left_equal => {
6170 _ = m.next();6213 _ = m.next();
6171 const lhs = try macroIntFromBool(c, node);6214 const lhs = try macroIntFromBool(c, node);
6172 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));6215 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
...@@ -6181,13 +6224,13 @@ fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6181,13 +6224,13 @@ fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6181 var node = try parseCAddSubExpr(c, m, scope);6224 var node = try parseCAddSubExpr(c, m, scope);
6182 while (true) {6225 while (true) {
6183 switch (m.peek().?) {6226 switch (m.peek().?) {
6184 .AngleBracketAngleBracketLeft => {6227 .angle_bracket_angle_bracket_left => {
6185 _ = m.next();6228 _ = m.next();
6186 const lhs = try macroIntFromBool(c, node);6229 const lhs = try macroIntFromBool(c, node);
6187 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));6230 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));
6188 node = try Tag.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6231 node = try Tag.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6189 },6232 },
6190 .AngleBracketAngleBracketRight => {6233 .angle_bracket_angle_bracket_right => {
6191 _ = m.next();6234 _ = m.next();
6192 const lhs = try macroIntFromBool(c, node);6235 const lhs = try macroIntFromBool(c, node);
6193 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));6236 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));
...@@ -6202,13 +6245,13 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6202,13 +6245,13 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6202 var node = try parseCMulExpr(c, m, scope);6245 var node = try parseCMulExpr(c, m, scope);
6203 while (true) {6246 while (true) {
6204 switch (m.peek().?) {6247 switch (m.peek().?) {
6205 .Plus => {6248 .plus => {
6206 _ = m.next();6249 _ = m.next();
6207 const lhs = try macroIntFromBool(c, node);6250 const lhs = try macroIntFromBool(c, node);
6208 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));6251 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));
6209 node = try Tag.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6252 node = try Tag.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6210 },6253 },
6211 .Minus => {6254 .minus => {
6212 _ = m.next();6255 _ = m.next();
6213 const lhs = try macroIntFromBool(c, node);6256 const lhs = try macroIntFromBool(c, node);
6214 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));6257 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));
...@@ -6223,17 +6266,17 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6223,17 +6266,17 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6223 var node = try parseCCastExpr(c, m, scope);6266 var node = try parseCCastExpr(c, m, scope);
6224 while (true) {6267 while (true) {
6225 switch (m.next().?) {6268 switch (m.next().?) {
6226 .Asterisk => {6269 .asterisk => {
6227 const lhs = try macroIntFromBool(c, node);6270 const lhs = try macroIntFromBool(c, node);
6228 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));6271 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
6229 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6272 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6230 },6273 },
6231 .Slash => {6274 .slash => {
6232 const lhs = try macroIntFromBool(c, node);6275 const lhs = try macroIntFromBool(c, node);
6233 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));6276 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
6234 node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .div, .lhs = lhs, .rhs = rhs });6277 node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .div, .lhs = lhs, .rhs = rhs });
6235 },6278 },
6236 .Percent => {6279 .percent => {
6237 const lhs = try macroIntFromBool(c, node);6280 const lhs = try macroIntFromBool(c, node);
6238 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));6281 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
6239 node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .rem, .lhs = lhs, .rhs = rhs });6282 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 {...@@ -6248,17 +6291,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62486291
6249fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6292fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6250 switch (m.next().?) {6293 switch (m.next().?) {
6251 .LParen => {6294 .l_paren => {
6252 if (try parseCTypeName(c, m, scope, true)) |type_name| {6295 if (try parseCTypeName(c, m, scope, true)) |type_name| {
6253 while (true) {6296 while (true) {
6254 const next_token = m.next().?;6297 const next_token = m.next().?;
6255 switch (next_token) {6298 switch (next_token) {
6256 .RParen => break,6299 .r_paren => break,
6257 else => |next_tag| {6300 else => |next_tag| {
6258 // Skip trailing blank defined before the RParen.6301 // 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()))
6260 continue;6304 continue;
6261 }6305
6262 try m.fail(6306 try m.fail(
6263 c,6307 c,
6264 "unable to translate C expr: expected ')' instead got '{s}'",6308 "unable to translate C expr: expected ')' instead got '{s}'",
...@@ -6268,7 +6312,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6268,7 +6312,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6268 },6312 },
6269 }6313 }
6270 }6314 }
6271 if (m.peek().? == .LBrace) {6315 if (m.peek().? == .l_brace) {
6272 // initializer list6316 // initializer list
6273 return parseCPostfixExpr(c, m, scope, type_name);6317 return parseCPostfixExpr(c, m, scope, type_name);
6274 }6318 }
...@@ -6294,7 +6338,7 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa...@@ -6294,7 +6338,7 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa
6294fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node {6338fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node {
6295 const tok = m.next().?;6339 const tok = m.next().?;
6296 switch (tok) {6340 switch (tok) {
6297 .Identifier => {6341 .identifier, .extended_identifier => {
6298 if (c.global_scope.blank_macros.contains(m.slice())) {6342 if (c.global_scope.blank_macros.contains(m.slice())) {
6299 return try parseCSpecifierQualifierList(c, m, scope, allow_fail);6343 return try parseCSpecifierQualifierList(c, m, scope, allow_fail);
6300 }6344 }
...@@ -6304,25 +6348,25 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_...@@ -6304,25 +6348,25 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_
6304 return try Tag.identifier.create(c.arena, mangled_name);6348 return try Tag.identifier.create(c.arena, mangled_name);
6305 }6349 }
6306 },6350 },
6307 .Keyword_void => return try Tag.type.create(c.arena, "anyopaque"),6351 .keyword_void => return try Tag.type.create(c.arena, "anyopaque"),
6308 .Keyword_bool => return try Tag.type.create(c.arena, "bool"),6352 .keyword_bool => return try Tag.type.create(c.arena, "bool"),
6309 .Keyword_char,6353 .keyword_char,
6310 .Keyword_int,6354 .keyword_int,
6311 .Keyword_short,6355 .keyword_short,
6312 .Keyword_long,6356 .keyword_long,
6313 .Keyword_float,6357 .keyword_float,
6314 .Keyword_double,6358 .keyword_double,
6315 .Keyword_signed,6359 .keyword_signed,
6316 .Keyword_unsigned,6360 .keyword_unsigned,
6317 .Keyword_complex,6361 .keyword_complex,
6318 => {6362 => {
6319 m.i -= 1;6363 m.i -= 1;
6320 return try parseCNumericType(c, m);6364 return try parseCNumericType(c, m);
6321 },6365 },
6322 .Keyword_enum, .Keyword_struct, .Keyword_union => {6366 .keyword_enum, .keyword_struct, .keyword_union => {
6323 // struct Foo will be declared as struct_Foo by transRecordDecl6367 // struct Foo will be declared as struct_Foo by transRecordDecl
6324 const slice = m.slice();6368 const slice = m.slice();
6325 try m.skip(c, .Identifier);6369 try m.skip(c, .identifier);
63266370
6327 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });6371 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
6328 return try Tag.identifier.create(c.arena, name);6372 return try Tag.identifier.create(c.arena, name);
...@@ -6364,15 +6408,15 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {...@@ -6364,15 +6408,15 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {
6364 var i: u8 = 0;6408 var i: u8 = 0;
6365 while (i < math.maxInt(u8)) : (i += 1) {6409 while (i < math.maxInt(u8)) : (i += 1) {
6366 switch (m.next().?) {6410 switch (m.next().?) {
6367 .Keyword_double => kw.double += 1,6411 .keyword_double => kw.double += 1,
6368 .Keyword_long => kw.long += 1,6412 .keyword_long => kw.long += 1,
6369 .Keyword_int => kw.int += 1,6413 .keyword_int => kw.int += 1,
6370 .Keyword_float => kw.float += 1,6414 .keyword_float => kw.float += 1,
6371 .Keyword_short => kw.short += 1,6415 .keyword_short => kw.short += 1,
6372 .Keyword_char => kw.char += 1,6416 .keyword_char => kw.char += 1,
6373 .Keyword_unsigned => kw.unsigned += 1,6417 .keyword_unsigned => kw.unsigned += 1,
6374 .Keyword_signed => kw.signed += 1,6418 .keyword_signed => kw.signed += 1,
6375 .Keyword_complex => kw.complex += 1,6419 .keyword_complex => kw.complex += 1,
6376 else => {6420 else => {
6377 m.i -= 1;6421 m.i -= 1;
6378 break;6422 break;
...@@ -6442,11 +6486,11 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {...@@ -6442,11 +6486,11 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {
64426486
6443fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, node: Node) ParseError!Node {6487fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, node: Node) ParseError!Node {
6444 switch (m.next().?) {6488 switch (m.next().?) {
6445 .Asterisk => {6489 .asterisk => {
6446 // last token of `node`6490 // last token of `node`
6447 const prev_id = m.list[m.i - 1].id;6491 const prev_id = m.list[m.i - 1].id;
64486492
6449 if (prev_id == .Keyword_void) {6493 if (prev_id == .keyword_void) {
6450 const ptr = try Tag.single_pointer.create(c.arena, .{6494 const ptr = try Tag.single_pointer.create(c.arena, .{
6451 .is_const = false,6495 .is_const = false,
6452 .is_volatile = false,6496 .is_volatile = false,
...@@ -6472,28 +6516,28 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6472,28 +6516,28 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6472 var node = type_name orelse try parseCPrimaryExpr(c, m, scope);6516 var node = type_name orelse try parseCPrimaryExpr(c, m, scope);
6473 while (true) {6517 while (true) {
6474 switch (m.next().?) {6518 switch (m.next().?) {
6475 .Period => {6519 .period => {
6476 try m.skip(c, .Identifier);6520 try m.skip(c, .identifier);
64776521
6478 node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });6522 node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });
6479 },6523 },
6480 .Arrow => {6524 .arrow => {
6481 try m.skip(c, .Identifier);6525 try m.skip(c, .identifier);
64826526
6483 const deref = try Tag.deref.create(c.arena, node);6527 const deref = try Tag.deref.create(c.arena, node);
6484 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });6528 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });
6485 },6529 },
6486 .LBracket => {6530 .l_bracket => {
6487 const index_val = try macroIntFromBool(c, try parseCExpr(c, m, scope));6531 const index_val = try macroIntFromBool(c, try parseCExpr(c, m, scope));
6488 const index = try Tag.as.create(c.arena, .{6532 const index = try Tag.as.create(c.arena, .{
6489 .lhs = try Tag.type.create(c.arena, "usize"),6533 .lhs = try Tag.type.create(c.arena, "usize"),
6490 .rhs = try Tag.int_cast.create(c.arena, index_val),6534 .rhs = try Tag.int_cast.create(c.arena, index_val),
6491 });6535 });
6492 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });6536 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);
6494 },6538 },
6495 .LParen => {6539 .l_paren => {
6496 if (m.peek().? == .RParen) {6540 if (m.peek().? == .r_paren) {
6497 m.i += 1;6541 m.i += 1;
6498 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &[0]Node{} });6542 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &[0]Node{} });
6499 } else {6543 } else {
...@@ -6504,8 +6548,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6504,8 +6548,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6504 try args.append(arg);6548 try args.append(arg);
6505 const next_id = m.next().?;6549 const next_id = m.next().?;
6506 switch (next_id) {6550 switch (next_id) {
6507 .Comma => {},6551 .comma => {},
6508 .RParen => break,6552 .r_paren => break,
6509 else => {6553 else => {
6510 try m.fail(c, "unable to translate C expr: expected ',' or ')' instead got '{s}'", .{next_id.symbol()});6554 try m.fail(c, "unable to translate C expr: expected ',' or ')' instead got '{s}'", .{next_id.symbol()});
6511 return error.ParseError;6555 return error.ParseError;
...@@ -6515,24 +6559,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6515,24 +6559,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6515 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });6559 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });
6516 }6560 }
6517 },6561 },
6518 .LBrace => {6562 .l_brace => {
6519 // Check for designated field initializers6563 // Check for designated field initializers
6520 if (m.peek().? == .Period) {6564 if (m.peek().? == .period) {
6521 var init_vals = std.ArrayList(ast.Payload.ContainerInitDot.Initializer).init(c.gpa);6565 var init_vals = std.ArrayList(ast.Payload.ContainerInitDot.Initializer).init(c.gpa);
6522 defer init_vals.deinit();6566 defer init_vals.deinit();
65236567
6524 while (true) {6568 while (true) {
6525 try m.skip(c, .Period);6569 try m.skip(c, .period);
6526 try m.skip(c, .Identifier);6570 try m.skip(c, .identifier);
6527 const name = m.slice();6571 const name = m.slice();
6528 try m.skip(c, .Equal);6572 try m.skip(c, .equal);
65296573
6530 const val = try parseCCondExpr(c, m, scope);6574 const val = try parseCCondExpr(c, m, scope);
6531 try init_vals.append(.{ .name = name, .value = val });6575 try init_vals.append(.{ .name = name, .value = val });
6532 const next_id = m.next().?;6576 const next_id = m.next().?;
6533 switch (next_id) {6577 switch (next_id) {
6534 .Comma => {},6578 .comma => {},
6535 .RBrace => break,6579 .r_brace => break,
6536 else => {6580 else => {
6537 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});6581 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});
6538 return error.ParseError;6582 return error.ParseError;
...@@ -6552,8 +6596,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6552,8 +6596,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6552 try init_vals.append(val);6596 try init_vals.append(val);
6553 const next_id = m.next().?;6597 const next_id = m.next().?;
6554 switch (next_id) {6598 switch (next_id) {
6555 .Comma => {},6599 .comma => {},
6556 .RBrace => break,6600 .r_brace => break,
6557 else => {6601 else => {
6558 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});6602 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});
6559 return error.ParseError;6603 return error.ParseError;
...@@ -6563,7 +6607,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6563,7 +6607,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6563 const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items));6607 const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items));
6564 node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node });6608 node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node });
6565 },6609 },
6566 .PlusPlus, .MinusMinus => {6610 .plus_plus, .minus_minus => {
6567 try m.fail(c, "TODO postfix inc/dec expr", .{});6611 try m.fail(c, "TODO postfix inc/dec expr", .{});
6568 return error.ParseError;6612 return error.ParseError;
6569 },6613 },
...@@ -6577,47 +6621,47 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6577,47 +6621,47 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65776621
6578fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6622fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6579 switch (m.next().?) {6623 switch (m.next().?) {
6580 .Bang => {6624 .bang => {
6581 const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));6625 const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));
6582 return Tag.not.create(c.arena, operand);6626 return Tag.not.create(c.arena, operand);
6583 },6627 },
6584 .Minus => {6628 .minus => {
6585 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));6629 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
6586 return Tag.negate.create(c.arena, operand);6630 return Tag.negate.create(c.arena, operand);
6587 },6631 },
6588 .Plus => return try parseCCastExpr(c, m, scope),6632 .plus => return try parseCCastExpr(c, m, scope),
6589 .Tilde => {6633 .tilde => {
6590 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));6634 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
6591 return Tag.bit_not.create(c.arena, operand);6635 return Tag.bit_not.create(c.arena, operand);
6592 },6636 },
6593 .Asterisk => {6637 .asterisk => {
6594 const operand = try parseCCastExpr(c, m, scope);6638 const operand = try parseCCastExpr(c, m, scope);
6595 return Tag.deref.create(c.arena, operand);6639 return Tag.deref.create(c.arena, operand);
6596 },6640 },
6597 .Ampersand => {6641 .ampersand => {
6598 const operand = try parseCCastExpr(c, m, scope);6642 const operand = try parseCCastExpr(c, m, scope);
6599 return Tag.address_of.create(c.arena, operand);6643 return Tag.address_of.create(c.arena, operand);
6600 },6644 },
6601 .Keyword_sizeof => {6645 .keyword_sizeof => {
6602 const operand = if (m.peek().? == .LParen) blk: {6646 const operand = if (m.peek().? == .l_paren) blk: {
6603 _ = m.next();6647 _ = m.next();
6604 const inner = (try parseCTypeName(c, m, scope, false)).?;6648 const inner = (try parseCTypeName(c, m, scope, false)).?;
6605 try m.skip(c, .RParen);6649 try m.skip(c, .r_paren);
6606 break :blk inner;6650 break :blk inner;
6607 } else try parseCUnaryExpr(c, m, scope);6651 } else try parseCUnaryExpr(c, m, scope);
66086652
6609 return Tag.helpers_sizeof.create(c.arena, operand);6653 return Tag.helpers_sizeof.create(c.arena, operand);
6610 },6654 },
6611 .Keyword_alignof => {6655 .keyword_alignof => {
6612 // TODO this won't work if using <stdalign.h>'s6656 // TODO this won't work if using <stdalign.h>'s
6613 // #define alignof _Alignof6657 // #define alignof _Alignof
6614 try m.skip(c, .LParen);6658 try m.skip(c, .l_paren);
6615 const operand = (try parseCTypeName(c, m, scope, false)).?;6659 const operand = (try parseCTypeName(c, m, scope, false)).?;
6616 try m.skip(c, .RParen);6660 try m.skip(c, .r_paren);
66176661
6618 return Tag.alignof.create(c.arena, operand);6662 return Tag.alignof.create(c.arena, operand);
6619 },6663 },
6620 .PlusPlus, .MinusMinus => {6664 .plus_plus, .minus_minus => {
6621 try m.fail(c, "TODO unary inc/dec expr", .{});6665 try m.fail(c, "TODO unary inc/dec expr", .{});
6622 return error.ParseError;6666 return error.ParseError;
6623 },6667 },
test/translate_c.zig+7-7
...@@ -424,7 +424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -424,7 +424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
424 \\ });424 \\ });
425 \\}425 \\}
426 ,426 ,
427 \\pub const B = A(@as(f32, 0.0));427 \\pub const B = A(@as(f32, 0));
428 });428 });
429429
430 cases.add("complex switch",430 cases.add("complex switch",
...@@ -633,7 +633,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -633,7 +633,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
633 cases.add("#define hex literal with capital X",633 cases.add("#define hex literal with capital X",
634 \\#define VAL 0XF00D634 \\#define VAL 0XF00D
635 , &[_][]const u8{635 , &[_][]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);
637 });637 });
638638
639 cases.add("anonymous struct & unions",639 cases.add("anonymous struct & unions",
...@@ -1243,12 +1243,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1243,12 +1243,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1243 \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l;1243 \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l;
1244 , &([_][]const u8{1244 , &([_][]const u8{
1245 "pub const foo = @as(f32, 3.14);",1245 "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);",
1247 "pub const FOO = @as(f64, 0.12345);",1247 "pub const FOO = @as(f64, 0.12345);",
1248 "pub const BAR = @as(f64, 0.12345);",1248 "pub const BAR = @as(f64, 0.12345);",
1249 "pub const baz = @as(f64, 1e1);",1249 "pub const baz = @as(f64, 1e1);",
1250 "pub const BAZ = @as(f32, 42e-3);",1250 "pub const BAZ = @as(f32, 42e-3);",
1251 "pub const foobar = -@as(c_longdouble, 73.0);",1251 "pub const foobar = -@as(c_longdouble, 73);",
1252 "pub export const my_float: f32 = 1.0;",1252 "pub export const my_float: f32 = 1.0;",
1253 "pub export const my_double: f64 = 1.0;",1253 "pub export const my_double: f64 = 1.0;",
1254 "pub export const my_longdouble: c_longdouble = 1.0;",1254 "pub export const my_longdouble: c_longdouble = 1.0;",
...@@ -1272,7 +1272,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1272,7 +1272,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1272 "pub const BAR = -@as(f32, 0x8F.BP5);",1272 "pub const BAR = -@as(f32, 0x8F.BP5);",
1273 "pub const FOOBAR = @as(f64, 0x0P+0);",1273 "pub const FOOBAR = @as(f64, 0x0P+0);",
1274 "pub const BAZ = -@as(f64, 0x0.0a5dp+12);",1274 "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);",
1276 });1276 });
12771277
1278 cases.add("comments",1278 cases.add("comments",
...@@ -3730,7 +3730,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3730,7 +3730,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3730 , &[_][]const u8{3730 , &[_][]const u8{
3731 \\pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0));3731 \\pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0));
3732 ,3732 ,
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));
3734 });3734 });
37353735
3736 if (builtin.abi == .msvc) {3736 if (builtin.abi == .msvc) {
...@@ -3812,7 +3812,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3812,7 +3812,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3812 \\pub const MAY_NEED_PROMOTION_1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 10241024, .decimal);3812 \\pub const MAY_NEED_PROMOTION_1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 10241024, .decimal);
3813 \\pub const MAY_NEED_PROMOTION_2 = @import("std").zig.c_translation.promoteIntLiteral(c_long, 307230723072, .decimal);3813 \\pub const MAY_NEED_PROMOTION_2 = @import("std").zig.c_translation.promoteIntLiteral(c_long, 307230723072, .decimal);
3814 \\pub const MAY_NEED_PROMOTION_3 = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 819281928192, .decimal);3814 \\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);
3816 \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal);3816 \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal);
3817 });3817 });
38183818