authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-26 12:06:08-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-26 12:06:08-04:00
log1f96a866769423e363f1c48654c0f51ecf75db58
tree504b4913f00bd6a32f097ea6061d5fa211d2c940
parent284ab109c4b83f7bb9a832f284f706e641b002fd
parentc029f4bfc47b5d6d825f7ae7a3f224e9e9d6ce0b

Merge remote-tracking branch 'origin/master' into llvm7


134 files changed, 8980 insertions(+), 6179 deletions(-)

CMakeLists.txt+1-1
...@@ -196,7 +196,7 @@ else()...@@ -196,7 +196,7 @@ else()
196 if(MSVC)196 if(MSVC)
197 set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -D_CRT_SECURE_NO_WARNINGS /w")197 set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -D_CRT_SECURE_NO_WARNINGS /w")
198 else()198 else()
199 set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment")199 set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment -Wno-class-memaccess -Wno-unknown-warning-option")
200 endif()200 endif()
201 set_target_properties(embedded_lld_lib PROPERTIES201 set_target_properties(embedded_lld_lib PROPERTIES
202 COMPILE_FLAGS ${ZIG_LLD_COMPILE_FLAGS}202 COMPILE_FLAGS ${ZIG_LLD_COMPILE_FLAGS}
README.md+7-4
...@@ -1,9 +1,9 @@...@@ -1,9 +1,9 @@
1![ZIG](http://ziglang.org/zig-logo.svg)1![ZIG](https://ziglang.org/zig-logo.svg)
22
3A programming language designed for robustness, optimality, and3A programming language designed for robustness, optimality, and
4clarity.4clarity.
55
6[ziglang.org](http://ziglang.org)6[ziglang.org](https://ziglang.org)
77
8## Feature Highlights8## Feature Highlights
99
...@@ -114,7 +114,7 @@ libc. Create demo games using Zig....@@ -114,7 +114,7 @@ libc. Create demo games using Zig.
114114
115## Building115## Building
116116
117[![Build Status](https://travis-ci.org/zig-lang/zig.svg?branch=master)](https://travis-ci.org/zig-lang/zig)117[![Build Status](https://travis-ci.org/ziglang/zig.svg?branch=master)](https://travis-ci.org/ziglang/zig)
118[![Build status](https://ci.appveyor.com/api/projects/status/4t80mk2dmucrc38i/branch/master?svg=true)](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master)118[![Build status](https://ci.appveyor.com/api/projects/status/4t80mk2dmucrc38i/branch/master?svg=true)](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master)
119119
120### Stage 1: Build Zig from C++ Source Code120### Stage 1: Build Zig from C++ Source Code
...@@ -161,7 +161,7 @@ bin/zig build --build-file ../build.zig test...@@ -161,7 +161,7 @@ bin/zig build --build-file ../build.zig test
161161
162##### Windows162##### Windows
163163
164See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows164See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows
165165
166### Stage 2: Build Self-Hosted Zig from Zig Source Code166### Stage 2: Build Self-Hosted Zig from Zig Source Code
167167
...@@ -182,6 +182,9 @@ binary....@@ -182,6 +182,9 @@ binary.
182182
183This is the actual compiler binary that we will install to the system.183This is the actual compiler binary that we will install to the system.
184184
185*Note: Stage 2 compiler is not yet able to build Stage 3. Building Stage 3 is
186not yet supported.*
187
185#### Debug / Development Build188#### Debug / Development Build
186189
187```190```
build.zig+34-25
...@@ -16,7 +16,7 @@ pub fn build(b: &Builder) !void {...@@ -16,7 +16,7 @@ pub fn build(b: &Builder) !void {
16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
1717
18 const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);18 const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);
19 var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8 {19 var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
20 docgen_exe.getOutputPath(),20 docgen_exe.getOutputPath(),
21 rel_zig_exe,21 rel_zig_exe,
22 "doc/langref.html.in",22 "doc/langref.html.in",
...@@ -30,7 +30,10 @@ pub fn build(b: &Builder) !void {...@@ -30,7 +30,10 @@ pub fn build(b: &Builder) !void {
30 const test_step = b.step("test", "Run all the tests");30 const test_step = b.step("test", "Run all the tests");
3131
32 // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library32 // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
33 const build_info = try b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});33 const build_info = try b.exec([][]const u8{
34 b.zig_exe,
35 "BUILD_INFO",
36 });
34 var index: usize = 0;37 var index: usize = 0;
35 const cmake_binary_dir = nextValue(&index, build_info);38 const cmake_binary_dir = nextValue(&index, build_info);
36 const cxx_compiler = nextValue(&index, build_info);39 const cxx_compiler = nextValue(&index, build_info);
...@@ -67,7 +70,10 @@ pub fn build(b: &Builder) !void {...@@ -67,7 +70,10 @@ pub fn build(b: &Builder) !void {
67 dependOnLib(exe, llvm);70 dependOnLib(exe, llvm);
6871
69 if (exe.target.getOs() == builtin.Os.linux) {72 if (exe.target.getOs() == builtin.Os.linux) {
70 const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});73 const libstdcxx_path_padded = try b.exec([][]const u8{
74 cxx_compiler,
75 "-print-file-name=libstdc++.a",
76 });
71 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();77 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
72 if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {78 if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {
73 warn(79 warn(
...@@ -111,17 +117,11 @@ pub fn build(b: &Builder) !void {...@@ -111,17 +117,11 @@ pub fn build(b: &Builder) !void {
111117
112 test_step.dependOn(docs_step);118 test_step.dependOn(docs_step);
113119
114 test_step.dependOn(tests.addPkgTests(b, test_filter,120 test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", with_lldb));
115 "test/behavior.zig", "behavior", "Run the behavior tests",
116 with_lldb));
117121
118 test_step.dependOn(tests.addPkgTests(b, test_filter,122 test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", with_lldb));
119 "std/index.zig", "std", "Run the standard library tests",
120 with_lldb));
121123
122 test_step.dependOn(tests.addPkgTests(b, test_filter,124 test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests", with_lldb));
123 "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests",
124 with_lldb));
125125
126 test_step.dependOn(tests.addCompareOutputTests(b, test_filter));126 test_step.dependOn(tests.addCompareOutputTests(b, test_filter));
127 test_step.dependOn(tests.addBuildExampleTests(b, test_filter));127 test_step.dependOn(tests.addBuildExampleTests(b, test_filter));
...@@ -149,8 +149,7 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) vo...@@ -149,8 +149,7 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) vo
149149
150fn addCppLib(b: &Builder, lib_exe_obj: &std.build.LibExeObjStep, cmake_binary_dir: []const u8, lib_name: []const u8) void {150fn addCppLib(b: &Builder, lib_exe_obj: &std.build.LibExeObjStep, cmake_binary_dir: []const u8, lib_name: []const u8) void {
151 const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";151 const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";
152 lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp",152 lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);
153 b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);
154}153}
155154
156const LibraryDep = struct {155const LibraryDep = struct {
...@@ -161,11 +160,21 @@ const LibraryDep = struct {...@@ -161,11 +160,21 @@ const LibraryDep = struct {
161};160};
162161
163fn findLLVM(b: &Builder, llvm_config_exe: []const u8) !LibraryDep {162fn findLLVM(b: &Builder, llvm_config_exe: []const u8) !LibraryDep {
164 const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});163 const libs_output = try b.exec([][]const u8{
165 const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});164 llvm_config_exe,
166 const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});165 "--libs",
166 "--system-libs",
167 });
168 const includes_output = try b.exec([][]const u8{
169 llvm_config_exe,
170 "--includedir",
171 });
172 const libdir_output = try b.exec([][]const u8{
173 llvm_config_exe,
174 "--libdir",
175 });
167176
168 var result = LibraryDep {177 var result = LibraryDep{
169 .libs = ArrayList([]const u8).init(b.allocator),178 .libs = ArrayList([]const u8).init(b.allocator),
170 .system_libs = ArrayList([]const u8).init(b.allocator),179 .system_libs = ArrayList([]const u8).init(b.allocator),
171 .includes = ArrayList([]const u8).init(b.allocator),180 .includes = ArrayList([]const u8).init(b.allocator),
...@@ -227,17 +236,17 @@ pub fn installCHeaders(b: &Builder, c_header_files: []const u8) void {...@@ -227,17 +236,17 @@ pub fn installCHeaders(b: &Builder, c_header_files: []const u8) void {
227}236}
228237
229fn nextValue(index: &usize, build_info: []const u8) []const u8 {238fn nextValue(index: &usize, build_info: []const u8) []const u8 {
230 const start = *index;239 const start = index.*;
231 while (true) : (*index += 1) {240 while (true) : (index.* += 1) {
232 switch (build_info[*index]) {241 switch (build_info[index.*]) {
233 '\n' => {242 '\n' => {
234 const result = build_info[start..*index];243 const result = build_info[start..index.*];
235 *index += 1;244 index.* += 1;
236 return result;245 return result;
237 },246 },
238 '\r' => {247 '\r' => {
239 const result = build_info[start..*index];248 const result = build_info[start..index.*];
240 *index += 2;249 index.* += 2;
241 return result;250 return result;
242 },251 },
243 else => continue,252 else => continue,
doc/langref.html.in+133-40
...@@ -96,7 +96,7 @@...@@ -96,7 +96,7 @@
96 </p>96 </p>
97 <p>97 <p>
98 If you search for something specific in this documentation and do not find it,98 If you search for something specific in this documentation and do not find it,
99 please <a href="https://github.com/zig-lang/www.ziglang.org/issues/new?title=I%20searched%20for%20___%20in%20the%20docs%20and%20didn%27t%20find%20it">file an issue</a> or <a href="https://webchat.freenode.net/?channels=%23zig">say something on IRC</a>.99 please <a href="https://github.com/ziglang/www.ziglang.org/issues/new?title=I%20searched%20for%20___%20in%20the%20docs%20and%20didn%27t%20find%20it">file an issue</a> or <a href="https://webchat.freenode.net/?channels=%23zig">say something on IRC</a>.
100 </p>100 </p>
101 <p>101 <p>
102 The code samples in this document are compiled and tested as part of the main test suite of Zig.102 The code samples in this document are compiled and tested as part of the main test suite of Zig.
...@@ -1232,7 +1232,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>...@@ -1232,7 +1232,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>
1232 </td>1232 </td>
1233 </tr>1233 </tr>
1234 <tr>1234 <tr>
1235 <td><pre><code class="zig">*a<code></pre></td>1235 <td><pre><code class="zig">a.*<code></pre></td>
1236 <td>1236 <td>
1237 <ul>1237 <ul>
1238 <li>{#link|Pointers#}</li>1238 <li>{#link|Pointers#}</li>
...@@ -1244,7 +1244,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>...@@ -1244,7 +1244,7 @@ mem.eql(u8, pattern, "ababab")</code></pre>
1244 <td>1244 <td>
1245 <pre><code class="zig">const x: u32 = 1234;1245 <pre><code class="zig">const x: u32 = 1234;
1246const ptr = &amp;x;1246const ptr = &amp;x;
1247*x == 1234</code></pre>1247x.* == 1234</code></pre>
1248 </td>1248 </td>
1249 </tr>1249 </tr>
1250 <tr>1250 <tr>
...@@ -1258,7 +1258,7 @@ const ptr = &amp;x;...@@ -1258,7 +1258,7 @@ const ptr = &amp;x;
1258 <td>1258 <td>
1259 <pre><code class="zig">const x: u32 = 1234;1259 <pre><code class="zig">const x: u32 = 1234;
1260const ptr = &amp;x;1260const ptr = &amp;x;
1261*x == 1234</code></pre>1261x.* == 1234</code></pre>
1262 </td>1262 </td>
1263 </tr>1263 </tr>
1264 </table>1264 </table>
...@@ -1267,8 +1267,8 @@ const ptr = &amp;x;...@@ -1267,8 +1267,8 @@ const ptr = &amp;x;
1267 {#header_open|Precedence#}1267 {#header_open|Precedence#}
1268 <pre><code>x() x[] x.y1268 <pre><code>x() x[] x.y
1269a!b1269a!b
1270!x -x -%x ~x *x &amp;x ?x ??x1270!x -x -%x ~x &amp;x ?x ??x
1271x{}1271x{} x.*
1272! * / % ** *%1272! * / % ** *%
1273+ - ++ +% -%1273+ - ++ +% -%
1274&lt;&lt; &gt;&gt;1274&lt;&lt; &gt;&gt;
...@@ -1316,7 +1316,7 @@ var some_integers: [100]i32 = undefined;...@@ -1316,7 +1316,7 @@ var some_integers: [100]i32 = undefined;
13161316
1317test "modify an array" {1317test "modify an array" {
1318 for (some_integers) |*item, i| {1318 for (some_integers) |*item, i| {
1319 *item = i32(i);1319 item.* = i32(i);
1320 }1320 }
1321 assert(some_integers[10] == 10);1321 assert(some_integers[10] == 10);
1322 assert(some_integers[99] == 99);1322 assert(some_integers[99] == 99);
...@@ -1357,7 +1357,7 @@ comptime {...@@ -1357,7 +1357,7 @@ comptime {
1357var fancy_array = init: {1357var fancy_array = init: {
1358 var initial_value: [10]Point = undefined;1358 var initial_value: [10]Point = undefined;
1359 for (initial_value) |*pt, i| {1359 for (initial_value) |*pt, i| {
1360 *pt = Point {1360 pt.* = Point {
1361 .x = i32(i),1361 .x = i32(i),
1362 .y = i32(i) * 2,1362 .y = i32(i) * 2,
1363 };1363 };
...@@ -1400,7 +1400,7 @@ test "address of syntax" {...@@ -1400,7 +1400,7 @@ test "address of syntax" {
1400 const x_ptr = &x;1400 const x_ptr = &x;
14011401
1402 // Deference a pointer:1402 // Deference a pointer:
1403 assert(*x_ptr == 1234);1403 assert(x_ptr.* == 1234);
14041404
1405 // When you get the address of a const variable, you get a const pointer.1405 // When you get the address of a const variable, you get a const pointer.
1406 assert(@typeOf(x_ptr) == &const i32);1406 assert(@typeOf(x_ptr) == &const i32);
...@@ -1409,8 +1409,8 @@ test "address of syntax" {...@@ -1409,8 +1409,8 @@ test "address of syntax" {
1409 var y: i32 = 5678;1409 var y: i32 = 5678;
1410 const y_ptr = &y;1410 const y_ptr = &y;
1411 assert(@typeOf(y_ptr) == &i32);1411 assert(@typeOf(y_ptr) == &i32);
1412 *y_ptr += 1;1412 y_ptr.* += 1;
1413 assert(*y_ptr == 5679);1413 assert(y_ptr.* == 5679);
1414}1414}
14151415
1416test "pointer array access" {1416test "pointer array access" {
...@@ -1448,9 +1448,9 @@ comptime {...@@ -1448,9 +1448,9 @@ comptime {
1448 // @ptrCast.1448 // @ptrCast.
1449 var x: i32 = 1;1449 var x: i32 = 1;
1450 const ptr = &x;1450 const ptr = &x;
1451 *ptr += 1;1451 ptr.* += 1;
1452 x += 1;1452 x += 1;
1453 assert(*ptr == 3);1453 assert(ptr.* == 3);
1454}1454}
14551455
1456test "@ptrToInt and @intToPtr" {1456test "@ptrToInt and @intToPtr" {
...@@ -1492,7 +1492,7 @@ test "nullable pointers" {...@@ -1492,7 +1492,7 @@ test "nullable pointers" {
1492 var x: i32 = 1;1492 var x: i32 = 1;
1493 ptr = &x;1493 ptr = &x;
14941494
1495 assert(*??ptr == 1);1495 assert((??ptr).* == 1);
14961496
1497 // Nullable pointers are the same size as normal pointers, because pointer1497 // Nullable pointers are the same size as normal pointers, because pointer
1498 // value 0 is used as the null value.1498 // value 0 is used as the null value.
...@@ -1505,7 +1505,7 @@ test "pointer casting" {...@@ -1505,7 +1505,7 @@ test "pointer casting" {
1505 // conversions are not possible.1505 // conversions are not possible.
1506 const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};1506 const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
1507 const u32_ptr = @ptrCast(&const u32, &bytes[0]);1507 const u32_ptr = @ptrCast(&const u32, &bytes[0]);
1508 assert(*u32_ptr == 0x12121212);1508 assert(u32_ptr.* == 0x12121212);
15091509
1510 // Even this example is contrived - there are better ways to do the above than1510 // Even this example is contrived - there are better ways to do the above than
1511 // pointer casting. For example, using a slice narrowing cast:1511 // pointer casting. For example, using a slice narrowing cast:
...@@ -1610,7 +1610,7 @@ fn foo(bytes: []u8) u32 {...@@ -1610,7 +1610,7 @@ fn foo(bytes: []u8) u32 {
1610 <code>u8</code> can alias any memory.1610 <code>u8</code> can alias any memory.
1611 </p>1611 </p>
1612 <p>As an example, this code produces undefined behavior:</p>1612 <p>As an example, this code produces undefined behavior:</p>
1613 <pre><code class="zig">*@ptrCast(&amp;u32, f32(12.34))</code></pre>1613 <pre><code class="zig">@ptrCast(&amp;u32, f32(12.34)).*</code></pre>
1614 <p>Instead, use {#link|@bitCast#}:1614 <p>Instead, use {#link|@bitCast#}:
1615 <pre><code class="zig">@bitCast(u32, f32(12.34))</code></pre>1615 <pre><code class="zig">@bitCast(u32, f32(12.34))</code></pre>
1616 <p>As an added benefit, the <code>@bitcast</code> version works at compile-time.</p>1616 <p>As an added benefit, the <code>@bitcast</code> version works at compile-time.</p>
...@@ -2040,7 +2040,7 @@ const Variant = union(enum) {...@@ -2040,7 +2040,7 @@ const Variant = union(enum) {
2040 Bool: bool,2040 Bool: bool,
20412041
2042 fn truthy(self: &const Variant) bool {2042 fn truthy(self: &const Variant) bool {
2043 return switch (*self) {2043 return switch (self.*) {
2044 Variant.Int => |x_int| x_int != 0,2044 Variant.Int => |x_int| x_int != 0,
2045 Variant.Bool => |x_bool| x_bool,2045 Variant.Bool => |x_bool| x_bool,
2046 };2046 };
...@@ -2151,7 +2151,7 @@ test "switch enum" {...@@ -2151,7 +2151,7 @@ test "switch enum" {
21512151
2152 // A reference to the matched value can be obtained using `*` syntax.2152 // A reference to the matched value can be obtained using `*` syntax.
2153 Item.C => |*item| blk: {2153 Item.C => |*item| blk: {
2154 (*item).x += 1;2154 item.*.x += 1;
2155 break :blk 6;2155 break :blk 6;
2156 },2156 },
21572157
...@@ -2374,7 +2374,7 @@ test "for reference" {...@@ -2374,7 +2374,7 @@ test "for reference" {
2374 // Iterate over the slice by reference by2374 // Iterate over the slice by reference by
2375 // specifying that the capture value is a pointer.2375 // specifying that the capture value is a pointer.
2376 for (items) |*value| {2376 for (items) |*value| {
2377 *value += 1;2377 value.* += 1;
2378 }2378 }
23792379
2380 assert(items[0] == 4);2380 assert(items[0] == 4);
...@@ -2483,7 +2483,7 @@ test "if nullable" {...@@ -2483,7 +2483,7 @@ test "if nullable" {
2483 // Access the value by reference using a pointer capture.2483 // Access the value by reference using a pointer capture.
2484 var c: ?u32 = 3;2484 var c: ?u32 = 3;
2485 if (c) |*value| {2485 if (c) |*value| {
2486 *value = 2;2486 value.* = 2;
2487 }2487 }
24882488
2489 if (c) |value| {2489 if (c) |value| {
...@@ -2524,7 +2524,7 @@ test "if error union" {...@@ -2524,7 +2524,7 @@ test "if error union" {
2524 // Access the value by reference using a pointer capture.2524 // Access the value by reference using a pointer capture.
2525 var c: error!u32 = 3;2525 var c: error!u32 = 3;
2526 if (c) |*value| {2526 if (c) |*value| {
2527 *value = 9;2527 value.* = 9;
2528 } else |err| {2528 } else |err| {
2529 unreachable;2529 unreachable;
2530 }2530 }
...@@ -2827,7 +2827,7 @@ test "fn reflection" {...@@ -2827,7 +2827,7 @@ test "fn reflection" {
2827 </p>2827 </p>
2828 <p>2828 <p>
2829 The number of unique error values across the entire compilation should determine the size of the error set type.2829 The number of unique error values across the entire compilation should determine the size of the error set type.
2830 However right now it is hard coded to be a <code>u16</code>. See <a href="https://github.com/zig-lang/zig/issues/786">#768</a>.2830 However right now it is hard coded to be a <code>u16</code>. See <a href="https://github.com/ziglang/zig/issues/786">#768</a>.
2831 </p>2831 </p>
2832 <p>2832 <p>
2833 You can implicitly cast an error from a subset to its superset:2833 You can implicitly cast an error from a subset to its superset:
...@@ -3111,7 +3111,48 @@ test "error union" {...@@ -3111,7 +3111,48 @@ test "error union" {
3111 {#code_end#}3111 {#code_end#}
3112 <p>TODO the <code>||</code> operator for error sets</p>3112 <p>TODO the <code>||</code> operator for error sets</p>
3113 {#header_open|Inferred Error Sets#}3113 {#header_open|Inferred Error Sets#}
3114 <p>TODO</p>3114 <p>
3115 Because many functions in Zig return a possible error, Zig supports inferring the error set.
3116 To infer the error set for a function, use this syntax:
3117 </p>
3118{#code_begin|test#}
3119// With an inferred error set
3120pub fn add_inferred(comptime T: type, a: T, b: T) !T {
3121 var answer: T = undefined;
3122 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
3123}
3124
3125// With an explicit error set
3126pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {
3127 var answer: T = undefined;
3128 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
3129}
3130
3131const Error = error {
3132 Overflow,
3133};
3134
3135const std = @import("std");
3136
3137test "inferred error set" {
3138 if (add_inferred(u8, 255, 1)) |_| unreachable else |err| switch (err) {
3139 error.Overflow => {}, // ok
3140 }
3141}
3142{#code_end#}
3143 <p>
3144 When a function has an inferred error set, that function becomes generic and thus it becomes
3145 trickier to do certain things with it, such as obtain a function pointer, or have an error
3146 set that is consistent across different build targets. Additionally, inferred error sets
3147 are incompatible with recursion.
3148 </p>
3149 <p>
3150 In these situations, it is recommended to use an explicit error set. You can generally start
3151 with an empty error set and let compile errors guide you toward completing the set.
3152 </p>
3153 <p>
3154 These limitations may be overcome in a future version of Zig.
3155 </p>
3115 {#header_close#}3156 {#header_close#}
3116 {#header_close#}3157 {#header_close#}
3117 {#header_open|Error Return Traces#}3158 {#header_open|Error Return Traces#}
...@@ -3872,13 +3913,22 @@ pub fn main() void {...@@ -3872,13 +3913,22 @@ pub fn main() void {
3872 {#header_open|@addWithOverflow#}3913 {#header_open|@addWithOverflow#}
3873 <pre><code class="zig">@addWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>3914 <pre><code class="zig">@addWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
3874 <p>3915 <p>
3875 Performs <code>*result = a + b</code>. If overflow or underflow occurs,3916 Performs <code>result.* = a + b</code>. If overflow or underflow occurs,
3876 stores the overflowed bits in <code>result</code> and returns <code>true</code>.3917 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
3877 If no overflow or underflow occurs, returns <code>false</code>.3918 If no overflow or underflow occurs, returns <code>false</code>.
3878 </p>3919 </p>
3879 {#header_close#}3920 {#header_close#}
3880 {#header_open|@ArgType#}3921 {#header_open|@ArgType#}
3881 <p>TODO</p>3922 <pre><code class="zig">@ArgType(comptime T: type, comptime n: usize) -&gt; type</code></pre>
3923 <p>
3924 This builtin function takes a function type and returns the type of the parameter at index <code>n</code>.
3925 </p>
3926 <p>
3927 <code>T</code> must be a function type.
3928 </p>
3929 <p>
3930 Note: This function is deprecated. Use {#link|@typeInfo#} instead.
3931 </p>
3882 {#header_close#}3932 {#header_close#}
3883 {#header_open|@atomicLoad#}3933 {#header_open|@atomicLoad#}
3884 <pre><code class="zig">@atomicLoad(comptime T: type, ptr: &amp;const T, comptime ordering: builtin.AtomicOrder) -&gt; T</code></pre>3934 <pre><code class="zig">@atomicLoad(comptime T: type, ptr: &amp;const T, comptime ordering: builtin.AtomicOrder) -&gt; T</code></pre>
...@@ -4073,9 +4123,9 @@ comptime {...@@ -4073,9 +4123,9 @@ comptime {
4073 </p>4123 </p>
4074 {#code_begin|syntax#}4124 {#code_begin|syntax#}
4075fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {4125fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {
4076 const old_value = *ptr;4126 const old_value = ptr.*;
4077 if (old_value == expected_value) {4127 if (old_value == expected_value) {
4078 *ptr = new_value;4128 ptr.* = new_value;
4079 return null;4129 return null;
4080 } else {4130 } else {
4081 return old_value;4131 return old_value;
...@@ -4100,9 +4150,9 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_v...@@ -4100,9 +4150,9 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_v
4100 </p>4150 </p>
4101 {#code_begin|syntax#}4151 {#code_begin|syntax#}
4102fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {4152fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {
4103 const old_value = *ptr;4153 const old_value = ptr.*;
4104 if (old_value == expected_value and usuallyTrueButSometimesFalse()) {4154 if (old_value == expected_value and usuallyTrueButSometimesFalse()) {
4105 *ptr = new_value;4155 ptr.* = new_value;
4106 return null;4156 return null;
4107 } else {4157 } else {
4108 return old_value;4158 return old_value;
...@@ -4447,7 +4497,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre>...@@ -4447,7 +4497,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre>
4447 This function is a low level intrinsic with no safety mechanisms. Most4497 This function is a low level intrinsic with no safety mechanisms. Most
4448 code should not use this function, instead using something like this:4498 code should not use this function, instead using something like this:
4449 </p>4499 </p>
4450 <pre><code class="zig">for (dest[0...byte_count]) |*b| *b = c;</code></pre>4500 <pre><code class="zig">for (dest[0...byte_count]) |*b| b.* = c;</code></pre>
4451 <p>4501 <p>
4452 The optimizer is intelligent enough to turn the above snippet into a memset.4502 The optimizer is intelligent enough to turn the above snippet into a memset.
4453 </p>4503 </p>
...@@ -4480,22 +4530,63 @@ mem.set(u8, dest, c);</code></pre>...@@ -4480,22 +4530,63 @@ mem.set(u8, dest, c);</code></pre>
4480 {#header_open|@mulWithOverflow#}4530 {#header_open|@mulWithOverflow#}
4481 <pre><code class="zig">@mulWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>4531 <pre><code class="zig">@mulWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
4482 <p>4532 <p>
4483 Performs <code>*result = a * b</code>. If overflow or underflow occurs,4533 Performs <code>result.* = a * b</code>. If overflow or underflow occurs,
4484 stores the overflowed bits in <code>result</code> and returns <code>true</code>.4534 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
4485 If no overflow or underflow occurs, returns <code>false</code>.4535 If no overflow or underflow occurs, returns <code>false</code>.
4486 </p>4536 </p>
4487 {#header_close#}4537 {#header_close#}
4538 {#header_open|@newStackCall#}
4539 <pre><code class="zig">@newStackCall(new_stack: []u8, function: var, args: ...) -&gt; var</code></pre>
4540 <p>
4541 This calls a function, in the same way that invoking an expression with parentheses does. However,
4542 instead of using the same stack as the caller, the function uses the stack provided in the <code>new_stack</code>
4543 parameter.
4544 </p>
4545 {#code_begin|test#}
4546const std = @import("std");
4547const assert = std.debug.assert;
4548
4549var new_stack_bytes: [1024]u8 = undefined;
4550
4551test "calling a function with a new stack" {
4552 const arg = 1234;
4553
4554 const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
4555 const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
4556 _ = targetFunction(arg);
4557
4558 assert(arg == 1234);
4559 assert(a < b);
4560}
4561
4562fn targetFunction(x: i32) usize {
4563 assert(x == 1234);
4564
4565 var local_variable: i32 = 42;
4566 const ptr = &local_variable;
4567 ptr.* += 1;
4568
4569 assert(local_variable == 43);
4570 return @ptrToInt(ptr);
4571}
4572 {#code_end#}
4573 {#header_close#}
4488 {#header_open|@noInlineCall#}4574 {#header_open|@noInlineCall#}
4489 <pre><code class="zig">@noInlineCall(function: var, args: ...) -&gt; var</code></pre>4575 <pre><code class="zig">@noInlineCall(function: var, args: ...) -&gt; var</code></pre>
4490 <p>4576 <p>
4491 This calls a function, in the same way that invoking an expression with parentheses does:4577 This calls a function, in the same way that invoking an expression with parentheses does:
4492 </p>4578 </p>
4493 <pre><code class="zig">const assert = @import("std").debug.assert;4579 {#code_begin|test#}
4580const assert = @import("std").debug.assert;
4581
4494test "noinline function call" {4582test "noinline function call" {
4495 assert(@noInlineCall(add, 3, 9) == 12);4583 assert(@noInlineCall(add, 3, 9) == 12);
4496}4584}
44974585
4498fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>4586fn add(a: i32, b: i32) i32 {
4587 return a + b;
4588}
4589 {#code_end#}
4499 <p>4590 <p>
4500 Unlike a normal function call, however, <code>@noInlineCall</code> guarantees that the call4591 Unlike a normal function call, however, <code>@noInlineCall</code> guarantees that the call
4501 will not be inlined. If the call must be inlined, a compile error is emitted.4592 will not be inlined. If the call must be inlined, a compile error is emitted.
...@@ -4705,7 +4796,7 @@ pub const FloatMode = enum {...@@ -4705,7 +4796,7 @@ pub const FloatMode = enum {
4705 {#header_open|@shlWithOverflow#}4796 {#header_open|@shlWithOverflow#}
4706 <pre><code class="zig">@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: &T) -&gt; bool</code></pre>4797 <pre><code class="zig">@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: &T) -&gt; bool</code></pre>
4707 <p>4798 <p>
4708 Performs <code>*result = a &lt;&lt; b</code>. If overflow or underflow occurs,4799 Performs <code>result.* = a &lt;&lt; b</code>. If overflow or underflow occurs,
4709 stores the overflowed bits in <code>result</code> and returns <code>true</code>.4800 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
4710 If no overflow or underflow occurs, returns <code>false</code>.4801 If no overflow or underflow occurs, returns <code>false</code>.
4711 </p>4802 </p>
...@@ -4749,7 +4840,7 @@ pub const FloatMode = enum {...@@ -4749,7 +4840,7 @@ pub const FloatMode = enum {
4749 {#header_open|@subWithOverflow#}4840 {#header_open|@subWithOverflow#}
4750 <pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>4841 <pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
4751 <p>4842 <p>
4752 Performs <code>*result = a - b</code>. If overflow or underflow occurs,4843 Performs <code>result.* = a - b</code>. If overflow or underflow occurs,
4753 stores the overflowed bits in <code>result</code> and returns <code>true</code>.4844 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
4754 If no overflow or underflow occurs, returns <code>false</code>.4845 If no overflow or underflow occurs, returns <code>false</code>.
4755 </p>4846 </p>
...@@ -5867,7 +5958,7 @@ pub fn main() void {...@@ -5867,7 +5958,7 @@ pub fn main() void {
5867 {#code_begin|exe#}5958 {#code_begin|exe#}
5868 {#link_libc#}5959 {#link_libc#}
5869const c = @cImport({5960const c = @cImport({
5870 // See https://github.com/zig-lang/zig/issues/5155961 // See https://github.com/ziglang/zig/issues/515
5871 @cDefine("_NO_CRT_STDIO_INLINE", "1");5962 @cDefine("_NO_CRT_STDIO_INLINE", "1");
5872 @cInclude("stdio.h");5963 @cInclude("stdio.h");
5873});5964});
...@@ -6210,7 +6301,7 @@ fn readU32Be() u32 {}...@@ -6210,7 +6301,7 @@ fn readU32Be() u32 {}
6210 <li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>6301 <li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>
6211 </ul>6302 </ul>
6212 <p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possbly the last line of the file).</p>6303 <p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possbly the last line of the file).</p>
6213 <p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/zig-lang/zig/issues/663">issue #663</a></p>6304 <p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/ziglang/zig/issues/663">issue #663</a></p>
6214 {#header_close#}6305 {#header_close#}
6215 {#header_open|Grammar#}6306 {#header_open|Grammar#}
6216 <pre><code class="nohighlight">Root = many(TopLevelItem) EOF6307 <pre><code class="nohighlight">Root = many(TopLevelItem) EOF
...@@ -6341,10 +6432,12 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"...@@ -6341,10 +6432,12 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
63416432
6342PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression6433PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
63436434
6344SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)6435SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | PtrDerefExpression)
63456436
6346FieldAccessExpression = "." Symbol6437FieldAccessExpression = "." Symbol
63476438
6439PtrDerefExpression = ".*"
6440
6348FnCallExpression = "(" list(Expression, ",") ")"6441FnCallExpression = "(" list(Expression, ",") ")"
63496442
6350ArrayAccessExpression = "[" Expression "]"6443ArrayAccessExpression = "[" Expression "]"
...@@ -6357,7 +6450,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")...@@ -6357,7 +6450,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
63576450
6358StructLiteralField = "." Symbol "=" Expression6451StructLiteralField = "." Symbol "=" Expression
63596452
6360PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"6453PrefixOp = "!" | "-" | "~" | ("*" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
63616454
6362PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType6455PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
63636456
...@@ -6451,7 +6544,7 @@ hljs.registerLanguage("zig", function(t) {...@@ -6451,7 +6544,7 @@ hljs.registerLanguage("zig", function(t) {
6451 a = t.IR + "\\s*\\(",6544 a = t.IR + "\\s*\\(",
6452 c = {6545 c = {
6453 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",6546 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
6454 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo",6547 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo newStackCall",
6455 literal: "true false null undefined"6548 literal: "true false null undefined"
6456 },6549 },
6457 n = [e, t.CLCM, t.CBCM, s, r];6550 n = [e, t.CLCM, t.CBCM, s, r];
example/hello_world/hello_libc.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const c = @cImport({1const c = @cImport({
2 // See https://github.com/zig-lang/zig/issues/5152 // See https://github.com/ziglang/zig/issues/515
3 @cDefine("_NO_CRT_STDIO_INLINE", "1");3 @cDefine("_NO_CRT_STDIO_INLINE", "1");
4 @cInclude("stdio.h");4 @cInclude("stdio.h");
5 @cInclude("string.h");5 @cInclude("string.h");
src-self-hosted/arg.zig+41-33
...@@ -30,24 +30,22 @@ fn argInAllowedSet(maybe_set: ?[]const []const u8, arg: []const u8) bool {...@@ -30,24 +30,22 @@ fn argInAllowedSet(maybe_set: ?[]const []const u8, arg: []const u8) bool {
30}30}
3131
32// Modifies the current argument index during iteration32// Modifies the current argument index during iteration
33fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required: usize,33fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required: usize, allowed_set: ?[]const []const u8, index: &usize) !FlagArg {
34 allowed_set: ?[]const []const u8, index: &usize) !FlagArg {
35
36 switch (required) {34 switch (required) {
37 0 => return FlagArg { .None = undefined }, // TODO: Required to force non-tag but value?35 0 => return FlagArg{ .None = undefined }, // TODO: Required to force non-tag but value?
38 1 => {36 1 => {
39 if (*index + 1 >= args.len) {37 if (index.* + 1 >= args.len) {
40 return error.MissingFlagArguments;38 return error.MissingFlagArguments;
41 }39 }
4240
43 *index += 1;41 index.* += 1;
44 const arg = args[*index];42 const arg = args[index.*];
4543
46 if (!argInAllowedSet(allowed_set, arg)) {44 if (!argInAllowedSet(allowed_set, arg)) {
47 return error.ArgumentNotInAllowedSet;45 return error.ArgumentNotInAllowedSet;
48 }46 }
4947
50 return FlagArg { .Single = arg };48 return FlagArg{ .Single = arg };
51 },49 },
52 else => |needed| {50 else => |needed| {
53 var extra = ArrayList([]const u8).init(allocator);51 var extra = ArrayList([]const u8).init(allocator);
...@@ -55,12 +53,12 @@ fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required:...@@ -55,12 +53,12 @@ fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required:
5553
56 var j: usize = 0;54 var j: usize = 0;
57 while (j < needed) : (j += 1) {55 while (j < needed) : (j += 1) {
58 if (*index + 1 >= args.len) {56 if (index.* + 1 >= args.len) {
59 return error.MissingFlagArguments;57 return error.MissingFlagArguments;
60 }58 }
6159
62 *index += 1;60 index.* += 1;
63 const arg = args[*index];61 const arg = args[index.*];
6462
65 if (!argInAllowedSet(allowed_set, arg)) {63 if (!argInAllowedSet(allowed_set, arg)) {
66 return error.ArgumentNotInAllowedSet;64 return error.ArgumentNotInAllowedSet;
...@@ -69,7 +67,7 @@ fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required:...@@ -69,7 +67,7 @@ fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required:
69 try extra.append(arg);67 try extra.append(arg);
70 }68 }
7169
72 return FlagArg { .Many = extra };70 return FlagArg{ .Many = extra };
73 },71 },
74 }72 }
75}73}
...@@ -82,7 +80,7 @@ pub const Args = struct {...@@ -82,7 +80,7 @@ pub const Args = struct {
82 positionals: ArrayList([]const u8),80 positionals: ArrayList([]const u8),
8381
84 pub fn parse(allocator: &Allocator, comptime spec: []const Flag, args: []const []const u8) !Args {82 pub fn parse(allocator: &Allocator, comptime spec: []const Flag, args: []const []const u8) !Args {
85 var parsed = Args {83 var parsed = Args{
86 .flags = HashMapFlags.init(allocator),84 .flags = HashMapFlags.init(allocator),
87 .positionals = ArrayList([]const u8).init(allocator),85 .positionals = ArrayList([]const u8).init(allocator),
88 };86 };
...@@ -116,11 +114,7 @@ pub const Args = struct {...@@ -116,11 +114,7 @@ pub const Args = struct {
116 };114 };
117115
118 if (flag.mergable) {116 if (flag.mergable) {
119 var prev =117 var prev = if (parsed.flags.get(flag_name_trimmed)) |entry| entry.value.Many else ArrayList([]const u8).init(allocator);
120 if (parsed.flags.get(flag_name_trimmed)) |entry|
121 entry.value.Many
122 else
123 ArrayList([]const u8).init(allocator);
124118
125 // MergeN creation disallows 0 length flag entry (doesn't make sense)119 // MergeN creation disallows 0 length flag entry (doesn't make sense)
126 switch (flag_args) {120 switch (flag_args) {
...@@ -129,7 +123,7 @@ pub const Args = struct {...@@ -129,7 +123,7 @@ pub const Args = struct {
129 FlagArg.Many => |inner| try prev.appendSlice(inner.toSliceConst()),123 FlagArg.Many => |inner| try prev.appendSlice(inner.toSliceConst()),
130 }124 }
131125
132 _ = try parsed.flags.put(flag_name_trimmed, FlagArg { .Many = prev });126 _ = try parsed.flags.put(flag_name_trimmed, FlagArg{ .Many = prev });
133 } else {127 } else {
134 _ = try parsed.flags.put(flag_name_trimmed, flag_args);128 _ = try parsed.flags.put(flag_name_trimmed, flag_args);
135 }129 }
...@@ -163,7 +157,9 @@ pub const Args = struct {...@@ -163,7 +157,9 @@ pub const Args = struct {
163 pub fn single(self: &Args, name: []const u8) ?[]const u8 {157 pub fn single(self: &Args, name: []const u8) ?[]const u8 {
164 if (self.flags.get(name)) |entry| {158 if (self.flags.get(name)) |entry| {
165 switch (entry.value) {159 switch (entry.value) {
166 FlagArg.Single => |inner| { return inner; },160 FlagArg.Single => |inner| {
161 return inner;
162 },
167 else => @panic("attempted to retrieve flag with wrong type"),163 else => @panic("attempted to retrieve flag with wrong type"),
168 }164 }
169 } else {165 } else {
...@@ -175,7 +171,9 @@ pub const Args = struct {...@@ -175,7 +171,9 @@ pub const Args = struct {
175 pub fn many(self: &Args, name: []const u8) ?[]const []const u8 {171 pub fn many(self: &Args, name: []const u8) ?[]const []const u8 {
176 if (self.flags.get(name)) |entry| {172 if (self.flags.get(name)) |entry| {
177 switch (entry.value) {173 switch (entry.value) {
178 FlagArg.Many => |inner| { return inner.toSliceConst(); },174 FlagArg.Many => |inner| {
175 return inner.toSliceConst();
176 },
179 else => @panic("attempted to retrieve flag with wrong type"),177 else => @panic("attempted to retrieve flag with wrong type"),
180 }178 }
181 } else {179 } else {
...@@ -207,7 +205,7 @@ pub const Flag = struct {...@@ -207,7 +205,7 @@ pub const Flag = struct {
207 }205 }
208206
209 pub fn ArgN(comptime name: []const u8, comptime n: usize) Flag {207 pub fn ArgN(comptime name: []const u8, comptime n: usize) Flag {
210 return Flag {208 return Flag{
211 .name = name,209 .name = name,
212 .required = n,210 .required = n,
213 .mergable = false,211 .mergable = false,
...@@ -220,7 +218,7 @@ pub const Flag = struct {...@@ -220,7 +218,7 @@ pub const Flag = struct {
220 @compileError("n must be greater than 0");218 @compileError("n must be greater than 0");
221 }219 }
222220
223 return Flag {221 return Flag{
224 .name = name,222 .name = name,
225 .required = n,223 .required = n,
226 .mergable = true,224 .mergable = true,
...@@ -229,7 +227,7 @@ pub const Flag = struct {...@@ -229,7 +227,7 @@ pub const Flag = struct {
229 }227 }
230228
231 pub fn Option(comptime name: []const u8, comptime set: []const []const u8) Flag {229 pub fn Option(comptime name: []const u8, comptime set: []const []const u8) Flag {
232 return Flag {230 return Flag{
233 .name = name,231 .name = name,
234 .required = 1,232 .required = 1,
235 .mergable = false,233 .mergable = false,
...@@ -239,26 +237,36 @@ pub const Flag = struct {...@@ -239,26 +237,36 @@ pub const Flag = struct {
239};237};
240238
241test "parse arguments" {239test "parse arguments" {
242 const spec1 = comptime []const Flag {240 const spec1 = comptime []const Flag{
243 Flag.Bool("--help"),241 Flag.Bool("--help"),
244 Flag.Bool("--init"),242 Flag.Bool("--init"),
245 Flag.Arg1("--build-file"),243 Flag.Arg1("--build-file"),
246 Flag.Option("--color", []const []const u8 { "on", "off", "auto" }),244 Flag.Option("--color", []const []const u8{
245 "on",
246 "off",
247 "auto",
248 }),
247 Flag.ArgN("--pkg-begin", 2),249 Flag.ArgN("--pkg-begin", 2),
248 Flag.ArgMergeN("--object", 1),250 Flag.ArgMergeN("--object", 1),
249 Flag.ArgN("--library", 1),251 Flag.ArgN("--library", 1),
250 };252 };
251253
252 const cliargs = []const []const u8 {254 const cliargs = []const []const u8{
253 "build",255 "build",
254 "--help",256 "--help",
255 "pos1",257 "pos1",
256 "--build-file", "build.zig",258 "--build-file",
257 "--object", "obj1",259 "build.zig",
258 "--object", "obj2",260 "--object",
259 "--library", "lib1",261 "obj1",
260 "--library", "lib2",262 "--object",
261 "--color", "on",263 "obj2",
264 "--library",
265 "lib1",
266 "--library",
267 "lib2",
268 "--color",
269 "on",
262 "pos2",270 "pos2",
263 };271 };
264272
src-self-hosted/main.zig-2
...@@ -637,14 +637,12 @@ const usage_fmt =...@@ -637,14 +637,12 @@ const usage_fmt =
637 \\637 \\
638 \\Options:638 \\Options:
639 \\ --help Print this help and exit639 \\ --help Print this help and exit
640 \\ --keep-backups Retain backup entries for every file
641 \\640 \\
642 \\641 \\
643 ;642 ;
644643
645const args_fmt_spec = []Flag {644const args_fmt_spec = []Flag {
646 Flag.Bool("--help"),645 Flag.Bool("--help"),
647 Flag.Bool("--keep-backups"),
648};646};
649647
650fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {648fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
src-self-hosted/module.zig+9-9
...@@ -96,6 +96,7 @@ pub const Module = struct {...@@ -96,6 +96,7 @@ pub const Module = struct {
96 pub const LinkLib = struct {96 pub const LinkLib = struct {
97 name: []const u8,97 name: []const u8,
98 path: ?[]const u8,98 path: ?[]const u8,
99
99 /// the list of symbols we depend on from this lib100 /// the list of symbols we depend on from this lib
100 symbols: ArrayList([]u8),101 symbols: ArrayList([]u8),
101 provided_explicitly: bool,102 provided_explicitly: bool,
...@@ -130,9 +131,7 @@ pub const Module = struct {...@@ -130,9 +131,7 @@ pub const Module = struct {
130 }131 }
131 };132 };
132133
133 pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,134 pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target, kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module {
134 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
135 {
136 var name_buffer = try Buffer.init(allocator, name);135 var name_buffer = try Buffer.init(allocator, name);
137 errdefer name_buffer.deinit();136 errdefer name_buffer.deinit();
138137
...@@ -148,14 +147,14 @@ pub const Module = struct {...@@ -148,14 +147,14 @@ pub const Module = struct {
148 const module_ptr = try allocator.create(Module);147 const module_ptr = try allocator.create(Module);
149 errdefer allocator.destroy(module_ptr);148 errdefer allocator.destroy(module_ptr);
150149
151 *module_ptr = Module {150 module_ptr.* = Module{
152 .allocator = allocator,151 .allocator = allocator,
153 .name = name_buffer,152 .name = name_buffer,
154 .root_src_path = root_src_path,153 .root_src_path = root_src_path,
155 .module = module,154 .module = module,
156 .context = context,155 .context = context,
157 .builder = builder,156 .builder = builder,
158 .target = *target,157 .target = target.*,
159 .kind = kind,158 .kind = kind,
160 .build_mode = build_mode,159 .build_mode = build_mode,
161 .zig_lib_dir = zig_lib_dir,160 .zig_lib_dir = zig_lib_dir,
...@@ -221,8 +220,10 @@ pub const Module = struct {...@@ -221,8 +220,10 @@ pub const Module = struct {
221220
222 pub fn build(self: &Module) !void {221 pub fn build(self: &Module) !void {
223 if (self.llvm_argv.len != 0) {222 if (self.llvm_argv.len != 0) {
224 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator,223 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator, [][]const []const u8{
225 [][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, });224 [][]const u8{"zig (LLVM option parsing)"},
225 self.llvm_argv,
226 });
226 defer c_compatible_args.deinit();227 defer c_compatible_args.deinit();
227 c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);228 c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
228 }229 }
...@@ -261,7 +262,6 @@ pub const Module = struct {...@@ -261,7 +262,6 @@ pub const Module = struct {
261262
262 warn("====llvm ir:====\n");263 warn("====llvm ir:====\n");
263 self.dump();264 self.dump();
264
265 }265 }
266266
267 pub fn link(self: &Module, out_file: ?[]const u8) !void {267 pub fn link(self: &Module, out_file: ?[]const u8) !void {
...@@ -285,7 +285,7 @@ pub const Module = struct {...@@ -285,7 +285,7 @@ pub const Module = struct {
285 }285 }
286286
287 const link_lib = try self.allocator.create(LinkLib);287 const link_lib = try self.allocator.create(LinkLib);
288 *link_lib = LinkLib {288 link_lib.* = LinkLib{
289 .name = name,289 .name = name,
290 .path = null,290 .path = null,
291 .provided_explicitly = provided_explicitly,291 .provided_explicitly = provided_explicitly,
src-self-hosted/target.zig+4-3
...@@ -12,7 +12,7 @@ pub const Target = union(enum) {...@@ -12,7 +12,7 @@ pub const Target = union(enum) {
12 Cross: CrossTarget,12 Cross: CrossTarget,
1313
14 pub fn oFileExt(self: &const Target) []const u8 {14 pub fn oFileExt(self: &const Target) []const u8 {
15 const environ = switch (*self) {15 const environ = switch (self.*) {
16 Target.Native => builtin.environ,16 Target.Native => builtin.environ,
17 Target.Cross => |t| t.environ,17 Target.Cross => |t| t.environ,
18 };18 };
...@@ -30,7 +30,7 @@ pub const Target = union(enum) {...@@ -30,7 +30,7 @@ pub const Target = union(enum) {
30 }30 }
3131
32 pub fn getOs(self: &const Target) builtin.Os {32 pub fn getOs(self: &const Target) builtin.Os {
33 return switch (*self) {33 return switch (self.*) {
34 Target.Native => builtin.os,34 Target.Native => builtin.os,
35 Target.Cross => |t| t.os,35 Target.Cross => |t| t.os,
36 };36 };
...@@ -38,7 +38,8 @@ pub const Target = union(enum) {...@@ -38,7 +38,8 @@ pub const Target = union(enum) {
3838
39 pub fn isDarwin(self: &const Target) bool {39 pub fn isDarwin(self: &const Target) bool {
40 return switch (self.getOs()) {40 return switch (self.getOs()) {
41 builtin.Os.ios, builtin.Os.macosx => true,41 builtin.Os.ios,
42 builtin.Os.macosx => true,
42 else => false,43 else => false,
43 };44 };
44 }45 }
src/all_types.hpp+13-1
...@@ -379,6 +379,7 @@ enum NodeType {...@@ -379,6 +379,7 @@ enum NodeType {
379 NodeTypeArrayAccessExpr,379 NodeTypeArrayAccessExpr,
380 NodeTypeSliceExpr,380 NodeTypeSliceExpr,
381 NodeTypeFieldAccessExpr,381 NodeTypeFieldAccessExpr,
382 NodeTypePtrDeref,
382 NodeTypeUse,383 NodeTypeUse,
383 NodeTypeBoolLiteral,384 NodeTypeBoolLiteral,
384 NodeTypeNullLiteral,385 NodeTypeNullLiteral,
...@@ -603,13 +604,16 @@ struct AstNodeFieldAccessExpr {...@@ -603,13 +604,16 @@ struct AstNodeFieldAccessExpr {
603 Buf *field_name;604 Buf *field_name;
604};605};
605606
607struct AstNodePtrDerefExpr {
608 AstNode *target;
609};
610
606enum PrefixOp {611enum PrefixOp {
607 PrefixOpInvalid,612 PrefixOpInvalid,
608 PrefixOpBoolNot,613 PrefixOpBoolNot,
609 PrefixOpBinNot,614 PrefixOpBinNot,
610 PrefixOpNegation,615 PrefixOpNegation,
611 PrefixOpNegationWrap,616 PrefixOpNegationWrap,
612 PrefixOpDereference,
613 PrefixOpMaybe,617 PrefixOpMaybe,
614 PrefixOpUnwrapMaybe,618 PrefixOpUnwrapMaybe,
615};619};
...@@ -911,6 +915,7 @@ struct AstNode {...@@ -911,6 +915,7 @@ struct AstNode {
911 AstNodeCompTime comptime_expr;915 AstNodeCompTime comptime_expr;
912 AstNodeAsmExpr asm_expr;916 AstNodeAsmExpr asm_expr;
913 AstNodeFieldAccessExpr field_access_expr;917 AstNodeFieldAccessExpr field_access_expr;
918 AstNodePtrDerefExpr ptr_deref_expr;
914 AstNodeContainerDecl container_decl;919 AstNodeContainerDecl container_decl;
915 AstNodeStructField struct_field;920 AstNodeStructField struct_field;
916 AstNodeStringLiteral string_literal;921 AstNodeStringLiteral string_literal;
...@@ -1340,6 +1345,7 @@ enum BuiltinFnId {...@@ -1340,6 +1345,7 @@ enum BuiltinFnId {
1340 BuiltinFnIdOffsetOf,1345 BuiltinFnIdOffsetOf,
1341 BuiltinFnIdInlineCall,1346 BuiltinFnIdInlineCall,
1342 BuiltinFnIdNoInlineCall,1347 BuiltinFnIdNoInlineCall,
1348 BuiltinFnIdNewStackCall,
1343 BuiltinFnIdTypeId,1349 BuiltinFnIdTypeId,
1344 BuiltinFnIdShlExact,1350 BuiltinFnIdShlExact,
1345 BuiltinFnIdShrExact,1351 BuiltinFnIdShrExact,
...@@ -1654,8 +1660,13 @@ struct CodeGen {...@@ -1654,8 +1660,13 @@ struct CodeGen {
1654 LLVMValueRef coro_alloc_helper_fn_val;1660 LLVMValueRef coro_alloc_helper_fn_val;
1655 LLVMValueRef merge_err_ret_traces_fn_val;1661 LLVMValueRef merge_err_ret_traces_fn_val;
1656 LLVMValueRef add_error_return_trace_addr_fn_val;1662 LLVMValueRef add_error_return_trace_addr_fn_val;
1663 LLVMValueRef stacksave_fn_val;
1664 LLVMValueRef stackrestore_fn_val;
1665 LLVMValueRef write_register_fn_val;
1657 bool error_during_imports;1666 bool error_during_imports;
16581667
1668 LLVMValueRef sp_md_node;
1669
1659 const char **clang_argv;1670 const char **clang_argv;
1660 size_t clang_argv_len;1671 size_t clang_argv_len;
1661 ZigList<const char *> lib_dirs;1672 ZigList<const char *> lib_dirs;
...@@ -2278,6 +2289,7 @@ struct IrInstructionCall {...@@ -2278,6 +2289,7 @@ struct IrInstructionCall {
2278 bool is_async;2289 bool is_async;
22792290
2280 IrInstruction *async_allocator;2291 IrInstruction *async_allocator;
2292 IrInstruction *new_stack;
2281};2293};
22822294
2283struct IrInstructionConst {2295struct IrInstructionConst {
src/analyze.cpp+3-2
...@@ -1007,7 +1007,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1007,7 +1007,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
1007 if (fn_type_id->return_type != nullptr) {1007 if (fn_type_id->return_type != nullptr) {
1008 ensure_complete_type(g, fn_type_id->return_type);1008 ensure_complete_type(g, fn_type_id->return_type);
1009 } else {1009 } else {
1010 zig_panic("TODO implement inferred return types https://github.com/zig-lang/zig/issues/447");1010 zig_panic("TODO implement inferred return types https://github.com/ziglang/zig/issues/447");
1011 }1011 }
10121012
1013 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);1013 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
...@@ -1556,7 +1556,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1556,7 +1556,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1556 return g->builtin_types.entry_invalid;1556 return g->builtin_types.entry_invalid;
1557 }1557 }
1558 add_node_error(g, proto_node,1558 add_node_error(g, proto_node,
1559 buf_sprintf("TODO implement inferred return types https://github.com/zig-lang/zig/issues/447"));1559 buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
1560 return g->builtin_types.entry_invalid;1560 return g->builtin_types.entry_invalid;
1561 //return get_generic_fn_type(g, &fn_type_id);1561 //return get_generic_fn_type(g, &fn_type_id);
1562 }1562 }
...@@ -3281,6 +3281,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3281,6 +3281,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3281 case NodeTypeUnreachable:3281 case NodeTypeUnreachable:
3282 case NodeTypeAsmExpr:3282 case NodeTypeAsmExpr:
3283 case NodeTypeFieldAccessExpr:3283 case NodeTypeFieldAccessExpr:
3284 case NodeTypePtrDeref:
3284 case NodeTypeStructField:3285 case NodeTypeStructField:
3285 case NodeTypeContainerInitExpr:3286 case NodeTypeContainerInitExpr:
3286 case NodeTypeStructValueField:3287 case NodeTypeStructValueField:
src/ast_render.cpp+9-1
...@@ -66,7 +66,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {...@@ -66,7 +66,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
66 case PrefixOpNegationWrap: return "-%";66 case PrefixOpNegationWrap: return "-%";
67 case PrefixOpBoolNot: return "!";67 case PrefixOpBoolNot: return "!";
68 case PrefixOpBinNot: return "~";68 case PrefixOpBinNot: return "~";
69 case PrefixOpDereference: return "*";
70 case PrefixOpMaybe: return "?";69 case PrefixOpMaybe: return "?";
71 case PrefixOpUnwrapMaybe: return "??";70 case PrefixOpUnwrapMaybe: return "??";
72 }71 }
...@@ -222,6 +221,8 @@ static const char *node_type_str(NodeType node_type) {...@@ -222,6 +221,8 @@ static const char *node_type_str(NodeType node_type) {
222 return "AsmExpr";221 return "AsmExpr";
223 case NodeTypeFieldAccessExpr:222 case NodeTypeFieldAccessExpr:
224 return "FieldAccessExpr";223 return "FieldAccessExpr";
224 case NodeTypePtrDeref:
225 return "PtrDerefExpr";
225 case NodeTypeContainerDecl:226 case NodeTypeContainerDecl:
226 return "ContainerDecl";227 return "ContainerDecl";
227 case NodeTypeStructField:228 case NodeTypeStructField:
...@@ -696,6 +697,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -696,6 +697,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
696 print_symbol(ar, rhs);697 print_symbol(ar, rhs);
697 break;698 break;
698 }699 }
700 case NodeTypePtrDeref:
701 {
702 AstNode *lhs = node->data.ptr_deref_expr.target;
703 render_node_ungrouped(ar, lhs);
704 fprintf(ar->f, ".*");
705 break;
706 }
699 case NodeTypeUndefinedLiteral:707 case NodeTypeUndefinedLiteral:
700 fprintf(ar->f, "undefined");708 fprintf(ar->f, "undefined");
701 break;709 break;
src/codegen.cpp+100-5
...@@ -586,7 +586,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -586,7 +586,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
586 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");586 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
587 }587 }
588 // Note: byval is disabled on windows due to an LLVM bug:588 // Note: byval is disabled on windows due to an LLVM bug:
589 // https://github.com/zig-lang/zig/issues/536589 // https://github.com/ziglang/zig/issues/536
590 if (is_byval && g->zig_target.os != OsWindows) {590 if (is_byval && g->zig_target.os != OsWindows) {
591 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "byval");591 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "byval");
592 }592 }
...@@ -923,6 +923,53 @@ static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) {...@@ -923,6 +923,53 @@ static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) {
923 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);923 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
924}924}
925925
926static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
927 if (g->stacksave_fn_val)
928 return g->stacksave_fn_val;
929
930 // declare i8* @llvm.stacksave()
931
932 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), nullptr, 0, false);
933 g->stacksave_fn_val = LLVMAddFunction(g->module, "llvm.stacksave", fn_type);
934 assert(LLVMGetIntrinsicID(g->stacksave_fn_val));
935
936 return g->stacksave_fn_val;
937}
938
939static LLVMValueRef get_stackrestore_fn_val(CodeGen *g) {
940 if (g->stackrestore_fn_val)
941 return g->stackrestore_fn_val;
942
943 // declare void @llvm.stackrestore(i8* %ptr)
944
945 LLVMTypeRef param_type = LLVMPointerType(LLVMInt8Type(), 0);
946 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), &param_type, 1, false);
947 g->stackrestore_fn_val = LLVMAddFunction(g->module, "llvm.stackrestore", fn_type);
948 assert(LLVMGetIntrinsicID(g->stackrestore_fn_val));
949
950 return g->stackrestore_fn_val;
951}
952
953static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
954 if (g->write_register_fn_val)
955 return g->write_register_fn_val;
956
957 // declare void @llvm.write_register.i64(metadata, i64 @value)
958 // !0 = !{!"sp\00"}
959
960 LLVMTypeRef param_types[] = {
961 LLVMMetadataTypeInContext(LLVMGetGlobalContext()),
962 LLVMIntType(g->pointer_size_bytes * 8),
963 };
964
965 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
966 Buf *name = buf_sprintf("llvm.write_register.i%d", g->pointer_size_bytes * 8);
967 g->write_register_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
968 assert(LLVMGetIntrinsicID(g->write_register_fn_val));
969
970 return g->write_register_fn_val;
971}
972
926static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {973static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {
927 if (g->coro_destroy_fn_val)974 if (g->coro_destroy_fn_val)
928 return g->coro_destroy_fn_val;975 return g->coro_destroy_fn_val;
...@@ -2840,6 +2887,38 @@ static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {...@@ -2840,6 +2887,38 @@ static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
2840 return 1 + get_async_allocator_arg_index(g, fn_type_id);2887 return 1 + get_async_allocator_arg_index(g, fn_type_id);
2841}2888}
28422889
2890
2891static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {
2892 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");
2893 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");
2894
2895 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
2896 LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
2897
2898 LLVMValueRef ptr_addr = LLVMBuildPtrToInt(g->builder, ptr_value, LLVMTypeOf(len_value), "");
2899 LLVMValueRef end_addr = LLVMBuildNUWAdd(g->builder, ptr_addr, len_value, "");
2900 LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), get_abi_alignment(g, g->builtin_types.entry_usize), false);
2901 LLVMValueRef align_adj = LLVMBuildURem(g->builder, end_addr, align_amt, "");
2902 return LLVMBuildNUWSub(g->builder, end_addr, align_adj, "");
2903}
2904
2905static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) {
2906 LLVMValueRef write_register_fn_val = get_write_register_fn_val(g);
2907
2908 if (g->sp_md_node == nullptr) {
2909 Buf *sp_reg_name = buf_create_from_str(arch_stack_pointer_register_name(&g->zig_target.arch));
2910 LLVMValueRef str_node = LLVMMDString(buf_ptr(sp_reg_name), buf_len(sp_reg_name) + 1);
2911 g->sp_md_node = LLVMMDNode(&str_node, 1);
2912 }
2913
2914 LLVMValueRef params[] = {
2915 g->sp_md_node,
2916 aligned_end_addr,
2917 };
2918
2919 LLVMBuildCall(g->builder, write_register_fn_val, params, 2, "");
2920}
2921
2843static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {2922static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
2844 LLVMValueRef fn_val;2923 LLVMValueRef fn_val;
2845 TypeTableEntry *fn_type;2924 TypeTableEntry *fn_type;
...@@ -2906,13 +2985,28 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2906,13 +2985,28 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2906 }2985 }
29072986
2908 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);2987 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
2909 LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,2988 LLVMValueRef result;
2910 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");2989
2990 if (instruction->new_stack == nullptr) {
2991 result = ZigLLVMBuildCall(g->builder, fn_val,
2992 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
2993 } else {
2994 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
2995 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
2996
2997 LLVMValueRef new_stack_addr = get_new_stack_addr(g, ir_llvm_value(g, instruction->new_stack));
2998 LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, "");
2999 gen_set_stack_pointer(g, new_stack_addr);
3000 result = ZigLLVMBuildCall(g->builder, fn_val,
3001 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3002 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
3003 }
3004
29113005
2912 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {3006 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
2913 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];3007 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
2914 // Note: byval is disabled on windows due to an LLVM bug:3008 // Note: byval is disabled on windows due to an LLVM bug:
2915 // https://github.com/zig-lang/zig/issues/5363009 // https://github.com/ziglang/zig/issues/536
2916 if (gen_info->is_byval && g->zig_target.os != OsWindows) {3010 if (gen_info->is_byval && g->zig_target.os != OsWindows) {
2917 addLLVMCallsiteAttr(result, (unsigned)gen_info->gen_index, "byval");3011 addLLVMCallsiteAttr(result, (unsigned)gen_info->gen_index, "byval");
2918 }3012 }
...@@ -6086,6 +6180,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -6086,6 +6180,7 @@ static void define_builtin_fns(CodeGen *g) {
6086 create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2);6180 create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2);
6087 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);6181 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
6088 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);6182 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
6183 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
6089 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);6184 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
6090 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);6185 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
6091 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);6186 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
...@@ -6550,7 +6645,7 @@ static void init(CodeGen *g) {...@@ -6550,7 +6645,7 @@ static void init(CodeGen *g) {
6550 const char *target_specific_features;6645 const char *target_specific_features;
6551 if (g->is_native_target) {6646 if (g->is_native_target) {
6552 // LLVM creates invalid binaries on Windows sometimes.6647 // LLVM creates invalid binaries on Windows sometimes.
6553 // See https://github.com/zig-lang/zig/issues/5086648 // See https://github.com/ziglang/zig/issues/508
6554 // As a workaround we do not use target native features on Windows.6649 // As a workaround we do not use target native features on Windows.
6555 if (g->zig_target.os == OsWindows) {6650 if (g->zig_target.os == OsWindows) {
6556 target_specific_cpu_args = "";6651 target_specific_cpu_args = "";
src/ir.cpp+83-19
...@@ -1102,7 +1102,8 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio...@@ -1102,7 +1102,8 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
11021102
1103static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,1103static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
1104 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,1104 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1105 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)1105 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
1106 IrInstruction *new_stack)
1106{1107{
1107 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);1108 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
1108 call_instruction->fn_entry = fn_entry;1109 call_instruction->fn_entry = fn_entry;
...@@ -1113,6 +1114,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc...@@ -1113,6 +1114,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
1113 call_instruction->arg_count = arg_count;1114 call_instruction->arg_count = arg_count;
1114 call_instruction->is_async = is_async;1115 call_instruction->is_async = is_async;
1115 call_instruction->async_allocator = async_allocator;1116 call_instruction->async_allocator = async_allocator;
1117 call_instruction->new_stack = new_stack;
11161118
1117 if (fn_ref)1119 if (fn_ref)
1118 ir_ref_instruction(fn_ref, irb->current_basic_block);1120 ir_ref_instruction(fn_ref, irb->current_basic_block);
...@@ -1120,16 +1122,19 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc...@@ -1120,16 +1122,19 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
1120 ir_ref_instruction(args[i], irb->current_basic_block);1122 ir_ref_instruction(args[i], irb->current_basic_block);
1121 if (async_allocator)1123 if (async_allocator)
1122 ir_ref_instruction(async_allocator, irb->current_basic_block);1124 ir_ref_instruction(async_allocator, irb->current_basic_block);
1125 if (new_stack != nullptr)
1126 ir_ref_instruction(new_stack, irb->current_basic_block);
11231127
1124 return &call_instruction->base;1128 return &call_instruction->base;
1125}1129}
11261130
1127static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,1131static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
1128 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,1132 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1129 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)1133 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
1134 IrInstruction *new_stack)
1130{1135{
1131 IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,1136 IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,
1132 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator);1137 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator, new_stack);
1133 ir_link_new_instruction(new_instruction, old_instruction);1138 ir_link_new_instruction(new_instruction, old_instruction);
1134 return new_instruction;1139 return new_instruction;
1135}1140}
...@@ -4303,7 +4308,37 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4303,7 +4308,37 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4303 }4308 }
4304 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;4309 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
43054310
4306 IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr);4311 IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr);
4312 return ir_lval_wrap(irb, scope, call, lval);
4313 }
4314 case BuiltinFnIdNewStackCall:
4315 {
4316 if (node->data.fn_call_expr.params.length == 0) {
4317 add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));
4318 return irb->codegen->invalid_instruction;
4319 }
4320
4321 AstNode *new_stack_node = node->data.fn_call_expr.params.at(0);
4322 IrInstruction *new_stack = ir_gen_node(irb, new_stack_node, scope);
4323 if (new_stack == irb->codegen->invalid_instruction)
4324 return new_stack;
4325
4326 AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1);
4327 IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
4328 if (fn_ref == irb->codegen->invalid_instruction)
4329 return fn_ref;
4330
4331 size_t arg_count = node->data.fn_call_expr.params.length - 2;
4332
4333 IrInstruction **args = allocate<IrInstruction*>(arg_count);
4334 for (size_t i = 0; i < arg_count; i += 1) {
4335 AstNode *arg_node = node->data.fn_call_expr.params.at(i + 2);
4336 args[i] = ir_gen_node(irb, arg_node, scope);
4337 if (args[i] == irb->codegen->invalid_instruction)
4338 return args[i];
4339 }
4340
4341 IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack);
4307 return ir_lval_wrap(irb, scope, call, lval);4342 return ir_lval_wrap(irb, scope, call, lval);
4308 }4343 }
4309 case BuiltinFnIdTypeId:4344 case BuiltinFnIdTypeId:
...@@ -4513,7 +4548,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node...@@ -4513,7 +4548,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
4513 }4548 }
4514 }4549 }
45154550
4516 IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator);4551 IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
4517 return ir_lval_wrap(irb, scope, fn_call, lval);4552 return ir_lval_wrap(irb, scope, fn_call, lval);
4518}4553}
45194554
...@@ -4574,8 +4609,14 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode...@@ -4574,8 +4609,14 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
4574}4609}
45754610
4576static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) {4611static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) {
4577 assert(node->type == NodeTypePrefixOpExpr);4612 AstNode *expr_node;
4578 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;4613 if (node->type == NodeTypePrefixOpExpr) {
4614 expr_node = node->data.prefix_op_expr.primary_expr;
4615 } else if (node->type == NodeTypePtrDeref) {
4616 expr_node = node->data.ptr_deref_expr.target;
4617 } else {
4618 zig_unreachable();
4619 }
45794620
4580 IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);4621 IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
4581 if (value == irb->codegen->invalid_instruction)4622 if (value == irb->codegen->invalid_instruction)
...@@ -4716,8 +4757,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod...@@ -4716,8 +4757,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
4716 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);4757 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);
4717 case PrefixOpNegationWrap:4758 case PrefixOpNegationWrap:
4718 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);4759 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
4719 case PrefixOpDereference:
4720 return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
4721 case PrefixOpMaybe:4760 case PrefixOpMaybe:
4722 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);4761 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);
4723 case PrefixOpUnwrapMaybe:4762 case PrefixOpUnwrapMaybe:
...@@ -6553,6 +6592,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -6553,6 +6592,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
65536592
6554 return ir_build_load_ptr(irb, scope, node, ptr_instruction);6593 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
6555 }6594 }
6595 case NodeTypePtrDeref:
6596 return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
6556 case NodeTypeThisLiteral:6597 case NodeTypeThisLiteral:
6557 return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval);6598 return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval);
6558 case NodeTypeBoolLiteral:6599 case NodeTypeBoolLiteral:
...@@ -6825,7 +6866,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6825,7 +6866,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6825 IrInstruction **args = allocate<IrInstruction *>(arg_count);6866 IrInstruction **args = allocate<IrInstruction *>(arg_count);
6826 args[0] = implicit_allocator_ptr; // self6867 args[0] = implicit_allocator_ptr; // self
6827 args[1] = mem_slice; // old_mem6868 args[1] = mem_slice; // old_mem
6828 ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr);6869 ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr);
68296870
6830 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");6871 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
6831 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);6872 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
...@@ -8686,6 +8727,10 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_...@@ -8686,6 +8727,10 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_
8686 *dest = *src;8727 *dest = *src;
8687 if (!same_global_refs) {8728 if (!same_global_refs) {
8688 dest->global_refs = global_refs;8729 dest->global_refs = global_refs;
8730 if (dest->type->id == TypeTableEntryIdStruct) {
8731 dest->data.x_struct.fields = allocate_nonzero<ConstExprValue>(dest->type->data.structure.src_field_count);
8732 memcpy(dest->data.x_struct.fields, src->data.x_struct.fields, sizeof(ConstExprValue) * dest->type->data.structure.src_field_count);
8733 }
8689 }8734 }
8690}8735}
86918736
...@@ -11670,7 +11715,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -11670,7 +11715,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
11670 if (var->mem_slot_index != SIZE_MAX) {11715 if (var->mem_slot_index != SIZE_MAX) {
11671 assert(var->mem_slot_index < ira->exec_context.mem_slot_count);11716 assert(var->mem_slot_index < ira->exec_context.mem_slot_count);
11672 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];11717 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
11673 *mem_slot = casted_init_value->value;11718 copy_const_val(mem_slot, &casted_init_value->value,
11719 !is_comptime_var || var->gen_is_const);
1167411720
11675 if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {11721 if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
11676 ir_build_const_from(ira, &decl_var_instruction->base);11722 ir_build_const_from(ira, &decl_var_instruction->base);
...@@ -11987,7 +12033,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c...@@ -11987,7 +12033,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c
11987 TypeTableEntry *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);12033 TypeTableEntry *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
1198812034
11989 IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node,12035 IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node,
11990 fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst);12036 fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, nullptr);
11991 result->value.type = async_return_type;12037 result->value.type = async_return_type;
11992 return result;12038 return result;
11993}12039}
...@@ -12084,7 +12130,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -12084,7 +12130,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
12084 casted_arg->value.type->id == TypeTableEntryIdNumLitFloat)12130 casted_arg->value.type->id == TypeTableEntryIdNumLitFloat)
12085 {12131 {
12086 ir_add_error(ira, casted_arg,12132 ir_add_error(ira, casted_arg,
12087 buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/zig-lang/zig/issues/557"));12133 buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/ziglang/zig/issues/557"));
12088 return false;12134 return false;
12089 }12135 }
1209012136
...@@ -12285,7 +12331,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12285,7 +12331,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1228512331
12286 if (fn_proto_node->data.fn_proto.is_var_args) {12332 if (fn_proto_node->data.fn_proto.is_var_args) {
12287 ir_add_error(ira, &call_instruction->base,12333 ir_add_error(ira, &call_instruction->base,
12288 buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/zig-lang/zig/issues/313"));12334 buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/ziglang/zig/issues/313"));
12289 return ira->codegen->builtin_types.entry_invalid;12335 return ira->codegen->builtin_types.entry_invalid;
12290 }12336 }
1229112337
...@@ -12357,6 +12403,19 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12357,6 +12403,19 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
12357 return ir_finish_anal(ira, return_type);12403 return ir_finish_anal(ira, return_type);
12358 }12404 }
1235912405
12406 IrInstruction *casted_new_stack = nullptr;
12407 if (call_instruction->new_stack != nullptr) {
12408 TypeTableEntry *u8_ptr = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
12409 TypeTableEntry *u8_slice = get_slice_type(ira->codegen, u8_ptr);
12410 IrInstruction *new_stack = call_instruction->new_stack->other;
12411 if (type_is_invalid(new_stack->value.type))
12412 return ira->codegen->builtin_types.entry_invalid;
12413
12414 casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice);
12415 if (type_is_invalid(casted_new_stack->value.type))
12416 return ira->codegen->builtin_types.entry_invalid;
12417 }
12418
12360 if (fn_type->data.fn.is_generic) {12419 if (fn_type->data.fn.is_generic) {
12361 if (!fn_entry) {12420 if (!fn_entry) {
12362 ir_add_error(ira, call_instruction->fn_ref,12421 ir_add_error(ira, call_instruction->fn_ref,
...@@ -12365,7 +12424,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12365,7 +12424,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
12365 }12424 }
12366 if (call_instruction->is_async && fn_type_id->is_var_args) {12425 if (call_instruction->is_async && fn_type_id->is_var_args) {
12367 ir_add_error(ira, call_instruction->fn_ref,12426 ir_add_error(ira, call_instruction->fn_ref,
12368 buf_sprintf("compiler bug: TODO: implement var args async functions. https://github.com/zig-lang/zig/issues/557"));12427 buf_sprintf("compiler bug: TODO: implement var args async functions. https://github.com/ziglang/zig/issues/557"));
12369 return ira->codegen->builtin_types.entry_invalid;12428 return ira->codegen->builtin_types.entry_invalid;
12370 }12429 }
1237112430
...@@ -12448,7 +12507,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12448,7 +12507,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
12448 VariableTableEntry *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);12507 VariableTableEntry *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
12449 if (arg_var == nullptr) {12508 if (arg_var == nullptr) {
12450 ir_add_error(ira, arg,12509 ir_add_error(ira, arg,
12451 buf_sprintf("compiler bug: var args can't handle void. https://github.com/zig-lang/zig/issues/557"));12510 buf_sprintf("compiler bug: var args can't handle void. https://github.com/ziglang/zig/issues/557"));
12452 return ira->codegen->builtin_types.entry_invalid;12511 return ira->codegen->builtin_types.entry_invalid;
12453 }12512 }
12454 IrInstruction *arg_var_ptr_inst = ir_get_var_ptr(ira, arg, arg_var, true, false);12513 IrInstruction *arg_var_ptr_inst = ir_get_var_ptr(ira, arg, arg_var, true, false);
...@@ -12583,7 +12642,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12583,7 +12642,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
12583 assert(async_allocator_inst == nullptr);12642 assert(async_allocator_inst == nullptr);
12584 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,12643 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
12585 impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,12644 impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
12586 call_instruction->is_async, nullptr);12645 call_instruction->is_async, nullptr, casted_new_stack);
1258712646
12588 ir_add_alloca(ira, new_call_instruction, return_type);12647 ir_add_alloca(ira, new_call_instruction, return_type);
1258912648
...@@ -12674,7 +12733,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12674,7 +12733,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1267412733
1267512734
12676 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,12735 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
12677 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr);12736 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, casted_new_stack);
1267812737
12679 ir_add_alloca(ira, new_call_instruction, return_type);12738 ir_add_alloca(ira, new_call_instruction, return_type);
12680 return ir_finish_anal(ira, return_type);12739 return ir_finish_anal(ira, return_type);
...@@ -16496,6 +16555,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -16496,6 +16555,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
16496 {16555 {
16497 size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index);16556 size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index);
16498 inner_fields[1].data.x_maybe = create_const_vals(1);16557 inner_fields[1].data.x_maybe = create_const_vals(1);
16558 inner_fields[1].data.x_maybe->special = ConstValSpecialStatic;
16499 inner_fields[1].data.x_maybe->type = ira->codegen->builtin_types.entry_usize;16559 inner_fields[1].data.x_maybe->type = ira->codegen->builtin_types.entry_usize;
16500 bigint_init_unsigned(&inner_fields[1].data.x_maybe->data.x_bigint, byte_offset);16560 bigint_init_unsigned(&inner_fields[1].data.x_maybe->data.x_bigint, byte_offset);
16501 }16561 }
...@@ -18030,7 +18090,11 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira...@@ -18030,7 +18090,11 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
18030 if (type_is_invalid(end_value->value.type))18090 if (type_is_invalid(end_value->value.type))
18031 return ira->codegen->builtin_types.entry_invalid;18091 return ira->codegen->builtin_types.entry_invalid;
1803218092
18033 assert(start_value->value.type->id == TypeTableEntryIdEnum);18093 if (start_value->value.type->id != TypeTableEntryIdEnum) {
18094 ir_add_error(ira, range->start, buf_sprintf("not an enum type"));
18095 return ira->codegen->builtin_types.entry_invalid;
18096 }
18097
18034 BigInt start_index;18098 BigInt start_index;
18035 bigint_init_bigint(&start_index, &start_value->value.data.x_enum_tag);18099 bigint_init_bigint(&start_index, &start_value->value.data.x_enum_tag);
1803618100
src/parser.cpp+25-18
...@@ -1046,11 +1046,12 @@ static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index...@@ -1046,11 +1046,12 @@ static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index
1046}1046}
10471047
1048/*1048/*
1049SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)1049SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | PtrDerefExpression | SliceExpression)
1050FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)1050FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
1051ArrayAccessExpression : token(LBracket) Expression token(RBracket)1051ArrayAccessExpression : token(LBracket) Expression token(RBracket)
1052SliceExpression = "[" Expression ".." option(Expression) "]"1052SliceExpression = "[" Expression ".." option(Expression) "]"
1053FieldAccessExpression : token(Dot) token(Symbol)1053FieldAccessExpression : token(Dot) token(Symbol)
1054PtrDerefExpression = ".*"
1054StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression1055StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
1055*/1056*/
1056static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1057static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
...@@ -1131,13 +1132,27 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,...@@ -1131,13 +1132,27 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
1131 } else if (first_token->id == TokenIdDot) {1132 } else if (first_token->id == TokenIdDot) {
1132 *token_index += 1;1133 *token_index += 1;
11331134
1134 Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);1135 Token *token = &pc->tokens->at(*token_index);
1136
1137 if (token->id == TokenIdSymbol) {
1138 *token_index += 1;
11351139
1136 AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);1140 AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
1137 node->data.field_access_expr.struct_expr = primary_expr;1141 node->data.field_access_expr.struct_expr = primary_expr;
1138 node->data.field_access_expr.field_name = token_buf(name_token);1142 node->data.field_access_expr.field_name = token_buf(token);
1143
1144 primary_expr = node;
1145 } else if (token->id == TokenIdStar) {
1146 *token_index += 1;
1147
1148 AstNode *node = ast_create_node(pc, NodeTypePtrDeref, first_token);
1149 node->data.ptr_deref_expr.target = primary_expr;
1150
1151 primary_expr = node;
1152 } else {
1153 ast_invalid_token_error(pc, token);
1154 }
11391155
1140 primary_expr = node;
1141 } else {1156 } else {
1142 return primary_expr;1157 return primary_expr;
1143 }1158 }
...@@ -1150,10 +1165,8 @@ static PrefixOp tok_to_prefix_op(Token *token) {...@@ -1150,10 +1165,8 @@ static PrefixOp tok_to_prefix_op(Token *token) {
1150 case TokenIdDash: return PrefixOpNegation;1165 case TokenIdDash: return PrefixOpNegation;
1151 case TokenIdMinusPercent: return PrefixOpNegationWrap;1166 case TokenIdMinusPercent: return PrefixOpNegationWrap;
1152 case TokenIdTilde: return PrefixOpBinNot;1167 case TokenIdTilde: return PrefixOpBinNot;
1153 case TokenIdStar: return PrefixOpDereference;
1154 case TokenIdMaybe: return PrefixOpMaybe;1168 case TokenIdMaybe: return PrefixOpMaybe;
1155 case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;1169 case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
1156 case TokenIdStarStar: return PrefixOpDereference;
1157 default: return PrefixOpInvalid;1170 default: return PrefixOpInvalid;
1158 }1171 }
1159}1172}
...@@ -1199,7 +1212,7 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {...@@ -1199,7 +1212,7 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
11991212
1200/*1213/*
1201PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression1214PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
1202PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"1215PrefixOp = "!" | "-" | "~" | ("*" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
1203*/1216*/
1204static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1217static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
1205 Token *token = &pc->tokens->at(*token_index);1218 Token *token = &pc->tokens->at(*token_index);
...@@ -1222,15 +1235,6 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,...@@ -1222,15 +1235,6 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,
12221235
1223 AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);1236 AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
1224 AstNode *parent_node = node;1237 AstNode *parent_node = node;
1225 if (token->id == TokenIdStarStar) {
1226 // pretend that we got 2 star tokens
1227
1228 parent_node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
1229 parent_node->data.prefix_op_expr.primary_expr = node;
1230 parent_node->data.prefix_op_expr.prefix_op = PrefixOpDereference;
1231
1232 node->column += 1;
1233 }
12341238
1235 AstNode *prefix_op_expr = ast_parse_error_set_expr(pc, token_index, true);1239 AstNode *prefix_op_expr = ast_parse_error_set_expr(pc, token_index, true);
1236 node->data.prefix_op_expr.primary_expr = prefix_op_expr;1240 node->data.prefix_op_expr.primary_expr = prefix_op_expr;
...@@ -3012,6 +3016,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -3012,6 +3016,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
3012 case NodeTypeFieldAccessExpr:3016 case NodeTypeFieldAccessExpr:
3013 visit_field(&node->data.field_access_expr.struct_expr, visit, context);3017 visit_field(&node->data.field_access_expr.struct_expr, visit, context);
3014 break;3018 break;
3019 case NodeTypePtrDeref:
3020 visit_field(&node->data.ptr_deref_expr.target, visit, context);
3021 break;
3015 case NodeTypeUse:3022 case NodeTypeUse:
3016 visit_field(&node->data.use.expr, visit, context);3023 visit_field(&node->data.use.expr, visit, context);
3017 break;3024 break;
src/target.cpp+63-1
...@@ -701,6 +701,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {...@@ -701,6 +701,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
701 case OsLinux:701 case OsLinux:
702 case OsMacOSX:702 case OsMacOSX:
703 case OsZen:703 case OsZen:
704 case OsOpenBSD:
704 switch (id) {705 switch (id) {
705 case CIntTypeShort:706 case CIntTypeShort:
706 case CIntTypeUShort:707 case CIntTypeUShort:
...@@ -741,7 +742,6 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {...@@ -741,7 +742,6 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
741 case OsKFreeBSD:742 case OsKFreeBSD:
742 case OsLv2:743 case OsLv2:
743 case OsNetBSD:744 case OsNetBSD:
744 case OsOpenBSD:
745 case OsSolaris:745 case OsSolaris:
746 case OsHaiku:746 case OsHaiku:
747 case OsMinix:747 case OsMinix:
...@@ -895,3 +895,65 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target...@@ -895,3 +895,65 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target
895895
896 return false;896 return false;
897}897}
898
899const char *arch_stack_pointer_register_name(const ArchType *arch) {
900 switch (arch->arch) {
901 case ZigLLVM_UnknownArch:
902 zig_unreachable();
903 case ZigLLVM_x86:
904 return "sp";
905 case ZigLLVM_x86_64:
906 return "rsp";
907
908 case ZigLLVM_aarch64:
909 case ZigLLVM_arm:
910 case ZigLLVM_thumb:
911 case ZigLLVM_aarch64_be:
912 case ZigLLVM_amdgcn:
913 case ZigLLVM_amdil:
914 case ZigLLVM_amdil64:
915 case ZigLLVM_armeb:
916 case ZigLLVM_arc:
917 case ZigLLVM_avr:
918 case ZigLLVM_bpfeb:
919 case ZigLLVM_bpfel:
920 case ZigLLVM_hexagon:
921 case ZigLLVM_lanai:
922 case ZigLLVM_hsail:
923 case ZigLLVM_hsail64:
924 case ZigLLVM_kalimba:
925 case ZigLLVM_le32:
926 case ZigLLVM_le64:
927 case ZigLLVM_mips:
928 case ZigLLVM_mips64:
929 case ZigLLVM_mips64el:
930 case ZigLLVM_mipsel:
931 case ZigLLVM_msp430:
932 case ZigLLVM_nios2:
933 case ZigLLVM_nvptx:
934 case ZigLLVM_nvptx64:
935 case ZigLLVM_ppc64le:
936 case ZigLLVM_r600:
937 case ZigLLVM_renderscript32:
938 case ZigLLVM_renderscript64:
939 case ZigLLVM_riscv32:
940 case ZigLLVM_riscv64:
941 case ZigLLVM_shave:
942 case ZigLLVM_sparc:
943 case ZigLLVM_sparcel:
944 case ZigLLVM_sparcv9:
945 case ZigLLVM_spir:
946 case ZigLLVM_spir64:
947 case ZigLLVM_systemz:
948 case ZigLLVM_tce:
949 case ZigLLVM_tcele:
950 case ZigLLVM_thumbeb:
951 case ZigLLVM_wasm32:
952 case ZigLLVM_wasm64:
953 case ZigLLVM_xcore:
954 case ZigLLVM_ppc:
955 case ZigLLVM_ppc64:
956 zig_panic("TODO populate this table with stack pointer register name for this CPU architecture");
957 }
958 zig_unreachable();
959}
src/target.hpp+2
...@@ -78,6 +78,8 @@ size_t target_arch_count(void);...@@ -78,6 +78,8 @@ size_t target_arch_count(void);
78const ArchType *get_target_arch(size_t index);78const ArchType *get_target_arch(size_t index);
79void get_arch_name(char *out_str, const ArchType *arch);79void get_arch_name(char *out_str, const ArchType *arch);
8080
81const char *arch_stack_pointer_register_name(const ArchType *arch);
82
81size_t target_vendor_count(void);83size_t target_vendor_count(void);
82ZigLLVM_VendorType get_target_vendor(size_t index);84ZigLLVM_VendorType get_target_vendor(size_t index);
8385
src/translate_c.cpp+53-30
...@@ -247,6 +247,12 @@ static AstNode *trans_create_node_field_access_str(Context *c, AstNode *containe...@@ -247,6 +247,12 @@ static AstNode *trans_create_node_field_access_str(Context *c, AstNode *containe
247 return trans_create_node_field_access(c, container, buf_create_from_str(field_name));247 return trans_create_node_field_access(c, container, buf_create_from_str(field_name));
248}248}
249249
250static AstNode *trans_create_node_ptr_deref(Context *c, AstNode *child_node) {
251 AstNode *node = trans_create_node(c, NodeTypePtrDeref);
252 node->data.ptr_deref_expr.target = child_node;
253 return node;
254}
255
250static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) {256static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) {
251 AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr);257 AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr);
252 node->data.prefix_op_expr.prefix_op = op;258 node->data.prefix_op_expr.prefix_op = op;
...@@ -1413,8 +1419,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result...@@ -1413,8 +1419,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
1413 AstNode *operation_type_cast = trans_c_cast(c, rhs_location,1419 AstNode *operation_type_cast = trans_c_cast(c, rhs_location,
1414 stmt->getComputationLHSType(),1420 stmt->getComputationLHSType(),
1415 stmt->getLHS()->getType(),1421 stmt->getLHS()->getType(),
1416 trans_create_node_prefix_op(c, PrefixOpDereference,1422 trans_create_node_ptr_deref(c, trans_create_node_symbol(c, tmp_var_name)));
1417 trans_create_node_symbol(c, tmp_var_name)));
14181423
1419 // result_type(... >> u5(rhs))1424 // result_type(... >> u5(rhs))
1420 AstNode *result_type_cast = trans_c_cast(c, rhs_location,1425 AstNode *result_type_cast = trans_c_cast(c, rhs_location,
...@@ -1427,7 +1432,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result...@@ -1427,7 +1432,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
14271432
1428 // *_ref = ...1433 // *_ref = ...
1429 AstNode *assign_statement = trans_create_node_bin_op(c,1434 AstNode *assign_statement = trans_create_node_bin_op(c,
1430 trans_create_node_prefix_op(c, PrefixOpDereference,1435 trans_create_node_ptr_deref(c,
1431 trans_create_node_symbol(c, tmp_var_name)),1436 trans_create_node_symbol(c, tmp_var_name)),
1432 BinOpTypeAssign, result_type_cast);1437 BinOpTypeAssign, result_type_cast);
14331438
...@@ -1437,7 +1442,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result...@@ -1437,7 +1442,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
1437 // break :x *_ref1442 // break :x *_ref
1438 child_scope->node->data.block.statements.append(1443 child_scope->node->data.block.statements.append(
1439 trans_create_node_break(c, label_name,1444 trans_create_node_break(c, label_name,
1440 trans_create_node_prefix_op(c, PrefixOpDereference,1445 trans_create_node_ptr_deref(c,
1441 trans_create_node_symbol(c, tmp_var_name))));1446 trans_create_node_symbol(c, tmp_var_name))));
1442 }1447 }
14431448
...@@ -1484,11 +1489,11 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,...@@ -1484,11 +1489,11 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
1484 if (rhs == nullptr) return nullptr;1489 if (rhs == nullptr) return nullptr;
14851490
1486 AstNode *assign_statement = trans_create_node_bin_op(c,1491 AstNode *assign_statement = trans_create_node_bin_op(c,
1487 trans_create_node_prefix_op(c, PrefixOpDereference,1492 trans_create_node_ptr_deref(c,
1488 trans_create_node_symbol(c, tmp_var_name)),1493 trans_create_node_symbol(c, tmp_var_name)),
1489 BinOpTypeAssign,1494 BinOpTypeAssign,
1490 trans_create_node_bin_op(c,1495 trans_create_node_bin_op(c,
1491 trans_create_node_prefix_op(c, PrefixOpDereference,1496 trans_create_node_ptr_deref(c,
1492 trans_create_node_symbol(c, tmp_var_name)),1497 trans_create_node_symbol(c, tmp_var_name)),
1493 bin_op,1498 bin_op,
1494 rhs));1499 rhs));
...@@ -1497,7 +1502,7 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,...@@ -1497,7 +1502,7 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
1497 // break :x *_ref1502 // break :x *_ref
1498 child_scope->node->data.block.statements.append(1503 child_scope->node->data.block.statements.append(
1499 trans_create_node_break(c, label_name,1504 trans_create_node_break(c, label_name,
1500 trans_create_node_prefix_op(c, PrefixOpDereference,1505 trans_create_node_ptr_deref(c,
1501 trans_create_node_symbol(c, tmp_var_name))));1506 trans_create_node_symbol(c, tmp_var_name))));
15021507
1503 return child_scope->node;1508 return child_scope->node;
...@@ -1818,13 +1823,13 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr...@@ -1818,13 +1823,13 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
1818 // const _tmp = *_ref;1823 // const _tmp = *_ref;
1819 Buf* tmp_var_name = buf_create_from_str("_tmp");1824 Buf* tmp_var_name = buf_create_from_str("_tmp");
1820 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,1825 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
1821 trans_create_node_prefix_op(c, PrefixOpDereference,1826 trans_create_node_ptr_deref(c,
1822 trans_create_node_symbol(c, ref_var_name)));1827 trans_create_node_symbol(c, ref_var_name)));
1823 child_scope->node->data.block.statements.append(tmp_var_decl);1828 child_scope->node->data.block.statements.append(tmp_var_decl);
18241829
1825 // *_ref += 1;1830 // *_ref += 1;
1826 AstNode *assign_statement = trans_create_node_bin_op(c,1831 AstNode *assign_statement = trans_create_node_bin_op(c,
1827 trans_create_node_prefix_op(c, PrefixOpDereference,1832 trans_create_node_ptr_deref(c,
1828 trans_create_node_symbol(c, ref_var_name)),1833 trans_create_node_symbol(c, ref_var_name)),
1829 assign_op,1834 assign_op,
1830 trans_create_node_unsigned(c, 1));1835 trans_create_node_unsigned(c, 1));
...@@ -1872,14 +1877,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra...@@ -1872,14 +1877,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
18721877
1873 // *_ref += 1;1878 // *_ref += 1;
1874 AstNode *assign_statement = trans_create_node_bin_op(c,1879 AstNode *assign_statement = trans_create_node_bin_op(c,
1875 trans_create_node_prefix_op(c, PrefixOpDereference,1880 trans_create_node_ptr_deref(c,
1876 trans_create_node_symbol(c, ref_var_name)),1881 trans_create_node_symbol(c, ref_var_name)),
1877 assign_op,1882 assign_op,
1878 trans_create_node_unsigned(c, 1));1883 trans_create_node_unsigned(c, 1));
1879 child_scope->node->data.block.statements.append(assign_statement);1884 child_scope->node->data.block.statements.append(assign_statement);
18801885
1881 // break :x *_ref1886 // break :x *_ref
1882 AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,1887 AstNode *deref_expr = trans_create_node_ptr_deref(c,
1883 trans_create_node_symbol(c, ref_var_name));1888 trans_create_node_symbol(c, ref_var_name));
1884 child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr));1889 child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr));
18851890
...@@ -1924,7 +1929,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc...@@ -1924,7 +1929,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
1924 if (is_fn_ptr)1929 if (is_fn_ptr)
1925 return value_node;1930 return value_node;
1926 AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);1931 AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
1927 return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped);1932 return trans_create_node_ptr_deref(c, unwrapped);
1928 }1933 }
1929 case UO_Plus:1934 case UO_Plus:
1930 emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus");1935 emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus");
...@@ -4445,27 +4450,45 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t...@@ -4445,27 +4450,45 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t
4445 }4450 }
4446}4451}
44474452
4448static PrefixOp ctok_to_prefix_op(CTok *token) {
4449 switch (token->id) {
4450 case CTokIdBang: return PrefixOpBoolNot;
4451 case CTokIdMinus: return PrefixOpNegation;
4452 case CTokIdTilde: return PrefixOpBinNot;
4453 case CTokIdAsterisk: return PrefixOpDereference;
4454 default: return PrefixOpInvalid;
4455 }
4456}
4457static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) {4453static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) {
4458 CTok *op_tok = &ctok->tokens.at(*tok_i);4454 CTok *op_tok = &ctok->tokens.at(*tok_i);
4459 PrefixOp prefix_op = ctok_to_prefix_op(op_tok);
4460 if (prefix_op == PrefixOpInvalid) {
4461 return parse_ctok_suffix_op_expr(c, ctok, tok_i);
4462 }
4463 *tok_i += 1;
44644455
4465 AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);4456 switch (op_tok->id) {
4466 if (prefix_op_expr == nullptr)4457 case CTokIdBang:
4467 return nullptr;4458 {
4468 return trans_create_node_prefix_op(c, prefix_op, prefix_op_expr);4459 *tok_i += 1;
4460 AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
4461 if (prefix_op_expr == nullptr)
4462 return nullptr;
4463 return trans_create_node_prefix_op(c, PrefixOpBoolNot, prefix_op_expr);
4464 }
4465 case CTokIdMinus:
4466 {
4467 *tok_i += 1;
4468 AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
4469 if (prefix_op_expr == nullptr)
4470 return nullptr;
4471 return trans_create_node_prefix_op(c, PrefixOpNegation, prefix_op_expr);
4472 }
4473 case CTokIdTilde:
4474 {
4475 *tok_i += 1;
4476 AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
4477 if (prefix_op_expr == nullptr)
4478 return nullptr;
4479 return trans_create_node_prefix_op(c, PrefixOpBinNot, prefix_op_expr);
4480 }
4481 case CTokIdAsterisk:
4482 {
4483 *tok_i += 1;
4484 AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i);
4485 if (prefix_op_expr == nullptr)
4486 return nullptr;
4487 return trans_create_node_ptr_deref(c, prefix_op_expr);
4488 }
4489 default:
4490 return parse_ctok_suffix_op_expr(c, ctok, tok_i);
4491 }
4469}4492}
44704493
4471static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) {4494static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) {
std/array_list.zig+33-21
...@@ -8,7 +8,7 @@ pub fn ArrayList(comptime T: type) type {...@@ -8,7 +8,7 @@ pub fn ArrayList(comptime T: type) type {
8 return AlignedArrayList(T, @alignOf(T));8 return AlignedArrayList(T, @alignOf(T));
9}9}
1010
11pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{11pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
12 return struct {12 return struct {
13 const Self = this;13 const Self = this;
1414
...@@ -21,7 +21,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -21,7 +21,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
2121
22 /// Deinitialize with `deinit` or use `toOwnedSlice`.22 /// Deinitialize with `deinit` or use `toOwnedSlice`.
23 pub fn init(allocator: &Allocator) Self {23 pub fn init(allocator: &Allocator) Self {
24 return Self {24 return Self{
25 .items = []align(A) T{},25 .items = []align(A) T{},
26 .len = 0,26 .len = 0,
27 .allocator = allocator,27 .allocator = allocator,
...@@ -52,7 +52,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -52,7 +52,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
52 /// allocated with `allocator`.52 /// allocated with `allocator`.
53 /// Deinitialize with `deinit` or use `toOwnedSlice`.53 /// Deinitialize with `deinit` or use `toOwnedSlice`.
54 pub fn fromOwnedSlice(allocator: &Allocator, slice: []align(A) T) Self {54 pub fn fromOwnedSlice(allocator: &Allocator, slice: []align(A) T) Self {
55 return Self {55 return Self{
56 .items = slice,56 .items = slice,
57 .len = slice.len,57 .len = slice.len,
58 .allocator = allocator,58 .allocator = allocator,
...@@ -63,7 +63,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -63,7 +63,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
63 pub fn toOwnedSlice(self: &Self) []align(A) T {63 pub fn toOwnedSlice(self: &Self) []align(A) T {
64 const allocator = self.allocator;64 const allocator = self.allocator;
65 const result = allocator.alignedShrink(T, A, self.items, self.len);65 const result = allocator.alignedShrink(T, A, self.items, self.len);
66 *self = init(allocator);66 self.* = init(allocator);
67 return result;67 return result;
68 }68 }
6969
...@@ -71,21 +71,21 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -71,21 +71,21 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
71 try l.ensureCapacity(l.len + 1);71 try l.ensureCapacity(l.len + 1);
72 l.len += 1;72 l.len += 1;
7373
74 mem.copy(T, l.items[n+1..l.len], l.items[n..l.len-1]);74 mem.copy(T, l.items[n + 1..l.len], l.items[n..l.len - 1]);
75 l.items[n] = *item;75 l.items[n] = item.*;
76 }76 }
7777
78 pub fn insertSlice(l: &Self, n: usize, items: []align(A) const T) !void {78 pub fn insertSlice(l: &Self, n: usize, items: []align(A) const T) !void {
79 try l.ensureCapacity(l.len + items.len);79 try l.ensureCapacity(l.len + items.len);
80 l.len += items.len;80 l.len += items.len;
8181
82 mem.copy(T, l.items[n+items.len..l.len], l.items[n..l.len-items.len]);82 mem.copy(T, l.items[n + items.len..l.len], l.items[n..l.len - items.len]);
83 mem.copy(T, l.items[n..n+items.len], items);83 mem.copy(T, l.items[n..n + items.len], items);
84 }84 }
8585
86 pub fn append(l: &Self, item: &const T) !void {86 pub fn append(l: &Self, item: &const T) !void {
87 const new_item_ptr = try l.addOne();87 const new_item_ptr = try l.addOne();
88 *new_item_ptr = *item;88 new_item_ptr.* = item.*;
89 }89 }
9090
91 pub fn appendSlice(l: &Self, items: []align(A) const T) !void {91 pub fn appendSlice(l: &Self, items: []align(A) const T) !void {
...@@ -128,8 +128,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{...@@ -128,8 +128,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
128 }128 }
129129
130 pub fn popOrNull(self: &Self) ?T {130 pub fn popOrNull(self: &Self) ?T {
131 if (self.len == 0)131 if (self.len == 0) return null;
132 return null;
133 return self.pop();132 return self.pop();
134 }133 }
135134
...@@ -160,13 +159,19 @@ test "basic ArrayList test" {...@@ -160,13 +159,19 @@ test "basic ArrayList test" {
160 var list = ArrayList(i32).init(debug.global_allocator);159 var list = ArrayList(i32).init(debug.global_allocator);
161 defer list.deinit();160 defer list.deinit();
162161
163 {var i: usize = 0; while (i < 10) : (i += 1) {162 {
164 list.append(i32(i + 1)) catch unreachable;163 var i: usize = 0;
165 }}164 while (i < 10) : (i += 1) {
165 list.append(i32(i + 1)) catch unreachable;
166 }
167 }
166168
167 {var i: usize = 0; while (i < 10) : (i += 1) {169 {
168 assert(list.items[i] == i32(i + 1));170 var i: usize = 0;
169 }}171 while (i < 10) : (i += 1) {
172 assert(list.items[i] == i32(i + 1));
173 }
174 }
170175
171 for (list.toSlice()) |v, i| {176 for (list.toSlice()) |v, i| {
172 assert(v == i32(i + 1));177 assert(v == i32(i + 1));
...@@ -179,14 +184,18 @@ test "basic ArrayList test" {...@@ -179,14 +184,18 @@ test "basic ArrayList test" {
179 assert(list.pop() == 10);184 assert(list.pop() == 10);
180 assert(list.len == 9);185 assert(list.len == 9);
181186
182 list.appendSlice([]const i32 { 1, 2, 3 }) catch unreachable;187 list.appendSlice([]const i32{
188 1,
189 2,
190 3,
191 }) catch unreachable;
183 assert(list.len == 12);192 assert(list.len == 12);
184 assert(list.pop() == 3);193 assert(list.pop() == 3);
185 assert(list.pop() == 2);194 assert(list.pop() == 2);
186 assert(list.pop() == 1);195 assert(list.pop() == 1);
187 assert(list.len == 9);196 assert(list.len == 9);
188197
189 list.appendSlice([]const i32 {}) catch unreachable;198 list.appendSlice([]const i32{}) catch unreachable;
190 assert(list.len == 9);199 assert(list.len == 9);
191}200}
192201
...@@ -228,12 +237,15 @@ test "insert ArrayList test" {...@@ -228,12 +237,15 @@ test "insert ArrayList test" {
228 assert(list.items[0] == 5);237 assert(list.items[0] == 5);
229 assert(list.items[1] == 1);238 assert(list.items[1] == 1);
230239
231 try list.insertSlice(1, []const i32 { 9, 8 });240 try list.insertSlice(1, []const i32{
241 9,
242 8,
243 });
232 assert(list.items[0] == 5);244 assert(list.items[0] == 5);
233 assert(list.items[1] == 9);245 assert(list.items[1] == 9);
234 assert(list.items[2] == 8);246 assert(list.items[2] == 8);
235247
236 const items = []const i32 { 1 };248 const items = []const i32{1};
237 try list.insertSlice(0, items[0..0]);249 try list.insertSlice(0, items[0..0]);
238 assert(list.items[0] == 5);250 assert(list.items[0] == 5);
239}251}
std/atomic/queue.zig+8-6
...@@ -16,7 +16,7 @@ pub fn Queue(comptime T: type) type {...@@ -16,7 +16,7 @@ pub fn Queue(comptime T: type) type {
16 data: T,16 data: T,
17 };17 };
1818
19 // TODO: well defined copy elision: https://github.com/zig-lang/zig/issues/28719 // TODO: well defined copy elision: https://github.com/ziglang/zig/issues/287
20 pub fn init(self: &Self) void {20 pub fn init(self: &Self) void {
21 self.root.next = null;21 self.root.next = null;
22 self.head = &self.root;22 self.head = &self.root;
...@@ -70,7 +70,7 @@ test "std.atomic.queue" {...@@ -70,7 +70,7 @@ test "std.atomic.queue" {
7070
71 var queue: Queue(i32) = undefined;71 var queue: Queue(i32) = undefined;
72 queue.init();72 queue.init();
73 var context = Context {73 var context = Context{
74 .allocator = a,74 .allocator = a,
75 .queue = &queue,75 .queue = &queue,
76 .put_sum = 0,76 .put_sum = 0,
...@@ -81,16 +81,18 @@ test "std.atomic.queue" {...@@ -81,16 +81,18 @@ test "std.atomic.queue" {
8181
82 var putters: [put_thread_count]&std.os.Thread = undefined;82 var putters: [put_thread_count]&std.os.Thread = undefined;
83 for (putters) |*t| {83 for (putters) |*t| {
84 *t = try std.os.spawnThread(&context, startPuts);84 t.* = try std.os.spawnThread(&context, startPuts);
85 }85 }
86 var getters: [put_thread_count]&std.os.Thread = undefined;86 var getters: [put_thread_count]&std.os.Thread = undefined;
87 for (getters) |*t| {87 for (getters) |*t| {
88 *t = try std.os.spawnThread(&context, startGets);88 t.* = try std.os.spawnThread(&context, startGets);
89 }89 }
9090
91 for (putters) |t| t.wait();91 for (putters) |t|
92 t.wait();
92 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);93 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
93 for (getters) |t| t.wait();94 for (getters) |t|
95 t.wait();
9496
95 std.debug.assert(context.put_sum == context.get_sum);97 std.debug.assert(context.put_sum == context.get_sum);
96 std.debug.assert(context.get_count == puts_per_thread * put_thread_count);98 std.debug.assert(context.get_count == puts_per_thread * put_thread_count);
std/atomic/stack.zig+8-8
...@@ -14,9 +14,7 @@ pub fn Stack(comptime T: type) type {...@@ -14,9 +14,7 @@ pub fn Stack(comptime T: type) type {
14 };14 };
1515
16 pub fn init() Self {16 pub fn init() Self {
17 return Self {17 return Self{ .root = null };
18 .root = null,
19 };
20 }18 }
2119
22 /// push operation, but only if you are the first item in the stack. if you did not succeed in20 /// push operation, but only if you are the first item in the stack. if you did not succeed in
...@@ -75,7 +73,7 @@ test "std.atomic.stack" {...@@ -75,7 +73,7 @@ test "std.atomic.stack" {
75 var a = &fixed_buffer_allocator.allocator;73 var a = &fixed_buffer_allocator.allocator;
7674
77 var stack = Stack(i32).init();75 var stack = Stack(i32).init();
78 var context = Context {76 var context = Context{
79 .allocator = a,77 .allocator = a,
80 .stack = &stack,78 .stack = &stack,
81 .put_sum = 0,79 .put_sum = 0,
...@@ -86,16 +84,18 @@ test "std.atomic.stack" {...@@ -86,16 +84,18 @@ test "std.atomic.stack" {
8684
87 var putters: [put_thread_count]&std.os.Thread = undefined;85 var putters: [put_thread_count]&std.os.Thread = undefined;
88 for (putters) |*t| {86 for (putters) |*t| {
89 *t = try std.os.spawnThread(&context, startPuts);87 t.* = try std.os.spawnThread(&context, startPuts);
90 }88 }
91 var getters: [put_thread_count]&std.os.Thread = undefined;89 var getters: [put_thread_count]&std.os.Thread = undefined;
92 for (getters) |*t| {90 for (getters) |*t| {
93 *t = try std.os.spawnThread(&context, startGets);91 t.* = try std.os.spawnThread(&context, startGets);
94 }92 }
9593
96 for (putters) |t| t.wait();94 for (putters) |t|
95 t.wait();
97 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);96 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
98 for (getters) |t| t.wait();97 for (getters) |t|
98 t.wait();
9999
100 std.debug.assert(context.put_sum == context.get_sum);100 std.debug.assert(context.put_sum == context.get_sum);
101 std.debug.assert(context.get_count == puts_per_thread * put_thread_count);101 std.debug.assert(context.get_count == puts_per_thread * put_thread_count);
std/buffer.zig+7-28
...@@ -31,9 +31,7 @@ pub const Buffer = struct {...@@ -31,9 +31,7 @@ pub const Buffer = struct {
31 /// * ::replaceContentsBuffer31 /// * ::replaceContentsBuffer
32 /// * ::resize32 /// * ::resize
33 pub fn initNull(allocator: &Allocator) Buffer {33 pub fn initNull(allocator: &Allocator) Buffer {
34 return Buffer {34 return Buffer{ .list = ArrayList(u8).init(allocator) };
35 .list = ArrayList(u8).init(allocator),
36 };
37 }35 }
3836
39 /// Must deinitialize with deinit.37 /// Must deinitialize with deinit.
...@@ -45,9 +43,7 @@ pub const Buffer = struct {...@@ -45,9 +43,7 @@ pub const Buffer = struct {
45 /// allocated with `allocator`.43 /// allocated with `allocator`.
46 /// Must deinitialize with deinit.44 /// Must deinitialize with deinit.
47 pub fn fromOwnedSlice(allocator: &Allocator, slice: []u8) Buffer {45 pub fn fromOwnedSlice(allocator: &Allocator, slice: []u8) Buffer {
48 var self = Buffer {46 var self = Buffer{ .list = ArrayList(u8).fromOwnedSlice(allocator, slice) };
49 .list = ArrayList(u8).fromOwnedSlice(allocator, slice),
50 };
51 self.list.append(0);47 self.list.append(0);
52 return self;48 return self;
53 }49 }
...@@ -57,11 +53,10 @@ pub const Buffer = struct {...@@ -57,11 +53,10 @@ pub const Buffer = struct {
57 pub fn toOwnedSlice(self: &Buffer) []u8 {53 pub fn toOwnedSlice(self: &Buffer) []u8 {
58 const allocator = self.list.allocator;54 const allocator = self.list.allocator;
59 const result = allocator.shrink(u8, self.list.items, self.len());55 const result = allocator.shrink(u8, self.list.items, self.len());
60 *self = initNull(allocator);56 self.* = initNull(allocator);
61 return result;57 return result;
62 }58 }
6359
64
65 pub fn deinit(self: &Buffer) void {60 pub fn deinit(self: &Buffer) void {
66 self.list.deinit();61 self.list.deinit();
67 }62 }
...@@ -99,26 +94,10 @@ pub const Buffer = struct {...@@ -99,26 +94,10 @@ pub const Buffer = struct {
99 mem.copy(u8, self.list.toSlice()[old_len..], m);94 mem.copy(u8, self.list.toSlice()[old_len..], m);
100 }95 }
10196
102 // TODO: remove, use OutStream for this
103 pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) !void {
104 return fmt.format(self, append, format, args);
105 }
106
107 // TODO: remove, use OutStream for this
108 pub fn appendByte(self: &Buffer, byte: u8) !void {97 pub fn appendByte(self: &Buffer, byte: u8) !void {
109 return self.appendByteNTimes(byte, 1);98 const old_len = self.len();
110 }99 try self.resize(old_len + 1);
111100 self.list.toSlice()[old_len] = byte;
112 // TODO: remove, use OutStream for this
113 pub fn appendByteNTimes(self: &Buffer, byte: u8, count: usize) !void {
114 var prev_size: usize = self.len();
115 const new_size = prev_size + count;
116 try self.resize(new_size);
117
118 var i: usize = prev_size;
119 while (i < new_size) : (i += 1) {
120 self.list.items[i] = byte;
121 }
122 }101 }
123102
124 pub fn eql(self: &const Buffer, m: []const u8) bool {103 pub fn eql(self: &const Buffer, m: []const u8) bool {
...@@ -154,7 +133,7 @@ test "simple Buffer" {...@@ -154,7 +133,7 @@ test "simple Buffer" {
154 var buf = try Buffer.init(debug.global_allocator, "");133 var buf = try Buffer.init(debug.global_allocator, "");
155 assert(buf.len() == 0);134 assert(buf.len() == 0);
156 try buf.append("hello");135 try buf.append("hello");
157 try buf.appendByte(' ');136 try buf.append(" ");
158 try buf.append("world");137 try buf.append("world");
159 assert(buf.eql("hello world"));138 assert(buf.eql("hello world"));
160 assert(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));139 assert(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));
std/build.zig+86-121
...@@ -82,10 +82,8 @@ pub const Builder = struct {...@@ -82,10 +82,8 @@ pub const Builder = struct {
82 description: []const u8,82 description: []const u8,
83 };83 };
8484
85 pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8,85 pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder {
86 cache_root: []const u8) Builder86 var self = Builder{
87 {
88 var self = Builder {
89 .zig_exe = zig_exe,87 .zig_exe = zig_exe,
90 .build_root = build_root,88 .build_root = build_root,
91 .cache_root = os.path.relative(allocator, build_root, cache_root) catch unreachable,89 .cache_root = os.path.relative(allocator, build_root, cache_root) catch unreachable,
...@@ -112,12 +110,12 @@ pub const Builder = struct {...@@ -112,12 +110,12 @@ pub const Builder = struct {
112 .lib_dir = undefined,110 .lib_dir = undefined,
113 .exe_dir = undefined,111 .exe_dir = undefined,
114 .installed_files = ArrayList([]const u8).init(allocator),112 .installed_files = ArrayList([]const u8).init(allocator),
115 .uninstall_tls = TopLevelStep {113 .uninstall_tls = TopLevelStep{
116 .step = Step.init("uninstall", allocator, makeUninstall),114 .step = Step.init("uninstall", allocator, makeUninstall),
117 .description = "Remove build artifacts from prefix path",115 .description = "Remove build artifacts from prefix path",
118 },116 },
119 .have_uninstall_step = false,117 .have_uninstall_step = false,
120 .install_tls = TopLevelStep {118 .install_tls = TopLevelStep{
121 .step = Step.initNoOp("install", allocator),119 .step = Step.initNoOp("install", allocator),
122 .description = "Copy build artifacts to prefix path",120 .description = "Copy build artifacts to prefix path",
123 },121 },
...@@ -151,9 +149,7 @@ pub const Builder = struct {...@@ -151,9 +149,7 @@ pub const Builder = struct {
151 return LibExeObjStep.createObject(self, name, root_src);149 return LibExeObjStep.createObject(self, name, root_src);
152 }150 }
153151
154 pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8,152 pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: ?[]const u8, ver: &const Version) &LibExeObjStep {
155 ver: &const Version) &LibExeObjStep
156 {
157 return LibExeObjStep.createSharedLibrary(self, name, root_src, ver);153 return LibExeObjStep.createSharedLibrary(self, name, root_src, ver);
158 }154 }
159155
...@@ -163,7 +159,7 @@ pub const Builder = struct {...@@ -163,7 +159,7 @@ pub const Builder = struct {
163159
164 pub fn addTest(self: &Builder, root_src: []const u8) &TestStep {160 pub fn addTest(self: &Builder, root_src: []const u8) &TestStep {
165 const test_step = self.allocator.create(TestStep) catch unreachable;161 const test_step = self.allocator.create(TestStep) catch unreachable;
166 *test_step = TestStep.init(self, root_src);162 test_step.* = TestStep.init(self, root_src);
167 return test_step;163 return test_step;
168 }164 }
169165
...@@ -190,33 +186,31 @@ pub const Builder = struct {...@@ -190,33 +186,31 @@ pub const Builder = struct {
190 }186 }
191187
192 /// ::argv is copied.188 /// ::argv is copied.
193 pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,189 pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) &CommandStep {
194 argv: []const []const u8) &CommandStep
195 {
196 return CommandStep.create(self, cwd, env_map, argv);190 return CommandStep.create(self, cwd, env_map, argv);
197 }191 }
198192
199 pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) &WriteFileStep {193 pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) &WriteFileStep {
200 const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;194 const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;
201 *write_file_step = WriteFileStep.init(self, file_path, data);195 write_file_step.* = WriteFileStep.init(self, file_path, data);
202 return write_file_step;196 return write_file_step;
203 }197 }
204198
205 pub fn addLog(self: &Builder, comptime format: []const u8, args: ...) &LogStep {199 pub fn addLog(self: &Builder, comptime format: []const u8, args: ...) &LogStep {
206 const data = self.fmt(format, args);200 const data = self.fmt(format, args);
207 const log_step = self.allocator.create(LogStep) catch unreachable;201 const log_step = self.allocator.create(LogStep) catch unreachable;
208 *log_step = LogStep.init(self, data);202 log_step.* = LogStep.init(self, data);
209 return log_step;203 return log_step;
210 }204 }
211205
212 pub fn addRemoveDirTree(self: &Builder, dir_path: []const u8) &RemoveDirStep {206 pub fn addRemoveDirTree(self: &Builder, dir_path: []const u8) &RemoveDirStep {
213 const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;207 const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;
214 *remove_dir_step = RemoveDirStep.init(self, dir_path);208 remove_dir_step.* = RemoveDirStep.init(self, dir_path);
215 return remove_dir_step;209 return remove_dir_step;
216 }210 }
217211
218 pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) Version {212 pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) Version {
219 return Version {213 return Version{
220 .major = major,214 .major = major,
221 .minor = minor,215 .minor = minor,
222 .patch = patch,216 .patch = patch,
...@@ -254,8 +248,7 @@ pub const Builder = struct {...@@ -254,8 +248,7 @@ pub const Builder = struct {
254 }248 }
255249
256 pub fn getInstallStep(self: &Builder) &Step {250 pub fn getInstallStep(self: &Builder) &Step {
257 if (self.have_install_step)251 if (self.have_install_step) return &self.install_tls.step;
258 return &self.install_tls.step;
259252
260 self.top_level_steps.append(&self.install_tls) catch unreachable;253 self.top_level_steps.append(&self.install_tls) catch unreachable;
261 self.have_install_step = true;254 self.have_install_step = true;
...@@ -263,8 +256,7 @@ pub const Builder = struct {...@@ -263,8 +256,7 @@ pub const Builder = struct {
263 }256 }
264257
265 pub fn getUninstallStep(self: &Builder) &Step {258 pub fn getUninstallStep(self: &Builder) &Step {
266 if (self.have_uninstall_step)259 if (self.have_uninstall_step) return &self.uninstall_tls.step;
267 return &self.uninstall_tls.step;
268260
269 self.top_level_steps.append(&self.uninstall_tls) catch unreachable;261 self.top_level_steps.append(&self.uninstall_tls) catch unreachable;
270 self.have_uninstall_step = true;262 self.have_uninstall_step = true;
...@@ -360,7 +352,7 @@ pub const Builder = struct {...@@ -360,7 +352,7 @@ pub const Builder = struct {
360352
361 pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) ?T {353 pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) ?T {
362 const type_id = comptime typeToEnum(T);354 const type_id = comptime typeToEnum(T);
363 const available_option = AvailableOption {355 const available_option = AvailableOption{
364 .name = name,356 .name = name,
365 .type_id = type_id,357 .type_id = type_id,
366 .description = description,358 .description = description,
...@@ -413,7 +405,7 @@ pub const Builder = struct {...@@ -413,7 +405,7 @@ pub const Builder = struct {
413405
414 pub fn step(self: &Builder, name: []const u8, description: []const u8) &Step {406 pub fn step(self: &Builder, name: []const u8, description: []const u8) &Step {
415 const step_info = self.allocator.create(TopLevelStep) catch unreachable;407 const step_info = self.allocator.create(TopLevelStep) catch unreachable;
416 *step_info = TopLevelStep {408 step_info.* = TopLevelStep{
417 .step = Step.initNoOp(name, self.allocator),409 .step = Step.initNoOp(name, self.allocator),
418 .description = description,410 .description = description,
419 };411 };
...@@ -446,9 +438,9 @@ pub const Builder = struct {...@@ -446,9 +438,9 @@ pub const Builder = struct {
446 }438 }
447439
448 pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) bool {440 pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) bool {
449 if (self.user_input_options.put(name, UserInputOption {441 if (self.user_input_options.put(name, UserInputOption{
450 .name = name,442 .name = name,
451 .value = UserValue { .Scalar = value },443 .value = UserValue{ .Scalar = value },
452 .used = false,444 .used = false,
453 }) catch unreachable) |*prev_value| {445 }) catch unreachable) |*prev_value| {
454 // option already exists446 // option already exists
...@@ -458,18 +450,18 @@ pub const Builder = struct {...@@ -458,18 +450,18 @@ pub const Builder = struct {
458 var list = ArrayList([]const u8).init(self.allocator);450 var list = ArrayList([]const u8).init(self.allocator);
459 list.append(s) catch unreachable;451 list.append(s) catch unreachable;
460 list.append(value) catch unreachable;452 list.append(value) catch unreachable;
461 _ = self.user_input_options.put(name, UserInputOption {453 _ = self.user_input_options.put(name, UserInputOption{
462 .name = name,454 .name = name,
463 .value = UserValue { .List = list },455 .value = UserValue{ .List = list },
464 .used = false,456 .used = false,
465 }) catch unreachable;457 }) catch unreachable;
466 },458 },
467 UserValue.List => |*list| {459 UserValue.List => |*list| {
468 // append to the list460 // append to the list
469 list.append(value) catch unreachable;461 list.append(value) catch unreachable;
470 _ = self.user_input_options.put(name, UserInputOption {462 _ = self.user_input_options.put(name, UserInputOption{
471 .name = name,463 .name = name,
472 .value = UserValue { .List = *list },464 .value = UserValue{ .List = list.* },
473 .used = false,465 .used = false,
474 }) catch unreachable;466 }) catch unreachable;
475 },467 },
...@@ -483,9 +475,9 @@ pub const Builder = struct {...@@ -483,9 +475,9 @@ pub const Builder = struct {
483 }475 }
484476
485 pub fn addUserInputFlag(self: &Builder, name: []const u8) bool {477 pub fn addUserInputFlag(self: &Builder, name: []const u8) bool {
486 if (self.user_input_options.put(name, UserInputOption {478 if (self.user_input_options.put(name, UserInputOption{
487 .name = name,479 .name = name,
488 .value = UserValue {.Flag = {} },480 .value = UserValue{ .Flag = {} },
489 .used = false,481 .used = false,
490 }) catch unreachable) |*prev_value| {482 }) catch unreachable) |*prev_value| {
491 switch (prev_value.value) {483 switch (prev_value.value) {
...@@ -556,9 +548,7 @@ pub const Builder = struct {...@@ -556,9 +548,7 @@ pub const Builder = struct {
556 warn("\n");548 warn("\n");
557 }549 }
558550
559 fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,551 fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) !void {
560 argv: []const []const u8) !void
561 {
562 if (self.verbose) {552 if (self.verbose) {
563 printCmd(cwd, argv);553 printCmd(cwd, argv);
564 }554 }
...@@ -617,7 +607,7 @@ pub const Builder = struct {...@@ -617,7 +607,7 @@ pub const Builder = struct {
617 self.pushInstalledFile(full_dest_path);607 self.pushInstalledFile(full_dest_path);
618608
619 const install_step = self.allocator.create(InstallFileStep) catch unreachable;609 const install_step = self.allocator.create(InstallFileStep) catch unreachable;
620 *install_step = InstallFileStep.init(self, src_path, full_dest_path);610 install_step.* = InstallFileStep.init(self, src_path, full_dest_path);
621 return install_step;611 return install_step;
622 }612 }
623613
...@@ -659,25 +649,23 @@ pub const Builder = struct {...@@ -659,25 +649,23 @@ pub const Builder = struct {
659 if (builtin.environ == builtin.Environ.msvc) {649 if (builtin.environ == builtin.Environ.msvc) {
660 return "cl.exe";650 return "cl.exe";
661 } else {651 } else {
662 return os.getEnvVarOwned(self.allocator, "CC") catch |err| 652 return os.getEnvVarOwned(self.allocator, "CC") catch |err|
663 if (err == error.EnvironmentVariableNotFound)653 if (err == error.EnvironmentVariableNotFound)
664 ([]const u8)("cc")654 ([]const u8)("cc")
665 else655 else
666 debug.panic("Unable to get environment variable: {}", err)656 debug.panic("Unable to get environment variable: {}", err);
667 ;
668 }657 }
669 }658 }
670659
671 pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {660 pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
672 // TODO report error for ambiguous situations661 // TODO report error for ambiguous situations
673 const exe_extension = (Target { .Native = {}}).exeFileExt();662 const exe_extension = (Target{ .Native = {} }).exeFileExt();
674 for (self.search_prefixes.toSliceConst()) |search_prefix| {663 for (self.search_prefixes.toSliceConst()) |search_prefix| {
675 for (names) |name| {664 for (names) |name| {
676 if (os.path.isAbsolute(name)) {665 if (os.path.isAbsolute(name)) {
677 return name;666 return name;
678 }667 }
679 const full_path = try os.path.join(self.allocator, search_prefix, "bin",668 const full_path = try os.path.join(self.allocator, search_prefix, "bin", self.fmt("{}{}", name, exe_extension));
680 self.fmt("{}{}", name, exe_extension));
681 if (os.path.real(self.allocator, full_path)) |real_path| {669 if (os.path.real(self.allocator, full_path)) |real_path| {
682 return real_path;670 return real_path;
683 } else |_| {671 } else |_| {
...@@ -761,7 +749,7 @@ pub const Target = union(enum) {...@@ -761,7 +749,7 @@ pub const Target = union(enum) {
761 Cross: CrossTarget,749 Cross: CrossTarget,
762750
763 pub fn oFileExt(self: &const Target) []const u8 {751 pub fn oFileExt(self: &const Target) []const u8 {
764 const environ = switch (*self) {752 const environ = switch (self.*) {
765 Target.Native => builtin.environ,753 Target.Native => builtin.environ,
766 Target.Cross => |t| t.environ,754 Target.Cross => |t| t.environ,
767 };755 };
...@@ -786,7 +774,7 @@ pub const Target = union(enum) {...@@ -786,7 +774,7 @@ pub const Target = union(enum) {
786 }774 }
787775
788 pub fn getOs(self: &const Target) builtin.Os {776 pub fn getOs(self: &const Target) builtin.Os {
789 return switch (*self) {777 return switch (self.*) {
790 Target.Native => builtin.os,778 Target.Native => builtin.os,
791 Target.Cross => |t| t.os,779 Target.Cross => |t| t.os,
792 };780 };
...@@ -794,7 +782,8 @@ pub const Target = union(enum) {...@@ -794,7 +782,8 @@ pub const Target = union(enum) {
794782
795 pub fn isDarwin(self: &const Target) bool {783 pub fn isDarwin(self: &const Target) bool {
796 return switch (self.getOs()) {784 return switch (self.getOs()) {
797 builtin.Os.ios, builtin.Os.macosx => true,785 builtin.Os.ios,
786 builtin.Os.macosx => true,
798 else => false,787 else => false,
799 };788 };
800 }789 }
...@@ -860,61 +849,57 @@ pub const LibExeObjStep = struct {...@@ -860,61 +849,57 @@ pub const LibExeObjStep = struct {
860 Obj,849 Obj,
861 };850 };
862851
863 pub fn createSharedLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8,852 pub fn createSharedLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8, ver: &const Version) &LibExeObjStep {
864 ver: &const Version) &LibExeObjStep
865 {
866 const self = builder.allocator.create(LibExeObjStep) catch unreachable;853 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
867 *self = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);854 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
868 return self;855 return self;
869 }856 }
870857
871 pub fn createCSharedLibrary(builder: &Builder, name: []const u8, version: &const Version) &LibExeObjStep {858 pub fn createCSharedLibrary(builder: &Builder, name: []const u8, version: &const Version) &LibExeObjStep {
872 const self = builder.allocator.create(LibExeObjStep) catch unreachable;859 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
873 *self = initC(builder, name, Kind.Lib, version, false);860 self.* = initC(builder, name, Kind.Lib, version, false);
874 return self;861 return self;
875 }862 }
876863
877 pub fn createStaticLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8) &LibExeObjStep {864 pub fn createStaticLibrary(builder: &Builder, name: []const u8, root_src: ?[]const u8) &LibExeObjStep {
878 const self = builder.allocator.create(LibExeObjStep) catch unreachable;865 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
879 *self = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));866 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
880 return self;867 return self;
881 }868 }
882869
883 pub fn createCStaticLibrary(builder: &Builder, name: []const u8) &LibExeObjStep {870 pub fn createCStaticLibrary(builder: &Builder, name: []const u8) &LibExeObjStep {
884 const self = builder.allocator.create(LibExeObjStep) catch unreachable;871 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
885 *self = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);872 self.* = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
886 return self;873 return self;
887 }874 }
888875
889 pub fn createObject(builder: &Builder, name: []const u8, root_src: []const u8) &LibExeObjStep {876 pub fn createObject(builder: &Builder, name: []const u8, root_src: []const u8) &LibExeObjStep {
890 const self = builder.allocator.create(LibExeObjStep) catch unreachable;877 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
891 *self = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));878 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
892 return self;879 return self;
893 }880 }
894881
895 pub fn createCObject(builder: &Builder, name: []const u8, src: []const u8) &LibExeObjStep {882 pub fn createCObject(builder: &Builder, name: []const u8, src: []const u8) &LibExeObjStep {
896 const self = builder.allocator.create(LibExeObjStep) catch unreachable;883 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
897 *self = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);884 self.* = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
898 self.object_src = src;885 self.object_src = src;
899 return self;886 return self;
900 }887 }
901888
902 pub fn createExecutable(builder: &Builder, name: []const u8, root_src: ?[]const u8) &LibExeObjStep {889 pub fn createExecutable(builder: &Builder, name: []const u8, root_src: ?[]const u8) &LibExeObjStep {
903 const self = builder.allocator.create(LibExeObjStep) catch unreachable;890 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
904 *self = initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0));891 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0));
905 return self;892 return self;
906 }893 }
907894
908 pub fn createCExecutable(builder: &Builder, name: []const u8) &LibExeObjStep {895 pub fn createCExecutable(builder: &Builder, name: []const u8) &LibExeObjStep {
909 const self = builder.allocator.create(LibExeObjStep) catch unreachable;896 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
910 *self = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);897 self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
911 return self;898 return self;
912 }899 }
913900
914 fn initExtraArgs(builder: &Builder, name: []const u8, root_src: ?[]const u8, kind: Kind,901 fn initExtraArgs(builder: &Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, static: bool, ver: &const Version) LibExeObjStep {
915 static: bool, ver: &const Version) LibExeObjStep902 var self = LibExeObjStep{
916 {
917 var self = LibExeObjStep {
918 .strip = false,903 .strip = false,
919 .builder = builder,904 .builder = builder,
920 .verbose_link = false,905 .verbose_link = false,
...@@ -930,7 +915,7 @@ pub const LibExeObjStep = struct {...@@ -930,7 +915,7 @@ pub const LibExeObjStep = struct {
930 .step = Step.init(name, builder.allocator, make),915 .step = Step.init(name, builder.allocator, make),
931 .output_path = null,916 .output_path = null,
932 .output_h_path = null,917 .output_h_path = null,
933 .version = *ver,918 .version = ver.*,
934 .out_filename = undefined,919 .out_filename = undefined,
935 .out_h_filename = builder.fmt("{}.h", name),920 .out_h_filename = builder.fmt("{}.h", name),
936 .major_only_filename = undefined,921 .major_only_filename = undefined,
...@@ -953,11 +938,11 @@ pub const LibExeObjStep = struct {...@@ -953,11 +938,11 @@ pub const LibExeObjStep = struct {
953 }938 }
954939
955 fn initC(builder: &Builder, name: []const u8, kind: Kind, version: &const Version, static: bool) LibExeObjStep {940 fn initC(builder: &Builder, name: []const u8, kind: Kind, version: &const Version, static: bool) LibExeObjStep {
956 var self = LibExeObjStep {941 var self = LibExeObjStep{
957 .builder = builder,942 .builder = builder,
958 .name = name,943 .name = name,
959 .kind = kind,944 .kind = kind,
960 .version = *version,945 .version = version.*,
961 .static = static,946 .static = static,
962 .target = Target.Native,947 .target = Target.Native,
963 .cflags = ArrayList([]const u8).init(builder.allocator),948 .cflags = ArrayList([]const u8).init(builder.allocator),
...@@ -1005,9 +990,9 @@ pub const LibExeObjStep = struct {...@@ -1005,9 +990,9 @@ pub const LibExeObjStep = struct {
1005 self.out_filename = self.builder.fmt("lib{}.a", self.name);990 self.out_filename = self.builder.fmt("lib{}.a", self.name);
1006 } else {991 } else {
1007 switch (self.target.getOs()) {992 switch (self.target.getOs()) {
1008 builtin.Os.ios, builtin.Os.macosx => {993 builtin.Os.ios,
1009 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib",994 builtin.Os.macosx => {
1010 self.name, self.version.major, self.version.minor, self.version.patch);995 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);
1011 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);996 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);
1012 self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);997 self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);
1013 },998 },
...@@ -1015,8 +1000,7 @@ pub const LibExeObjStep = struct {...@@ -1015,8 +1000,7 @@ pub const LibExeObjStep = struct {
1015 self.out_filename = self.builder.fmt("{}.dll", self.name);1000 self.out_filename = self.builder.fmt("{}.dll", self.name);
1016 },1001 },
1017 else => {1002 else => {
1018 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}",1003 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch);
1019 self.name, self.version.major, self.version.minor, self.version.patch);
1020 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);1004 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
1021 self.name_only_filename = self.builder.fmt("lib{}.so", self.name);1005 self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
1022 },1006 },
...@@ -1026,16 +1010,12 @@ pub const LibExeObjStep = struct {...@@ -1026,16 +1010,12 @@ pub const LibExeObjStep = struct {
1026 }1010 }
1027 }1011 }
10281012
1029 pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os,1013 pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
1030 target_environ: builtin.Environ) void1014 self.target = Target{ .Cross = CrossTarget{
1031 {1015 .arch = target_arch,
1032 self.target = Target {1016 .os = target_os,
1033 .Cross = CrossTarget {1017 .environ = target_environ,
1034 .arch = target_arch,1018 } };
1035 .os = target_os,
1036 .environ = target_environ,
1037 }
1038 };
1039 self.computeOutFileNames();1019 self.computeOutFileNames();
1040 }1020 }
10411021
...@@ -1159,7 +1139,7 @@ pub const LibExeObjStep = struct {...@@ -1159,7 +1139,7 @@ pub const LibExeObjStep = struct {
1159 pub fn addPackagePath(self: &LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {1139 pub fn addPackagePath(self: &LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
1160 assert(self.is_zig);1140 assert(self.is_zig);
11611141
1162 self.packages.append(Pkg {1142 self.packages.append(Pkg{
1163 .name = name,1143 .name = name,
1164 .path = pkg_index_path,1144 .path = pkg_index_path,
1165 }) catch unreachable;1145 }) catch unreachable;
...@@ -1343,8 +1323,7 @@ pub const LibExeObjStep = struct {...@@ -1343,8 +1323,7 @@ pub const LibExeObjStep = struct {
1343 try builder.spawnChild(zig_args.toSliceConst());1323 try builder.spawnChild(zig_args.toSliceConst());
13441324
1345 if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {1325 if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
1346 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,1326 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
1347 self.name_only_filename);
1348 }1327 }
1349 }1328 }
13501329
...@@ -1373,7 +1352,8 @@ pub const LibExeObjStep = struct {...@@ -1373,7 +1352,8 @@ pub const LibExeObjStep = struct {
1373 args.append("ssp-buffer-size=4") catch unreachable;1352 args.append("ssp-buffer-size=4") catch unreachable;
1374 }1353 }
1375 },1354 },
1376 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {1355 builtin.Mode.ReleaseFast,
1356 builtin.Mode.ReleaseSmall => {
1377 args.append("-O2") catch unreachable;1357 args.append("-O2") catch unreachable;
1378 args.append("-fno-stack-protector") catch unreachable;1358 args.append("-fno-stack-protector") catch unreachable;
1379 },1359 },
...@@ -1505,8 +1485,7 @@ pub const LibExeObjStep = struct {...@@ -1505,8 +1485,7 @@ pub const LibExeObjStep = struct {
1505 }1485 }
15061486
1507 if (!is_darwin) {1487 if (!is_darwin) {
1508 const rpath_arg = builder.fmt("-Wl,-rpath,{}",1488 const rpath_arg = builder.fmt("-Wl,-rpath,{}", os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
1509 os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
1510 defer builder.allocator.free(rpath_arg);1489 defer builder.allocator.free(rpath_arg);
1511 cc_args.append(rpath_arg) catch unreachable;1490 cc_args.append(rpath_arg) catch unreachable;
15121491
...@@ -1535,8 +1514,7 @@ pub const LibExeObjStep = struct {...@@ -1535,8 +1514,7 @@ pub const LibExeObjStep = struct {
1535 try builder.spawnChild(cc_args.toSliceConst());1514 try builder.spawnChild(cc_args.toSliceConst());
15361515
1537 if (self.target.wantSharedLibSymLinks()) {1516 if (self.target.wantSharedLibSymLinks()) {
1538 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,1517 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
1539 self.name_only_filename);
1540 }1518 }
1541 }1519 }
1542 },1520 },
...@@ -1581,8 +1559,7 @@ pub const LibExeObjStep = struct {...@@ -1581,8 +1559,7 @@ pub const LibExeObjStep = struct {
1581 cc_args.append("-o") catch unreachable;1559 cc_args.append("-o") catch unreachable;
1582 cc_args.append(output_path) catch unreachable;1560 cc_args.append(output_path) catch unreachable;
15831561
1584 const rpath_arg = builder.fmt("-Wl,-rpath,{}",1562 const rpath_arg = builder.fmt("-Wl,-rpath,{}", os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
1585 os.path.real(builder.allocator, builder.pathFromRoot(builder.cache_root)) catch unreachable);
1586 defer builder.allocator.free(rpath_arg);1563 defer builder.allocator.free(rpath_arg);
1587 cc_args.append(rpath_arg) catch unreachable;1564 cc_args.append(rpath_arg) catch unreachable;
15881565
...@@ -1635,7 +1612,7 @@ pub const TestStep = struct {...@@ -1635,7 +1612,7 @@ pub const TestStep = struct {
16351612
1636 pub fn init(builder: &Builder, root_src: []const u8) TestStep {1613 pub fn init(builder: &Builder, root_src: []const u8) TestStep {
1637 const step_name = builder.fmt("test {}", root_src);1614 const step_name = builder.fmt("test {}", root_src);
1638 return TestStep {1615 return TestStep{
1639 .step = Step.init(step_name, builder.allocator, make),1616 .step = Step.init(step_name, builder.allocator, make),
1640 .builder = builder,1617 .builder = builder,
1641 .root_src = root_src,1618 .root_src = root_src,
...@@ -1644,7 +1621,7 @@ pub const TestStep = struct {...@@ -1644,7 +1621,7 @@ pub const TestStep = struct {
1644 .name_prefix = "",1621 .name_prefix = "",
1645 .filter = null,1622 .filter = null,
1646 .link_libs = BufSet.init(builder.allocator),1623 .link_libs = BufSet.init(builder.allocator),
1647 .target = Target { .Native = {} },1624 .target = Target{ .Native = {} },
1648 .exec_cmd_args = null,1625 .exec_cmd_args = null,
1649 .include_dirs = ArrayList([]const u8).init(builder.allocator),1626 .include_dirs = ArrayList([]const u8).init(builder.allocator),
1650 };1627 };
...@@ -1674,16 +1651,12 @@ pub const TestStep = struct {...@@ -1674,16 +1651,12 @@ pub const TestStep = struct {
1674 self.filter = text;1651 self.filter = text;
1675 }1652 }
16761653
1677 pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os,1654 pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
1678 target_environ: builtin.Environ) void1655 self.target = Target{ .Cross = CrossTarget{
1679 {1656 .arch = target_arch,
1680 self.target = Target {1657 .os = target_os,
1681 .Cross = CrossTarget {1658 .environ = target_environ,
1682 .arch = target_arch,1659 } };
1683 .os = target_os,
1684 .environ = target_environ,
1685 }
1686 };
1687 }1660 }
16881661
1689 pub fn setExecCmd(self: &TestStep, args: []const ?[]const u8) void {1662 pub fn setExecCmd(self: &TestStep, args: []const ?[]const u8) void {
...@@ -1789,11 +1762,9 @@ pub const CommandStep = struct {...@@ -1789,11 +1762,9 @@ pub const CommandStep = struct {
1789 env_map: &const BufMap,1762 env_map: &const BufMap,
17901763
1791 /// ::argv is copied.1764 /// ::argv is copied.
1792 pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap,1765 pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap, argv: []const []const u8) &CommandStep {
1793 argv: []const []const u8) &CommandStep
1794 {
1795 const self = builder.allocator.create(CommandStep) catch unreachable;1766 const self = builder.allocator.create(CommandStep) catch unreachable;
1796 *self = CommandStep {1767 self.* = CommandStep{
1797 .builder = builder,1768 .builder = builder,
1798 .step = Step.init(argv[0], builder.allocator, make),1769 .step = Step.init(argv[0], builder.allocator, make),
1799 .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,1770 .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,
...@@ -1828,7 +1799,7 @@ const InstallArtifactStep = struct {...@@ -1828,7 +1799,7 @@ const InstallArtifactStep = struct {
1828 LibExeObjStep.Kind.Exe => builder.exe_dir,1799 LibExeObjStep.Kind.Exe => builder.exe_dir,
1829 LibExeObjStep.Kind.Lib => builder.lib_dir,1800 LibExeObjStep.Kind.Lib => builder.lib_dir,
1830 };1801 };
1831 *self = Self {1802 self.* = Self{
1832 .builder = builder,1803 .builder = builder,
1833 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),1804 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
1834 .artifact = artifact,1805 .artifact = artifact,
...@@ -1837,10 +1808,8 @@ const InstallArtifactStep = struct {...@@ -1837,10 +1808,8 @@ const InstallArtifactStep = struct {
1837 self.step.dependOn(&artifact.step);1808 self.step.dependOn(&artifact.step);
1838 builder.pushInstalledFile(self.dest_file);1809 builder.pushInstalledFile(self.dest_file);
1839 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {1810 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
1840 builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir,1811 builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.major_only_filename) catch unreachable);
1841 artifact.major_only_filename) catch unreachable);1812 builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.name_only_filename) catch unreachable);
1842 builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir,
1843 artifact.name_only_filename) catch unreachable);
1844 }1813 }
1845 return self;1814 return self;
1846 }1815 }
...@@ -1859,8 +1828,7 @@ const InstallArtifactStep = struct {...@@ -1859,8 +1828,7 @@ const InstallArtifactStep = struct {
1859 };1828 };
1860 try builder.copyFileMode(self.artifact.getOutputPath(), self.dest_file, mode);1829 try builder.copyFileMode(self.artifact.getOutputPath(), self.dest_file, mode);
1861 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {1830 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
1862 try doAtomicSymLinks(builder.allocator, self.dest_file,1831 try doAtomicSymLinks(builder.allocator, self.dest_file, self.artifact.major_only_filename, self.artifact.name_only_filename);
1863 self.artifact.major_only_filename, self.artifact.name_only_filename);
1864 }1832 }
1865 }1833 }
1866};1834};
...@@ -1872,7 +1840,7 @@ pub const InstallFileStep = struct {...@@ -1872,7 +1840,7 @@ pub const InstallFileStep = struct {
1872 dest_path: []const u8,1840 dest_path: []const u8,
18731841
1874 pub fn init(builder: &Builder, src_path: []const u8, dest_path: []const u8) InstallFileStep {1842 pub fn init(builder: &Builder, src_path: []const u8, dest_path: []const u8) InstallFileStep {
1875 return InstallFileStep {1843 return InstallFileStep{
1876 .builder = builder,1844 .builder = builder,
1877 .step = Step.init(builder.fmt("install {}", src_path), builder.allocator, make),1845 .step = Step.init(builder.fmt("install {}", src_path), builder.allocator, make),
1878 .src_path = src_path,1846 .src_path = src_path,
...@@ -1893,7 +1861,7 @@ pub const WriteFileStep = struct {...@@ -1893,7 +1861,7 @@ pub const WriteFileStep = struct {
1893 data: []const u8,1861 data: []const u8,
18941862
1895 pub fn init(builder: &Builder, file_path: []const u8, data: []const u8) WriteFileStep {1863 pub fn init(builder: &Builder, file_path: []const u8, data: []const u8) WriteFileStep {
1896 return WriteFileStep {1864 return WriteFileStep{
1897 .builder = builder,1865 .builder = builder,
1898 .step = Step.init(builder.fmt("writefile {}", file_path), builder.allocator, make),1866 .step = Step.init(builder.fmt("writefile {}", file_path), builder.allocator, make),
1899 .file_path = file_path,1867 .file_path = file_path,
...@@ -1922,7 +1890,7 @@ pub const LogStep = struct {...@@ -1922,7 +1890,7 @@ pub const LogStep = struct {
1922 data: []const u8,1890 data: []const u8,
19231891
1924 pub fn init(builder: &Builder, data: []const u8) LogStep {1892 pub fn init(builder: &Builder, data: []const u8) LogStep {
1925 return LogStep {1893 return LogStep{
1926 .builder = builder,1894 .builder = builder,
1927 .step = Step.init(builder.fmt("log {}", data), builder.allocator, make),1895 .step = Step.init(builder.fmt("log {}", data), builder.allocator, make),
1928 .data = data,1896 .data = data,
...@@ -1941,7 +1909,7 @@ pub const RemoveDirStep = struct {...@@ -1941,7 +1909,7 @@ pub const RemoveDirStep = struct {
1941 dir_path: []const u8,1909 dir_path: []const u8,
19421910
1943 pub fn init(builder: &Builder, dir_path: []const u8) RemoveDirStep {1911 pub fn init(builder: &Builder, dir_path: []const u8) RemoveDirStep {
1944 return RemoveDirStep {1912 return RemoveDirStep{
1945 .builder = builder,1913 .builder = builder,
1946 .step = Step.init(builder.fmt("RemoveDir {}", dir_path), builder.allocator, make),1914 .step = Step.init(builder.fmt("RemoveDir {}", dir_path), builder.allocator, make),
1947 .dir_path = dir_path,1915 .dir_path = dir_path,
...@@ -1966,8 +1934,8 @@ pub const Step = struct {...@@ -1966,8 +1934,8 @@ pub const Step = struct {
1966 loop_flag: bool,1934 loop_flag: bool,
1967 done_flag: bool,1935 done_flag: bool,
19681936
1969 pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)error!void) Step {1937 pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn(&Step) error!void) Step {
1970 return Step {1938 return Step{
1971 .name = name,1939 .name = name,
1972 .makeFn = makeFn,1940 .makeFn = makeFn,
1973 .dependencies = ArrayList(&Step).init(allocator),1941 .dependencies = ArrayList(&Step).init(allocator),
...@@ -1980,8 +1948,7 @@ pub const Step = struct {...@@ -1980,8 +1948,7 @@ pub const Step = struct {
1980 }1948 }
19811949
1982 pub fn make(self: &Step) !void {1950 pub fn make(self: &Step) !void {
1983 if (self.done_flag)1951 if (self.done_flag) return;
1984 return;
19851952
1986 try self.makeFn(self);1953 try self.makeFn(self);
1987 self.done_flag = true;1954 self.done_flag = true;
...@@ -1994,9 +1961,7 @@ pub const Step = struct {...@@ -1994,9 +1961,7 @@ pub const Step = struct {
1994 fn makeNoOp(self: &Step) error!void {}1961 fn makeNoOp(self: &Step) error!void {}
1995};1962};
19961963
1997fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8,1964fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
1998 filename_name_only: []const u8) !void
1999{
2000 const out_dir = os.path.dirname(output_path);1965 const out_dir = os.path.dirname(output_path);
2001 const out_basename = os.path.basename(output_path);1966 const out_basename = os.path.basename(output_path);
2002 // sym link for libfoo.so.1 to libfoo.so.1.2.31967 // sym link for libfoo.so.1 to libfoo.so.1.2.3
std/crypto/blake2.zig+470-241
...@@ -6,11 +6,23 @@ const builtin = @import("builtin");...@@ -6,11 +6,23 @@ const builtin = @import("builtin");
6const htest = @import("test.zig");6const htest = @import("test.zig");
77
8const RoundParam = struct {8const RoundParam = struct {
9 a: usize, b: usize, c: usize, d: usize, x: usize, y: usize,9 a: usize,
10 b: usize,
11 c: usize,
12 d: usize,
13 x: usize,
14 y: usize,
10};15};
1116
12fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {17fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
13 return RoundParam { .a = a, .b = b, .c = c, .d = d, .x = x, .y = y, };18 return RoundParam{
19 .a = a,
20 .b = b,
21 .c = c,
22 .d = d,
23 .x = x,
24 .y = y,
25 };
14}26}
1527
16/////////////////////28/////////////////////
...@@ -19,145 +31,153 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {...@@ -19,145 +31,153 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
19pub const Blake2s224 = Blake2s(224);31pub const Blake2s224 = Blake2s(224);
20pub const Blake2s256 = Blake2s(256);32pub const Blake2s256 = Blake2s(256);
2133
22fn Blake2s(comptime out_len: usize) type { return struct {34fn Blake2s(comptime out_len: usize) type {
23 const Self = this;35 return struct {
24 const block_size = 64;36 const Self = this;
25 const digest_size = out_len / 8;37 const block_size = 64;
38 const digest_size = out_len / 8;
39
40 const iv = [8]u32{
41 0x6A09E667,
42 0xBB67AE85,
43 0x3C6EF372,
44 0xA54FF53A,
45 0x510E527F,
46 0x9B05688C,
47 0x1F83D9AB,
48 0x5BE0CD19,
49 };
2650
27 const iv = [8]u32 {51 const sigma = [10][16]u8{
28 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,52 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
29 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,53 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
30 };54 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
55 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
56 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
57 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
58 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
59 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
60 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
61 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
62 };
3163
32 const sigma = [10][16]u8 {64 h: [8]u32,
33 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },65 t: u64,
34 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },66 // Streaming cache
35 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },67 buf: [64]u8,
36 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },68 buf_len: u8,
37 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
38 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
39 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
40 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
41 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
42 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
43 };
4469
45 h: [8]u32,70 pub fn init() Self {
46 t: u64,71 debug.assert(8 <= out_len and out_len <= 512);
47 // Streaming cache72
48 buf: [64]u8,73 var s: Self = undefined;
49 buf_len: u8,74 s.reset();
5075 return s;
51 pub fn init() Self {
52 debug.assert(8 <= out_len and out_len <= 512);
53
54 var s: Self = undefined;
55 s.reset();
56 return s;
57 }
58
59 pub fn reset(d: &Self) void {
60 mem.copy(u32, d.h[0..], iv[0..]);
61
62 // No key plus default parameters
63 d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
64 d.t = 0;
65 d.buf_len = 0;
66 }
67
68 pub fn hash(b: []const u8, out: []u8) void {
69 var d = Self.init();
70 d.update(b);
71 d.final(out);
72 }
73
74 pub fn update(d: &Self, b: []const u8) void {
75 var off: usize = 0;
76
77 // Partial buffer exists from previous update. Copy into buffer then hash.
78 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
79 off += 64 - d.buf_len;
80 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
81 d.t += 64;
82 d.round(d.buf[0..], false);
83 d.buf_len = 0;
84 }76 }
8577
86 // Full middle blocks.78 pub fn reset(d: &Self) void {
87 while (off + 64 <= b.len) : (off += 64) {79 mem.copy(u32, d.h[0..], iv[0..]);
88 d.t += 64;80
89 d.round(b[off..off + 64], false);81 // No key plus default parameters
82 d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
83 d.t = 0;
84 d.buf_len = 0;
90 }85 }
9186
92 // Copy any remainder for next pass.87 pub fn hash(b: []const u8, out: []u8) void {
93 mem.copy(u8, d.buf[d.buf_len..], b[off..]);88 var d = Self.init();
94 d.buf_len += u8(b[off..].len);89 d.update(b);
95 }90 d.final(out);
91 }
9692
97 pub fn final(d: &Self, out: []u8) void {93 pub fn update(d: &Self, b: []const u8) void {
98 debug.assert(out.len >= out_len / 8);94 var off: usize = 0;
9995
100 mem.set(u8, d.buf[d.buf_len..], 0);96 // Partial buffer exists from previous update. Copy into buffer then hash.
101 d.t += d.buf_len;97 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
102 d.round(d.buf[0..], true);98 off += 64 - d.buf_len;
99 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
100 d.t += 64;
101 d.round(d.buf[0..], false);
102 d.buf_len = 0;
103 }
103104
104 const rr = d.h[0 .. out_len / 32];105 // Full middle blocks.
106 while (off + 64 <= b.len) : (off += 64) {
107 d.t += 64;
108 d.round(b[off..off + 64], false);
109 }
105110
106 for (rr) |s, j| {111 // Copy any remainder for next pass.
107 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);112 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
113 d.buf_len += u8(b[off..].len);
108 }114 }
109 }
110115
111 fn round(d: &Self, b: []const u8, last: bool) void {116 pub fn final(d: &Self, out: []u8) void {
112 debug.assert(b.len == 64);117 debug.assert(out.len >= out_len / 8);
113118
114 var m: [16]u32 = undefined;119 mem.set(u8, d.buf[d.buf_len..], 0);
115 var v: [16]u32 = undefined;120 d.t += d.buf_len;
121 d.round(d.buf[0..], true);
116122
117 for (m) |*r, i| {123 const rr = d.h[0..out_len / 32];
118 *r = mem.readIntLE(u32, b[4*i .. 4*i + 4]);
119 }
120124
121 var k: usize = 0;125 for (rr) |s, j| {
122 while (k < 8) : (k += 1) {126 mem.writeInt(out[4 * j..4 * j + 4], s, builtin.Endian.Little);
123 v[k] = d.h[k];127 }
124 v[k+8] = iv[k];
125 }128 }
126129
127 v[12] ^= @truncate(u32, d.t);130 fn round(d: &Self, b: []const u8, last: bool) void {
128 v[13] ^= u32(d.t >> 32);131 debug.assert(b.len == 64);
129 if (last) v[14] = ~v[14];
130
131 const rounds = comptime []RoundParam {
132 Rp(0, 4, 8, 12, 0, 1),
133 Rp(1, 5, 9, 13, 2, 3),
134 Rp(2, 6, 10, 14, 4, 5),
135 Rp(3, 7, 11, 15, 6, 7),
136 Rp(0, 5, 10, 15, 8, 9),
137 Rp(1, 6, 11, 12, 10, 11),
138 Rp(2, 7, 8, 13, 12, 13),
139 Rp(3, 4, 9, 14, 14, 15),
140 };
141132
142 comptime var j: usize = 0;133 var m: [16]u32 = undefined;
143 inline while (j < 10) : (j += 1) {134 var v: [16]u32 = undefined;
144 inline for (rounds) |r| {135
145 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];136 for (m) |*r, i| {
146 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));137 r.* = mem.readIntLE(u32, b[4 * i..4 * i + 4]);
147 v[r.c] = v[r.c] +% v[r.d];
148 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
149 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
150 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
151 v[r.c] = v[r.c] +% v[r.d];
152 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
153 }138 }
154 }
155139
156 for (d.h) |*r, i| {140 var k: usize = 0;
157 *r ^= v[i] ^ v[i + 8];141 while (k < 8) : (k += 1) {
142 v[k] = d.h[k];
143 v[k + 8] = iv[k];
144 }
145
146 v[12] ^= @truncate(u32, d.t);
147 v[13] ^= u32(d.t >> 32);
148 if (last) v[14] = ~v[14];
149
150 const rounds = comptime []RoundParam{
151 Rp(0, 4, 8, 12, 0, 1),
152 Rp(1, 5, 9, 13, 2, 3),
153 Rp(2, 6, 10, 14, 4, 5),
154 Rp(3, 7, 11, 15, 6, 7),
155 Rp(0, 5, 10, 15, 8, 9),
156 Rp(1, 6, 11, 12, 10, 11),
157 Rp(2, 7, 8, 13, 12, 13),
158 Rp(3, 4, 9, 14, 14, 15),
159 };
160
161 comptime var j: usize = 0;
162 inline while (j < 10) : (j += 1) {
163 inline for (rounds) |r| {
164 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
165 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
166 v[r.c] = v[r.c] +% v[r.d];
167 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
168 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
169 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
170 v[r.c] = v[r.c] +% v[r.d];
171 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
172 }
173 }
174
175 for (d.h) |*r, i| {
176 r.* ^= v[i] ^ v[i + 8];
177 }
158 }178 }
159 }179 };
160};}180}
161181
162test "blake2s224 single" {182test "blake2s224 single" {
163 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";183 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
...@@ -230,7 +250,7 @@ test "blake2s256 streaming" {...@@ -230,7 +250,7 @@ test "blake2s256 streaming" {
230}250}
231251
232test "blake2s256 aligned final" {252test "blake2s256 aligned final" {
233 var block = []u8 {0} ** Blake2s256.block_size;253 var block = []u8{0} ** Blake2s256.block_size;
234 var out: [Blake2s256.digest_size]u8 = undefined;254 var out: [Blake2s256.digest_size]u8 = undefined;
235255
236 var h = Blake2s256.init();256 var h = Blake2s256.init();
...@@ -238,154 +258,363 @@ test "blake2s256 aligned final" {...@@ -238,154 +258,363 @@ test "blake2s256 aligned final" {
238 h.final(out[0..]);258 h.final(out[0..]);
239}259}
240260
241
242/////////////////////261/////////////////////
243// Blake2b262// Blake2b
244263
245pub const Blake2b384 = Blake2b(384);264pub const Blake2b384 = Blake2b(384);
246pub const Blake2b512 = Blake2b(512);265pub const Blake2b512 = Blake2b(512);
247266
248fn Blake2b(comptime out_len: usize) type { return struct {267fn Blake2b(comptime out_len: usize) type {
249 const Self = this;268 return struct {
250 const block_size = 128;269 const Self = this;
251 const digest_size = out_len / 8;270 const block_size = 128;
271 const digest_size = out_len / 8;
272
273 const iv = [8]u64{
274 0x6a09e667f3bcc908,
275 0xbb67ae8584caa73b,
276 0x3c6ef372fe94f82b,
277 0xa54ff53a5f1d36f1,
278 0x510e527fade682d1,
279 0x9b05688c2b3e6c1f,
280 0x1f83d9abfb41bd6b,
281 0x5be0cd19137e2179,
282 };
252283
253 const iv = [8]u64 {284 const sigma = [12][16]u8{
254 0x6a09e667f3bcc908, 0xbb67ae8584caa73b,285 []const u8{
255 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,286 0,
256 0x510e527fade682d1, 0x9b05688c2b3e6c1f,287 1,
257 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,288 2,
258 };289 3,
290 4,
291 5,
292 6,
293 7,
294 8,
295 9,
296 10,
297 11,
298 12,
299 13,
300 14,
301 15,
302 },
303 []const u8{
304 14,
305 10,
306 4,
307 8,
308 9,
309 15,
310 13,
311 6,
312 1,
313 12,
314 0,
315 2,
316 11,
317 7,
318 5,
319 3,
320 },
321 []const u8{
322 11,
323 8,
324 12,
325 0,
326 5,
327 2,
328 15,
329 13,
330 10,
331 14,
332 3,
333 6,
334 7,
335 1,
336 9,
337 4,
338 },
339 []const u8{
340 7,
341 9,
342 3,
343 1,
344 13,
345 12,
346 11,
347 14,
348 2,
349 6,
350 5,
351 10,
352 4,
353 0,
354 15,
355 8,
356 },
357 []const u8{
358 9,
359 0,
360 5,
361 7,
362 2,
363 4,
364 10,
365 15,
366 14,
367 1,
368 11,
369 12,
370 6,
371 8,
372 3,
373 13,
374 },
375 []const u8{
376 2,
377 12,
378 6,
379 10,
380 0,
381 11,
382 8,
383 3,
384 4,
385 13,
386 7,
387 5,
388 15,
389 14,
390 1,
391 9,
392 },
393 []const u8{
394 12,
395 5,
396 1,
397 15,
398 14,
399 13,
400 4,
401 10,
402 0,
403 7,
404 6,
405 3,
406 9,
407 2,
408 8,
409 11,
410 },
411 []const u8{
412 13,
413 11,
414 7,
415 14,
416 12,
417 1,
418 3,
419 9,
420 5,
421 0,
422 15,
423 4,
424 8,
425 6,
426 2,
427 10,
428 },
429 []const u8{
430 6,
431 15,
432 14,
433 9,
434 11,
435 3,
436 0,
437 8,
438 12,
439 2,
440 13,
441 7,
442 1,
443 4,
444 10,
445 5,
446 },
447 []const u8{
448 10,
449 2,
450 8,
451 4,
452 7,
453 6,
454 1,
455 5,
456 15,
457 11,
458 9,
459 14,
460 3,
461 12,
462 13,
463 0,
464 },
465 []const u8{
466 0,
467 1,
468 2,
469 3,
470 4,
471 5,
472 6,
473 7,
474 8,
475 9,
476 10,
477 11,
478 12,
479 13,
480 14,
481 15,
482 },
483 []const u8{
484 14,
485 10,
486 4,
487 8,
488 9,
489 15,
490 13,
491 6,
492 1,
493 12,
494 0,
495 2,
496 11,
497 7,
498 5,
499 3,
500 },
501 };
259502
260 const sigma = [12][16]u8 {503 h: [8]u64,
261 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },504 t: u128,
262 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },505 // Streaming cache
263 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },506 buf: [128]u8,
264 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },507 buf_len: u8,
265 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
266 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
267 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
268 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
269 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
270 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 },
271 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
272 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
273 };
274508
275 h: [8]u64,509 pub fn init() Self {
276 t: u128,510 debug.assert(8 <= out_len and out_len <= 512);
277 // Streaming cache511
278 buf: [128]u8,512 var s: Self = undefined;
279 buf_len: u8,513 s.reset();
280514 return s;
281 pub fn init() Self {515 }
282 debug.assert(8 <= out_len and out_len <= 512);516
283517 pub fn reset(d: &Self) void {
284 var s: Self = undefined;518 mem.copy(u64, d.h[0..], iv[0..]);
285 s.reset();519
286 return s;520 // No key plus default parameters
287 }521 d.h[0] ^= 0x01010000 ^ (out_len >> 3);
288522 d.t = 0;
289 pub fn reset(d: &Self) void {
290 mem.copy(u64, d.h[0..], iv[0..]);
291
292 // No key plus default parameters
293 d.h[0] ^= 0x01010000 ^ (out_len >> 3);
294 d.t = 0;
295 d.buf_len = 0;
296 }
297
298 pub fn hash(b: []const u8, out: []u8) void {
299 var d = Self.init();
300 d.update(b);
301 d.final(out);
302 }
303
304 pub fn update(d: &Self, b: []const u8) void {
305 var off: usize = 0;
306
307 // Partial buffer exists from previous update. Copy into buffer then hash.
308 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
309 off += 128 - d.buf_len;
310 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
311 d.t += 128;
312 d.round(d.buf[0..], false);
313 d.buf_len = 0;523 d.buf_len = 0;
314 }524 }
315525
316 // Full middle blocks.526 pub fn hash(b: []const u8, out: []u8) void {
317 while (off + 128 <= b.len) : (off += 128) {527 var d = Self.init();
318 d.t += 128;528 d.update(b);
319 d.round(b[off..off + 128], false);529 d.final(out);
320 }530 }
321531
322 // Copy any remainder for next pass.532 pub fn update(d: &Self, b: []const u8) void {
323 mem.copy(u8, d.buf[d.buf_len..], b[off..]);533 var off: usize = 0;
324 d.buf_len += u8(b[off..].len);
325 }
326534
327 pub fn final(d: &Self, out: []u8) void {535 // Partial buffer exists from previous update. Copy into buffer then hash.
328 mem.set(u8, d.buf[d.buf_len..], 0);536 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
329 d.t += d.buf_len;537 off += 128 - d.buf_len;
330 d.round(d.buf[0..], true);538 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
539 d.t += 128;
540 d.round(d.buf[0..], false);
541 d.buf_len = 0;
542 }
331543
332 const rr = d.h[0 .. out_len / 64];544 // Full middle blocks.
545 while (off + 128 <= b.len) : (off += 128) {
546 d.t += 128;
547 d.round(b[off..off + 128], false);
548 }
333549
334 for (rr) |s, j| {550 // Copy any remainder for next pass.
335 mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Little);551 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
552 d.buf_len += u8(b[off..].len);
336 }553 }
337 }
338554
339 fn round(d: &Self, b: []const u8, last: bool) void {555 pub fn final(d: &Self, out: []u8) void {
340 debug.assert(b.len == 128);556 mem.set(u8, d.buf[d.buf_len..], 0);
557 d.t += d.buf_len;
558 d.round(d.buf[0..], true);
341559
342 var m: [16]u64 = undefined;560 const rr = d.h[0..out_len / 64];
343 var v: [16]u64 = undefined;
344561
345 for (m) |*r, i| {562 for (rr) |s, j| {
346 *r = mem.readIntLE(u64, b[8*i .. 8*i + 8]);563 mem.writeInt(out[8 * j..8 * j + 8], s, builtin.Endian.Little);
564 }
347 }565 }
348566
349 var k: usize = 0;567 fn round(d: &Self, b: []const u8, last: bool) void {
350 while (k < 8) : (k += 1) {568 debug.assert(b.len == 128);
351 v[k] = d.h[k];
352 v[k+8] = iv[k];
353 }
354569
355 v[12] ^= @truncate(u64, d.t);570 var m: [16]u64 = undefined;
356 v[13] ^= u64(d.t >> 64);571 var v: [16]u64 = undefined;
357 if (last) v[14] = ~v[14];
358
359 const rounds = comptime []RoundParam {
360 Rp(0, 4, 8, 12, 0, 1),
361 Rp(1, 5, 9, 13, 2, 3),
362 Rp(2, 6, 10, 14, 4, 5),
363 Rp(3, 7, 11, 15, 6, 7),
364 Rp(0, 5, 10, 15, 8, 9),
365 Rp(1, 6, 11, 12, 10, 11),
366 Rp(2, 7, 8, 13, 12, 13),
367 Rp(3, 4, 9, 14, 14, 15),
368 };
369572
370 comptime var j: usize = 0;573 for (m) |*r, i| {
371 inline while (j < 12) : (j += 1) {574 r.* = mem.readIntLE(u64, b[8 * i..8 * i + 8]);
372 inline for (rounds) |r| {575 }
373 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];576
374 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));577 var k: usize = 0;
375 v[r.c] = v[r.c] +% v[r.d];578 while (k < 8) : (k += 1) {
376 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));579 v[k] = d.h[k];
377 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];580 v[k + 8] = iv[k];
378 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
379 v[r.c] = v[r.c] +% v[r.d];
380 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
381 }581 }
382 }
383582
384 for (d.h) |*r, i| {583 v[12] ^= @truncate(u64, d.t);
385 *r ^= v[i] ^ v[i + 8];584 v[13] ^= u64(d.t >> 64);
585 if (last) v[14] = ~v[14];
586
587 const rounds = comptime []RoundParam{
588 Rp(0, 4, 8, 12, 0, 1),
589 Rp(1, 5, 9, 13, 2, 3),
590 Rp(2, 6, 10, 14, 4, 5),
591 Rp(3, 7, 11, 15, 6, 7),
592 Rp(0, 5, 10, 15, 8, 9),
593 Rp(1, 6, 11, 12, 10, 11),
594 Rp(2, 7, 8, 13, 12, 13),
595 Rp(3, 4, 9, 14, 14, 15),
596 };
597
598 comptime var j: usize = 0;
599 inline while (j < 12) : (j += 1) {
600 inline for (rounds) |r| {
601 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
602 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
603 v[r.c] = v[r.c] +% v[r.d];
604 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
605 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
606 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
607 v[r.c] = v[r.c] +% v[r.d];
608 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
609 }
610 }
611
612 for (d.h) |*r, i| {
613 r.* ^= v[i] ^ v[i + 8];
614 }
386 }615 }
387 }616 };
388};}617}
389618
390test "blake2b384 single" {619test "blake2b384 single" {
391 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";620 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
...@@ -458,7 +687,7 @@ test "blake2b512 streaming" {...@@ -458,7 +687,7 @@ test "blake2b512 streaming" {
458}687}
459688
460test "blake2b512 aligned final" {689test "blake2b512 aligned final" {
461 var block = []u8 {0} ** Blake2b512.block_size;690 var block = []u8{0} ** Blake2b512.block_size;
462 var out: [Blake2b512.digest_size]u8 = undefined;691 var out: [Blake2b512.digest_size]u8 = undefined;
463692
464 var h = Blake2b512.init();693 var h = Blake2b512.init();
std/crypto/hmac.zig+2-2
...@@ -29,12 +29,12 @@ pub fn Hmac(comptime H: type) type {...@@ -29,12 +29,12 @@ pub fn Hmac(comptime H: type) type {
2929
30 var o_key_pad: [H.block_size]u8 = undefined;30 var o_key_pad: [H.block_size]u8 = undefined;
31 for (o_key_pad) |*b, i| {31 for (o_key_pad) |*b, i| {
32 *b = scratch[i] ^ 0x5c;32 b.* = scratch[i] ^ 0x5c;
33 }33 }
3434
35 var i_key_pad: [H.block_size]u8 = undefined;35 var i_key_pad: [H.block_size]u8 = undefined;
36 for (i_key_pad) |*b, i| {36 for (i_key_pad) |*b, i| {
37 *b = scratch[i] ^ 0x36;37 b.* = scratch[i] ^ 0x36;
38 }38 }
3939
40 // HMAC(k, m) = H(o_key_pad | H(i_key_pad | message)) where | is concatenation40 // HMAC(k, m) = H(o_key_pad | H(i_key_pad | message)) where | is concatenation
std/crypto/sha3.zig+180-101
...@@ -10,148 +10,228 @@ pub const Sha3_256 = Keccak(256, 0x06);...@@ -10,148 +10,228 @@ pub const Sha3_256 = Keccak(256, 0x06);
10pub const Sha3_384 = Keccak(384, 0x06);10pub const Sha3_384 = Keccak(384, 0x06);
11pub const Sha3_512 = Keccak(512, 0x06);11pub const Sha3_512 = Keccak(512, 0x06);
1212
13fn Keccak(comptime bits: usize, comptime delim: u8) type { return struct {13fn Keccak(comptime bits: usize, comptime delim: u8) type {
14 const Self = this;14 return struct {
15 const block_size = 200;15 const Self = this;
16 const digest_size = bits / 8;16 const block_size = 200;
1717 const digest_size = bits / 8;
18 s: [200]u8,18
19 offset: usize,19 s: [200]u8,
20 rate: usize,20 offset: usize,
2121 rate: usize,
22 pub fn init() Self {22
23 var d: Self = undefined;23 pub fn init() Self {
24 d.reset();24 var d: Self = undefined;
25 return d;25 d.reset();
26 }26 return d;
27 }
2728
28 pub fn reset(d: &Self) void {29 pub fn reset(d: &Self) void {
29 mem.set(u8, d.s[0..], 0);30 mem.set(u8, d.s[0..], 0);
30 d.offset = 0;31 d.offset = 0;
31 d.rate = 200 - (bits / 4);32 d.rate = 200 - (bits / 4);
32 }33 }
3334
34 pub fn hash(b: []const u8, out: []u8) void {35 pub fn hash(b: []const u8, out: []u8) void {
35 var d = Self.init();36 var d = Self.init();
36 d.update(b);37 d.update(b);
37 d.final(out);38 d.final(out);
38 }39 }
3940
40 pub fn update(d: &Self, b: []const u8) void {41 pub fn update(d: &Self, b: []const u8) void {
41 var ip: usize = 0;42 var ip: usize = 0;
42 var len = b.len;43 var len = b.len;
43 var rate = d.rate - d.offset;44 var rate = d.rate - d.offset;
44 var offset = d.offset;45 var offset = d.offset;
4546
46 // absorb47 // absorb
47 while (len >= rate) {48 while (len >= rate) {
48 for (d.s[offset .. offset + rate]) |*r, i|49 for (d.s[offset..offset + rate]) |*r, i|
49 *r ^= b[ip..][i];50 r.* ^= b[ip..][i];
5051
51 keccak_f(1600, d.s[0..]);52 keccak_f(1600, d.s[0..]);
5253
53 ip += rate;54 ip += rate;
54 len -= rate;55 len -= rate;
55 rate = d.rate;56 rate = d.rate;
56 offset = 0;57 offset = 0;
57 }58 }
5859
59 for (d.s[offset .. offset + len]) |*r, i|60 for (d.s[offset..offset + len]) |*r, i|
60 *r ^= b[ip..][i];61 r.* ^= b[ip..][i];
6162
62 d.offset = offset + len;63 d.offset = offset + len;
63 }64 }
6465
65 pub fn final(d: &Self, out: []u8) void {66 pub fn final(d: &Self, out: []u8) void {
66 // padding67 // padding
67 d.s[d.offset] ^= delim;68 d.s[d.offset] ^= delim;
68 d.s[d.rate - 1] ^= 0x80;69 d.s[d.rate - 1] ^= 0x80;
6970
70 keccak_f(1600, d.s[0..]);71 keccak_f(1600, d.s[0..]);
7172
72 // squeeze73 // squeeze
73 var op: usize = 0;74 var op: usize = 0;
74 var len: usize = bits / 8;75 var len: usize = bits / 8;
7576
76 while (len >= d.rate) {77 while (len >= d.rate) {
77 mem.copy(u8, out[op..], d.s[0..d.rate]);78 mem.copy(u8, out[op..], d.s[0..d.rate]);
78 keccak_f(1600, d.s[0..]);79 keccak_f(1600, d.s[0..]);
79 op += d.rate;80 op += d.rate;
80 len -= d.rate;81 len -= d.rate;
82 }
83
84 mem.copy(u8, out[op..], d.s[0..len]);
81 }85 }
86 };
87}
8288
83 mem.copy(u8, out[op..], d.s[0..len]);89const RC = []const u64{
84 }90 0x0000000000000001,
85};}91 0x0000000000008082,
8692 0x800000000000808a,
87const RC = []const u64 {93 0x8000000080008000,
88 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,94 0x000000000000808b,
89 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,95 0x0000000080000001,
90 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,96 0x8000000080008081,
91 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,97 0x8000000000008009,
92 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,98 0x000000000000008a,
93 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,99 0x0000000000000088,
100 0x0000000080008009,
101 0x000000008000000a,
102 0x000000008000808b,
103 0x800000000000008b,
104 0x8000000000008089,
105 0x8000000000008003,
106 0x8000000000008002,
107 0x8000000000000080,
108 0x000000000000800a,
109 0x800000008000000a,
110 0x8000000080008081,
111 0x8000000000008080,
112 0x0000000080000001,
113 0x8000000080008008,
94};114};
95115
96const ROTC = []const usize {116const ROTC = []const usize{
97 1, 3, 6, 10, 15, 21, 28, 36,117 1,
98 45, 55, 2, 14, 27, 41, 56, 8,118 3,
99 25, 43, 62, 18, 39, 61, 20, 44119 6,
120 10,
121 15,
122 21,
123 28,
124 36,
125 45,
126 55,
127 2,
128 14,
129 27,
130 41,
131 56,
132 8,
133 25,
134 43,
135 62,
136 18,
137 39,
138 61,
139 20,
140 44,
100};141};
101142
102const PIL = []const usize {143const PIL = []const usize{
103 10, 7, 11, 17, 18, 3, 5, 16,144 10,
104 8, 21, 24, 4, 15, 23, 19, 13,145 7,
105 12, 2, 20, 14, 22, 9, 6, 1146 11,
147 17,
148 18,
149 3,
150 5,
151 16,
152 8,
153 21,
154 24,
155 4,
156 15,
157 23,
158 19,
159 13,
160 12,
161 2,
162 20,
163 14,
164 22,
165 9,
166 6,
167 1,
106};168};
107169
108const M5 = []const usize {170const M5 = []const usize{
109 0, 1, 2, 3, 4, 0, 1, 2, 3, 4171 0,
172 1,
173 2,
174 3,
175 4,
176 0,
177 1,
178 2,
179 3,
180 4,
110};181};
111182
112fn keccak_f(comptime F: usize, d: []u8) void {183fn keccak_f(comptime F: usize, d: []u8) void {
113 debug.assert(d.len == F / 8);184 debug.assert(d.len == F / 8);
114185
115 const B = F / 25;186 const B = F / 25;
116 const no_rounds = comptime x: { break :x 12 + 2 * math.log2(B); };187 const no_rounds = comptime x: {
188 break :x 12 + 2 * math.log2(B);
189 };
117190
118 var s = []const u64 {0} ** 25;191 var s = []const u64{0} ** 25;
119 var t = []const u64 {0} ** 1;192 var t = []const u64{0} ** 1;
120 var c = []const u64 {0} ** 5;193 var c = []const u64{0} ** 5;
121194
122 for (s) |*r, i| {195 for (s) |*r, i| {
123 *r = mem.readIntLE(u64, d[8*i .. 8*i + 8]);196 r.* = mem.readIntLE(u64, d[8 * i..8 * i + 8]);
124 }197 }
125198
126 comptime var x: usize = 0;199 comptime var x: usize = 0;
127 comptime var y: usize = 0;200 comptime var y: usize = 0;
128 for (RC[0..no_rounds]) |round| {201 for (RC[0..no_rounds]) |round| {
129 // theta202 // theta
130 x = 0; inline while (x < 5) : (x += 1) {203 x = 0;
131 c[x] = s[x] ^ s[x+5] ^ s[x+10] ^ s[x+15] ^ s[x+20];204 inline while (x < 5) : (x += 1) {
205 c[x] = s[x] ^ s[x + 5] ^ s[x + 10] ^ s[x + 15] ^ s[x + 20];
132 }206 }
133 x = 0; inline while (x < 5) : (x += 1) {207 x = 0;
134 t[0] = c[M5[x+4]] ^ math.rotl(u64, c[M5[x+1]], usize(1));208 inline while (x < 5) : (x += 1) {
135 y = 0; inline while (y < 5) : (y += 1) {209 t[0] = c[M5[x + 4]] ^ math.rotl(u64, c[M5[x + 1]], usize(1));
136 s[x + y*5] ^= t[0];210 y = 0;
211 inline while (y < 5) : (y += 1) {
212 s[x + y * 5] ^= t[0];
137 }213 }
138 }214 }
139215
140 // rho+pi216 // rho+pi
141 t[0] = s[1];217 t[0] = s[1];
142 x = 0; inline while (x < 24) : (x += 1) {218 x = 0;
219 inline while (x < 24) : (x += 1) {
143 c[0] = s[PIL[x]];220 c[0] = s[PIL[x]];
144 s[PIL[x]] = math.rotl(u64, t[0], ROTC[x]);221 s[PIL[x]] = math.rotl(u64, t[0], ROTC[x]);
145 t[0] = c[0];222 t[0] = c[0];
146 }223 }
147224
148 // chi225 // chi
149 y = 0; inline while (y < 5) : (y += 1) {226 y = 0;
150 x = 0; inline while (x < 5) : (x += 1) {227 inline while (y < 5) : (y += 1) {
151 c[x] = s[x + y*5];228 x = 0;
229 inline while (x < 5) : (x += 1) {
230 c[x] = s[x + y * 5];
152 }231 }
153 x = 0; inline while (x < 5) : (x += 1) {232 x = 0;
154 s[x + y*5] = c[x] ^ (~c[M5[x+1]] & c[M5[x+2]]);233 inline while (x < 5) : (x += 1) {
234 s[x + y * 5] = c[x] ^ (~c[M5[x + 1]] & c[M5[x + 2]]);
155 }235 }
156 }236 }
157237
...@@ -160,11 +240,10 @@ fn keccak_f(comptime F: usize, d: []u8) void {...@@ -160,11 +240,10 @@ fn keccak_f(comptime F: usize, d: []u8) void {
160 }240 }
161241
162 for (s) |r, i| {242 for (s) |r, i| {
163 mem.writeInt(d[8*i .. 8*i + 8], r, builtin.Endian.Little);243 mem.writeInt(d[8 * i..8 * i + 8], r, builtin.Endian.Little);
164 }244 }
165}245}
166246
167
168test "sha3-224 single" {247test "sha3-224 single" {
169 htest.assertEqualHash(Sha3_224, "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", "");248 htest.assertEqualHash(Sha3_224, "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", "");
170 htest.assertEqualHash(Sha3_224, "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc");249 htest.assertEqualHash(Sha3_224, "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc");
...@@ -192,7 +271,7 @@ test "sha3-224 streaming" {...@@ -192,7 +271,7 @@ test "sha3-224 streaming" {
192}271}
193272
194test "sha3-256 single" {273test "sha3-256 single" {
195 htest.assertEqualHash(Sha3_256, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" , "");274 htest.assertEqualHash(Sha3_256, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", "");
196 htest.assertEqualHash(Sha3_256, "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc");275 htest.assertEqualHash(Sha3_256, "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc");
197 htest.assertEqualHash(Sha3_256, "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");276 htest.assertEqualHash(Sha3_256, "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
198}277}
...@@ -218,7 +297,7 @@ test "sha3-256 streaming" {...@@ -218,7 +297,7 @@ test "sha3-256 streaming" {
218}297}
219298
220test "sha3-256 aligned final" {299test "sha3-256 aligned final" {
221 var block = []u8 {0} ** Sha3_256.block_size;300 var block = []u8{0} ** Sha3_256.block_size;
222 var out: [Sha3_256.digest_size]u8 = undefined;301 var out: [Sha3_256.digest_size]u8 = undefined;
223302
224 var h = Sha3_256.init();303 var h = Sha3_256.init();
...@@ -228,7 +307,7 @@ test "sha3-256 aligned final" {...@@ -228,7 +307,7 @@ test "sha3-256 aligned final" {
228307
229test "sha3-384 single" {308test "sha3-384 single" {
230 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";309 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
231 htest.assertEqualHash(Sha3_384, h1 , "");310 htest.assertEqualHash(Sha3_384, h1, "");
232 const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25";311 const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25";
233 htest.assertEqualHash(Sha3_384, h2, "abc");312 htest.assertEqualHash(Sha3_384, h2, "abc");
234 const h3 = "79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7";313 const h3 = "79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7";
...@@ -259,7 +338,7 @@ test "sha3-384 streaming" {...@@ -259,7 +338,7 @@ test "sha3-384 streaming" {
259338
260test "sha3-512 single" {339test "sha3-512 single" {
261 const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26";340 const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26";
262 htest.assertEqualHash(Sha3_512, h1 , "");341 htest.assertEqualHash(Sha3_512, h1, "");
263 const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0";342 const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0";
264 htest.assertEqualHash(Sha3_512, h2, "abc");343 htest.assertEqualHash(Sha3_512, h2, "abc");
265 const h3 = "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185";344 const h3 = "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185";
...@@ -289,7 +368,7 @@ test "sha3-512 streaming" {...@@ -289,7 +368,7 @@ test "sha3-512 streaming" {
289}368}
290369
291test "sha3-512 aligned final" {370test "sha3-512 aligned final" {
292 var block = []u8 {0} ** Sha3_512.block_size;371 var block = []u8{0} ** Sha3_512.block_size;
293 var out: [Sha3_512.digest_size]u8 = undefined;372 var out: [Sha3_512.digest_size]u8 = undefined;
294373
295 var h = Sha3_512.init();374 var h = Sha3_512.init();
std/crypto/test.zig+1-2
...@@ -14,9 +14,8 @@ pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, inpu...@@ -14,9 +14,8 @@ pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, inpu
14pub fn assertEqual(comptime expected: []const u8, input: []const u8) void {14pub fn assertEqual(comptime expected: []const u8, input: []const u8) void {
15 var expected_bytes: [expected.len / 2]u8 = undefined;15 var expected_bytes: [expected.len / 2]u8 = undefined;
16 for (expected_bytes) |*r, i| {16 for (expected_bytes) |*r, i| {
17 *r = fmt.parseInt(u8, expected[2*i .. 2*i+2], 16) catch unreachable;17 r.* = fmt.parseInt(u8, expected[2 * i .. 2 * i + 2], 16) catch unreachable;
18 }18 }
1919
20 debug.assert(mem.eql(u8, expected_bytes, input));20 debug.assert(mem.eql(u8, expected_bytes, input));
21}21}
22
std/debug/index.zig+98-135
...@@ -104,9 +104,7 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn {...@@ -104,9 +104,7 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn {
104104
105var panicking: u8 = 0; // TODO make this a bool105var panicking: u8 = 0; // TODO make this a bool
106106
107pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize,107pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
108 comptime format: []const u8, args: ...) noreturn
109{
110 @setCold(true);108 @setCold(true);
111109
112 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {110 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
...@@ -132,9 +130,7 @@ const WHITE = "\x1b[37;1m";...@@ -132,9 +130,7 @@ const WHITE = "\x1b[37;1m";
132const DIM = "\x1b[2m";130const DIM = "\x1b[2m";
133const RESET = "\x1b[0m";131const RESET = "\x1b[0m";
134132
135pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator,133pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator, debug_info: &ElfStackTrace, tty_color: bool) !void {
136 debug_info: &ElfStackTrace, tty_color: bool) !void
137{
138 var frame_index: usize = undefined;134 var frame_index: usize = undefined;
139 var frames_left: usize = undefined;135 var frames_left: usize = undefined;
140 if (stack_trace.index < stack_trace.instruction_addresses.len) {136 if (stack_trace.index < stack_trace.instruction_addresses.len) {
...@@ -154,9 +150,7 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var,...@@ -154,9 +150,7 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var,
154 }150 }
155}151}
156152
157pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,153pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator, debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void {
158 debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void
159{
160 const AddressState = union(enum) {154 const AddressState = union(enum) {
161 NotLookingForStartAddress,155 NotLookingForStartAddress,
162 LookingForStartAddress: usize,156 LookingForStartAddress: usize,
...@@ -166,14 +160,14 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,...@@ -166,14 +160,14 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
166 // else AddressState.NotLookingForStartAddress;160 // else AddressState.NotLookingForStartAddress;
167 var addr_state: AddressState = undefined;161 var addr_state: AddressState = undefined;
168 if (start_addr) |addr| {162 if (start_addr) |addr| {
169 addr_state = AddressState { .LookingForStartAddress = addr };163 addr_state = AddressState{ .LookingForStartAddress = addr };
170 } else {164 } else {
171 addr_state = AddressState.NotLookingForStartAddress;165 addr_state = AddressState.NotLookingForStartAddress;
172 }166 }
173167
174 var fp = @ptrToInt(@frameAddress());168 var fp = @ptrToInt(@frameAddress());
175 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {169 while (fp != 0) : (fp = @intToPtr(&const usize, fp).*) {
176 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));170 const return_address = @intToPtr(&const usize, fp + @sizeOf(usize)).*;
177171
178 switch (addr_state) {172 switch (addr_state) {
179 AddressState.NotLookingForStartAddress => {},173 AddressState.NotLookingForStartAddress => {},
...@@ -200,32 +194,32 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us...@@ -200,32 +194,32 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us
200 // in practice because the compiler dumps everything in a single194 // in practice because the compiler dumps everything in a single
201 // object file. Future improvement: use external dSYM data when195 // object file. Future improvement: use external dSYM data when
202 // available.196 // available.
203 const unknown = macho.Symbol { .name = "???", .address = address };197 const unknown = macho.Symbol{
198 .name = "???",
199 .address = address,
200 };
204 const symbol = debug_info.symbol_table.search(address) ?? &unknown;201 const symbol = debug_info.symbol_table.search(address) ?? &unknown;
205 try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++202 try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n", symbol.name, address);
206 DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n",
207 symbol.name, address);
208 },203 },
209 else => {204 else => {
210 const compile_unit = findCompileUnit(debug_info, address) catch {205 const compile_unit = findCompileUnit(debug_info, address) catch {
211 try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",206 try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n", address);
212 address);
213 return;207 return;
214 };208 };
215 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);209 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
216 if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| {210 if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| {
217 defer line_info.deinit();211 defer line_info.deinit();
218 try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++212 try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n", line_info.file_name, line_info.line, line_info.column, address, compile_unit_name);
219 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
220 line_info.file_name, line_info.line, line_info.column,
221 address, compile_unit_name);
222 if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) {213 if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) {
223 if (line_info.column == 0) {214 if (line_info.column == 0) {
224 try out_stream.write("\n");215 try out_stream.write("\n");
225 } else {216 } else {
226 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {217 {
227 try out_stream.writeByte(' ');218 var col_i: usize = 1;
228 }}219 while (col_i < line_info.column) : (col_i += 1) {
220 try out_stream.writeByte(' ');
221 }
222 }
229 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");223 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
230 }224 }
231 } else |err| switch (err) {225 } else |err| switch (err) {
...@@ -233,7 +227,8 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us...@@ -233,7 +227,8 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: us
233 else => return err,227 else => return err,
234 }228 }
235 } else |err| switch (err) {229 } else |err| switch (err) {
236 error.MissingDebugInfo, error.InvalidDebugInfo => {230 error.MissingDebugInfo,
231 error.InvalidDebugInfo => {
237 try out_stream.print(ptr_hex ++ " in ??? ({})\n", address, compile_unit_name);232 try out_stream.print(ptr_hex ++ " in ??? ({})\n", address, compile_unit_name);
238 },233 },
239 else => return err,234 else => return err,
...@@ -247,7 +242,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {...@@ -247,7 +242,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
247 builtin.ObjectFormat.elf => {242 builtin.ObjectFormat.elf => {
248 const st = try allocator.create(ElfStackTrace);243 const st = try allocator.create(ElfStackTrace);
249 errdefer allocator.destroy(st);244 errdefer allocator.destroy(st);
250 *st = ElfStackTrace {245 st.* = ElfStackTrace{
251 .self_exe_file = undefined,246 .self_exe_file = undefined,
252 .elf = undefined,247 .elf = undefined,
253 .debug_info = undefined,248 .debug_info = undefined,
...@@ -279,9 +274,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {...@@ -279,9 +274,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
279 const st = try allocator.create(ElfStackTrace);274 const st = try allocator.create(ElfStackTrace);
280 errdefer allocator.destroy(st);275 errdefer allocator.destroy(st);
281276
282 *st = ElfStackTrace {277 st.* = ElfStackTrace{ .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)) };
283 .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)),
284 };
285278
286 return st;279 return st;
287 },280 },
...@@ -325,8 +318,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &con...@@ -325,8 +318,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &con
325 }318 }
326 }319 }
327320
328 if (amt_read < buf.len)321 if (amt_read < buf.len) return error.EndOfFile;
329 return error.EndOfFile;
330 }322 }
331}323}
332324
...@@ -418,10 +410,8 @@ const Constant = struct {...@@ -418,10 +410,8 @@ const Constant = struct {
418 signed: bool,410 signed: bool,
419411
420 fn asUnsignedLe(self: &const Constant) !u64 {412 fn asUnsignedLe(self: &const Constant) !u64 {
421 if (self.payload.len > @sizeOf(u64))413 if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
422 return error.InvalidDebugInfo;414 if (self.signed) return error.InvalidDebugInfo;
423 if (self.signed)
424 return error.InvalidDebugInfo;
425 return mem.readInt(self.payload, u64, builtin.Endian.Little);415 return mem.readInt(self.payload, u64, builtin.Endian.Little);
426 }416 }
427};417};
...@@ -438,15 +428,14 @@ const Die = struct {...@@ -438,15 +428,14 @@ const Die = struct {
438428
439 fn getAttr(self: &const Die, id: u64) ?&const FormValue {429 fn getAttr(self: &const Die, id: u64) ?&const FormValue {
440 for (self.attrs.toSliceConst()) |*attr| {430 for (self.attrs.toSliceConst()) |*attr| {
441 if (attr.id == id)431 if (attr.id == id) return &attr.value;
442 return &attr.value;
443 }432 }
444 return null;433 return null;
445 }434 }
446435
447 fn getAttrAddr(self: &const Die, id: u64) !u64 {436 fn getAttrAddr(self: &const Die, id: u64) !u64 {
448 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;437 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
449 return switch (*form_value) {438 return switch (form_value.*) {
450 FormValue.Address => |value| value,439 FormValue.Address => |value| value,
451 else => error.InvalidDebugInfo,440 else => error.InvalidDebugInfo,
452 };441 };
...@@ -454,7 +443,7 @@ const Die = struct {...@@ -454,7 +443,7 @@ const Die = struct {
454443
455 fn getAttrSecOffset(self: &const Die, id: u64) !u64 {444 fn getAttrSecOffset(self: &const Die, id: u64) !u64 {
456 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;445 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
457 return switch (*form_value) {446 return switch (form_value.*) {
458 FormValue.Const => |value| value.asUnsignedLe(),447 FormValue.Const => |value| value.asUnsignedLe(),
459 FormValue.SecOffset => |value| value,448 FormValue.SecOffset => |value| value,
460 else => error.InvalidDebugInfo,449 else => error.InvalidDebugInfo,
...@@ -463,7 +452,7 @@ const Die = struct {...@@ -463,7 +452,7 @@ const Die = struct {
463452
464 fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 {453 fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 {
465 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;454 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
466 return switch (*form_value) {455 return switch (form_value.*) {
467 FormValue.Const => |value| value.asUnsignedLe(),456 FormValue.Const => |value| value.asUnsignedLe(),
468 else => error.InvalidDebugInfo,457 else => error.InvalidDebugInfo,
469 };458 };
...@@ -471,7 +460,7 @@ const Die = struct {...@@ -471,7 +460,7 @@ const Die = struct {
471460
472 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 {461 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 {
473 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;462 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
474 return switch (*form_value) {463 return switch (form_value.*) {
475 FormValue.String => |value| value,464 FormValue.String => |value| value,
476 FormValue.StrPtr => |offset| getString(st, offset),465 FormValue.StrPtr => |offset| getString(st, offset),
477 else => error.InvalidDebugInfo,466 else => error.InvalidDebugInfo,
...@@ -518,10 +507,8 @@ const LineNumberProgram = struct {...@@ -518,10 +507,8 @@ const LineNumberProgram = struct {
518 prev_basic_block: bool,507 prev_basic_block: bool,
519 prev_end_sequence: bool,508 prev_end_sequence: bool,
520509
521 pub fn init(is_stmt: bool, include_dirs: []const []const u8,510 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: &ArrayList(FileEntry), target_address: usize) LineNumberProgram {
522 file_entries: &ArrayList(FileEntry), target_address: usize) LineNumberProgram511 return LineNumberProgram{
523 {
524 return LineNumberProgram {
525 .address = 0,512 .address = 0,
526 .file = 1,513 .file = 1,
527 .line = 1,514 .line = 1,
...@@ -548,14 +535,16 @@ const LineNumberProgram = struct {...@@ -548,14 +535,16 @@ const LineNumberProgram = struct {
548 return error.MissingDebugInfo;535 return error.MissingDebugInfo;
549 } else if (self.prev_file - 1 >= self.file_entries.len) {536 } else if (self.prev_file - 1 >= self.file_entries.len) {
550 return error.InvalidDebugInfo;537 return error.InvalidDebugInfo;
551 } else &self.file_entries.items[self.prev_file - 1];538 } else
539 &self.file_entries.items[self.prev_file - 1];
552540
553 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {541 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
554 return error.InvalidDebugInfo;542 return error.InvalidDebugInfo;
555 } else self.include_dirs[file_entry.dir_index];543 } else
544 self.include_dirs[file_entry.dir_index];
556 const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);545 const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
557 errdefer self.file_entries.allocator.free(file_name);546 errdefer self.file_entries.allocator.free(file_name);
558 return LineInfo {547 return LineInfo{
559 .line = if (self.prev_line >= 0) usize(self.prev_line) else 0,548 .line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
560 .column = self.prev_column,549 .column = self.prev_column,
561 .file_name = file_name,550 .file_name = file_name,
...@@ -578,8 +567,7 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: var) ![]u8 {...@@ -578,8 +567,7 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: var) ![]u8 {
578 var buf = ArrayList(u8).init(allocator);567 var buf = ArrayList(u8).init(allocator);
579 while (true) {568 while (true) {
580 const byte = try in_stream.readByte();569 const byte = try in_stream.readByte();
581 if (byte == 0)570 if (byte == 0) break;
582 break;
583 try buf.append(byte);571 try buf.append(byte);
584 }572 }
585 return buf.toSlice();573 return buf.toSlice();
...@@ -600,7 +588,7 @@ fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8...@@ -600,7 +588,7 @@ fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8
600588
601fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {589fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
602 const buf = try readAllocBytes(allocator, in_stream, size);590 const buf = try readAllocBytes(allocator, in_stream, size);
603 return FormValue { .Block = buf };591 return FormValue{ .Block = buf };
604}592}
605593
606fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {594fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
...@@ -609,26 +597,23 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !...@@ -609,26 +597,23 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !
609}597}
610598
611fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {599fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
612 return FormValue { .Const = Constant {600 return FormValue{ .Const = Constant{
613 .signed = signed,601 .signed = signed,
614 .payload = try readAllocBytes(allocator, in_stream, size),602 .payload = try readAllocBytes(allocator, in_stream, size),
615 }};603 } };
616}604}
617605
618fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {606fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
619 return if (is_64) try in_stream.readIntLe(u64)607 return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32));
620 else u64(try in_stream.readIntLe(u32)) ;
621}608}
622609
623fn parseFormValueTargetAddrSize(in_stream: var) !u64 {610fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
624 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32))611 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable;
625 else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64)
626 else unreachable;
627}612}
628613
629fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {614fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue {
630 const buf = try readAllocBytes(allocator, in_stream, size);615 const buf = try readAllocBytes(allocator, in_stream, size);
631 return FormValue { .Ref = buf };616 return FormValue{ .Ref = buf };
632}617}
633618
634fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type) !FormValue {619fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type) !FormValue {
...@@ -646,11 +631,9 @@ const ParseFormValueError = error {...@@ -646,11 +631,9 @@ const ParseFormValueError = error {
646 OutOfMemory,631 OutOfMemory,
647};632};
648633
649fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool)634fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue {
650 ParseFormValueError!FormValue
651{
652 return switch (form_id) {635 return switch (form_id) {
653 DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) },636 DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
654 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),637 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
655 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),638 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
656 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),639 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
...@@ -662,7 +645,8 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -662,7 +645,8 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
662 DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),645 DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
663 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),646 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
664 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),647 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
665 DW.FORM_udata, DW.FORM_sdata => {648 DW.FORM_udata,
649 DW.FORM_sdata => {
666 const block_len = try readULeb128(in_stream);650 const block_len = try readULeb128(in_stream);
667 const signed = form_id == DW.FORM_sdata;651 const signed = form_id == DW.FORM_sdata;
668 return parseFormValueConstant(allocator, in_stream, signed, block_len);652 return parseFormValueConstant(allocator, in_stream, signed, block_len);
...@@ -670,11 +654,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -670,11 +654,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
670 DW.FORM_exprloc => {654 DW.FORM_exprloc => {
671 const size = try readULeb128(in_stream);655 const size = try readULeb128(in_stream);
672 const buf = try readAllocBytes(allocator, in_stream, size);656 const buf = try readAllocBytes(allocator, in_stream, size);
673 return FormValue { .ExprLoc = buf };657 return FormValue{ .ExprLoc = buf };
674 },658 },
675 DW.FORM_flag => FormValue { .Flag = (try in_stream.readByte()) != 0 },659 DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 },
676 DW.FORM_flag_present => FormValue { .Flag = true },660 DW.FORM_flag_present => FormValue{ .Flag = true },
677 DW.FORM_sec_offset => FormValue { .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },661 DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
678662
679 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),663 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
680 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),664 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
...@@ -685,11 +669,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -685,11 +669,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64
685 return parseFormValueRefLen(allocator, in_stream, ref_len);669 return parseFormValueRefLen(allocator, in_stream, ref_len);
686 },670 },
687671
688 DW.FORM_ref_addr => FormValue { .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },672 DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
689 DW.FORM_ref_sig8 => FormValue { .RefSig8 = try in_stream.readIntLe(u64) },673 DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) },
690674
691 DW.FORM_string => FormValue { .String = try readStringRaw(allocator, in_stream) },675 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
692 DW.FORM_strp => FormValue { .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },676 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
693 DW.FORM_indirect => {677 DW.FORM_indirect => {
694 const child_form_id = try readULeb128(in_stream);678 const child_form_id = try readULeb128(in_stream);
695 return parseFormValue(allocator, in_stream, child_form_id, is_64);679 return parseFormValue(allocator, in_stream, child_form_id, is_64);
...@@ -705,9 +689,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {...@@ -705,9 +689,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
705 var result = AbbrevTable.init(st.allocator());689 var result = AbbrevTable.init(st.allocator());
706 while (true) {690 while (true) {
707 const abbrev_code = try readULeb128(in_stream);691 const abbrev_code = try readULeb128(in_stream);
708 if (abbrev_code == 0)692 if (abbrev_code == 0) return result;
709 return result;693 try result.append(AbbrevTableEntry{
710 try result.append(AbbrevTableEntry {
711 .abbrev_code = abbrev_code,694 .abbrev_code = abbrev_code,
712 .tag_id = try readULeb128(in_stream),695 .tag_id = try readULeb128(in_stream),
713 .has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,696 .has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,
...@@ -718,9 +701,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {...@@ -718,9 +701,8 @@ fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable {
718 while (true) {701 while (true) {
719 const attr_id = try readULeb128(in_stream);702 const attr_id = try readULeb128(in_stream);
720 const form_id = try readULeb128(in_stream);703 const form_id = try readULeb128(in_stream);
721 if (attr_id == 0 and form_id == 0)704 if (attr_id == 0 and form_id == 0) break;
722 break;705 try attrs.append(AbbrevAttr{
723 try attrs.append(AbbrevAttr {
724 .attr_id = attr_id,706 .attr_id = attr_id,
725 .form_id = form_id,707 .form_id = form_id,
726 });708 });
...@@ -737,7 +719,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {...@@ -737,7 +719,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {
737 }719 }
738 }720 }
739 try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);721 try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
740 try st.abbrev_table_list.append(AbbrevTableHeader {722 try st.abbrev_table_list.append(AbbrevTableHeader{
741 .offset = abbrev_offset,723 .offset = abbrev_offset,
742 .table = try parseAbbrevTable(st),724 .table = try parseAbbrevTable(st),
743 });725 });
...@@ -746,8 +728,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {...@@ -746,8 +728,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable {
746728
747fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&const AbbrevTableEntry {729fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&const AbbrevTableEntry {
748 for (abbrev_table.toSliceConst()) |*table_entry| {730 for (abbrev_table.toSliceConst()) |*table_entry| {
749 if (table_entry.abbrev_code == abbrev_code)731 if (table_entry.abbrev_code == abbrev_code) return table_entry;
750 return table_entry;
751 }732 }
752 return null;733 return null;
753}734}
...@@ -759,14 +740,14 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) !...@@ -759,14 +740,14 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) !
759 const abbrev_code = try readULeb128(in_stream);740 const abbrev_code = try readULeb128(in_stream);
760 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;741 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
761742
762 var result = Die {743 var result = Die{
763 .tag_id = table_entry.tag_id,744 .tag_id = table_entry.tag_id,
764 .has_children = table_entry.has_children,745 .has_children = table_entry.has_children,
765 .attrs = ArrayList(Die.Attr).init(st.allocator()),746 .attrs = ArrayList(Die.Attr).init(st.allocator()),
766 };747 };
767 try result.attrs.resize(table_entry.attrs.len);748 try result.attrs.resize(table_entry.attrs.len);
768 for (table_entry.attrs.toSliceConst()) |attr, i| {749 for (table_entry.attrs.toSliceConst()) |attr, i| {
769 result.attrs.items[i] = Die.Attr {750 result.attrs.items[i] = Die.Attr{
770 .id = attr.attr_id,751 .id = attr.attr_id,
771 .value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),752 .value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
772 };753 };
...@@ -790,8 +771,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -790,8 +771,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
790771
791 var is_64: bool = undefined;772 var is_64: bool = undefined;
792 const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);773 const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
793 if (unit_length == 0)774 if (unit_length == 0) return error.MissingDebugInfo;
794 return error.MissingDebugInfo;
795 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));775 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
796776
797 if (compile_unit.index != this_index) {777 if (compile_unit.index != this_index) {
...@@ -803,8 +783,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -803,8 +783,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
803 // TODO support 3 and 5783 // TODO support 3 and 5
804 if (version != 2 and version != 4) return error.InvalidDebugInfo;784 if (version != 2 and version != 4) return error.InvalidDebugInfo;
805785
806 const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64)786 const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
807 else try in_stream.readInt(st.elf.endian, u32);
808 const prog_start_offset = (try in_file.getPos()) + prologue_length;787 const prog_start_offset = (try in_file.getPos()) + prologue_length;
809788
810 const minimum_instruction_length = try in_stream.readByte();789 const minimum_instruction_length = try in_stream.readByte();
...@@ -819,38 +798,37 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -819,38 +798,37 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
819 const line_base = try in_stream.readByteSigned();798 const line_base = try in_stream.readByteSigned();
820799
821 const line_range = try in_stream.readByte();800 const line_range = try in_stream.readByte();
822 if (line_range == 0)801 if (line_range == 0) return error.InvalidDebugInfo;
823 return error.InvalidDebugInfo;
824802
825 const opcode_base = try in_stream.readByte();803 const opcode_base = try in_stream.readByte();
826804
827 const standard_opcode_lengths = try st.allocator().alloc(u8, opcode_base - 1);805 const standard_opcode_lengths = try st.allocator().alloc(u8, opcode_base - 1);
828806
829 {var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {807 {
830 standard_opcode_lengths[i] = try in_stream.readByte();808 var i: usize = 0;
831 }}809 while (i < opcode_base - 1) : (i += 1) {
810 standard_opcode_lengths[i] = try in_stream.readByte();
811 }
812 }
832813
833 var include_directories = ArrayList([]u8).init(st.allocator());814 var include_directories = ArrayList([]u8).init(st.allocator());
834 try include_directories.append(compile_unit_cwd);815 try include_directories.append(compile_unit_cwd);
835 while (true) {816 while (true) {
836 const dir = try st.readString();817 const dir = try st.readString();
837 if (dir.len == 0)818 if (dir.len == 0) break;
838 break;
839 try include_directories.append(dir);819 try include_directories.append(dir);
840 }820 }
841821
842 var file_entries = ArrayList(FileEntry).init(st.allocator());822 var file_entries = ArrayList(FileEntry).init(st.allocator());
843 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),823 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
844 &file_entries, target_address);
845824
846 while (true) {825 while (true) {
847 const file_name = try st.readString();826 const file_name = try st.readString();
848 if (file_name.len == 0)827 if (file_name.len == 0) break;
849 break;
850 const dir_index = try readULeb128(in_stream);828 const dir_index = try readULeb128(in_stream);
851 const mtime = try readULeb128(in_stream);829 const mtime = try readULeb128(in_stream);
852 const len_bytes = try readULeb128(in_stream);830 const len_bytes = try readULeb128(in_stream);
853 try file_entries.append(FileEntry {831 try file_entries.append(FileEntry{
854 .file_name = file_name,832 .file_name = file_name,
855 .dir_index = dir_index,833 .dir_index = dir_index,
856 .mtime = mtime,834 .mtime = mtime,
...@@ -866,8 +844,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -866,8 +844,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
866 var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash844 var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
867 if (opcode == DW.LNS_extended_op) {845 if (opcode == DW.LNS_extended_op) {
868 const op_size = try readULeb128(in_stream);846 const op_size = try readULeb128(in_stream);
869 if (op_size < 1)847 if (op_size < 1) return error.InvalidDebugInfo;
870 return error.InvalidDebugInfo;
871 sub_op = try in_stream.readByte();848 sub_op = try in_stream.readByte();
872 switch (sub_op) {849 switch (sub_op) {
873 DW.LNE_end_sequence => {850 DW.LNE_end_sequence => {
...@@ -884,7 +861,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -884,7 +861,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
884 const dir_index = try readULeb128(in_stream);861 const dir_index = try readULeb128(in_stream);
885 const mtime = try readULeb128(in_stream);862 const mtime = try readULeb128(in_stream);
886 const len_bytes = try readULeb128(in_stream);863 const len_bytes = try readULeb128(in_stream);
887 try file_entries.append(FileEntry {864 try file_entries.append(FileEntry{
888 .file_name = file_name,865 .file_name = file_name,
889 .dir_index = dir_index,866 .dir_index = dir_index,
890 .mtime = mtime,867 .mtime = mtime,
...@@ -941,11 +918,9 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -941,11 +918,9 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
941 const arg = try in_stream.readInt(st.elf.endian, u16);918 const arg = try in_stream.readInt(st.elf.endian, u16);
942 prog.address += arg;919 prog.address += arg;
943 },920 },
944 DW.LNS_set_prologue_end => {921 DW.LNS_set_prologue_end => {},
945 },
946 else => {922 else => {
947 if (opcode - 1 >= standard_opcode_lengths.len)923 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
948 return error.InvalidDebugInfo;
949 const len_bytes = standard_opcode_lengths[opcode - 1];924 const len_bytes = standard_opcode_lengths[opcode - 1];
950 try in_file.seekForward(len_bytes);925 try in_file.seekForward(len_bytes);
951 },926 },
...@@ -972,16 +947,13 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {...@@ -972,16 +947,13 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
972947
973 var is_64: bool = undefined;948 var is_64: bool = undefined;
974 const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);949 const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
975 if (unit_length == 0)950 if (unit_length == 0) return;
976 return;
977 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));951 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
978952
979 const version = try in_stream.readInt(st.elf.endian, u16);953 const version = try in_stream.readInt(st.elf.endian, u16);
980 if (version < 2 or version > 5) return error.InvalidDebugInfo;954 if (version < 2 or version > 5) return error.InvalidDebugInfo;
981955
982 const debug_abbrev_offset =956 const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
983 if (is_64) try in_stream.readInt(st.elf.endian, u64)
984 else try in_stream.readInt(st.elf.endian, u32);
985957
986 const address_size = try in_stream.readByte();958 const address_size = try in_stream.readByte();
987 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;959 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
...@@ -992,15 +964,14 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {...@@ -992,15 +964,14 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
992 try st.self_exe_file.seekTo(compile_unit_pos);964 try st.self_exe_file.seekTo(compile_unit_pos);
993965
994 const compile_unit_die = try st.allocator().create(Die);966 const compile_unit_die = try st.allocator().create(Die);
995 *compile_unit_die = try parseDie(st, abbrev_table, is_64);967 compile_unit_die.* = try parseDie(st, abbrev_table, is_64);
996968
997 if (compile_unit_die.tag_id != DW.TAG_compile_unit)969 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
998 return error.InvalidDebugInfo;
999970
1000 const pc_range = x: {971 const pc_range = x: {
1001 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {972 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
1002 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {973 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
1003 const pc_end = switch (*high_pc_value) {974 const pc_end = switch (high_pc_value.*) {
1004 FormValue.Address => |value| value,975 FormValue.Address => |value| value,
1005 FormValue.Const => |value| b: {976 FormValue.Const => |value| b: {
1006 const offset = try value.asUnsignedLe();977 const offset = try value.asUnsignedLe();
...@@ -1008,7 +979,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {...@@ -1008,7 +979,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
1008 },979 },
1009 else => return error.InvalidDebugInfo,980 else => return error.InvalidDebugInfo,
1010 };981 };
1011 break :x PcRange {982 break :x PcRange{
1012 .start = low_pc,983 .start = low_pc,
1013 .end = pc_end,984 .end = pc_end,
1014 };985 };
...@@ -1016,13 +987,12 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {...@@ -1016,13 +987,12 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void {
1016 break :x null;987 break :x null;
1017 }988 }
1018 } else |err| {989 } else |err| {
1019 if (err != error.MissingDebugInfo)990 if (err != error.MissingDebugInfo) return err;
1020 return err;
1021 break :x null;991 break :x null;
1022 }992 }
1023 };993 };
1024994
1025 try st.compile_unit_list.append(CompileUnit {995 try st.compile_unit_list.append(CompileUnit{
1026 .version = version,996 .version = version,
1027 .is_64 = is_64,997 .is_64 = is_64,
1028 .pc_range = pc_range,998 .pc_range = pc_range,
...@@ -1040,8 +1010,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit...@@ -1040,8 +1010,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
1040 const in_stream = &in_file_stream.stream;1010 const in_stream = &in_file_stream.stream;
1041 for (st.compile_unit_list.toSlice()) |*compile_unit| {1011 for (st.compile_unit_list.toSlice()) |*compile_unit| {
1042 if (compile_unit.pc_range) |range| {1012 if (compile_unit.pc_range) |range| {
1043 if (target_address >= range.start and target_address < range.end)1013 if (target_address >= range.start and target_address < range.end) return compile_unit;
1044 return compile_unit;
1045 }1014 }
1046 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {1015 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
1047 var base_address: usize = 0;1016 var base_address: usize = 0;
...@@ -1063,8 +1032,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit...@@ -1063,8 +1032,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
1063 }1032 }
1064 }1033 }
1065 } else |err| {1034 } else |err| {
1066 if (err != error.MissingDebugInfo)1035 if (err != error.MissingDebugInfo) return err;
1067 return err;
1068 continue;1036 continue;
1069 }1037 }
1070 }1038 }
...@@ -1073,8 +1041,8 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit...@@ -1073,8 +1041,8 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit
10731041
1074fn readInitialLength(comptime E: type, in_stream: &io.InStream(E), is_64: &bool) !u64 {1042fn readInitialLength(comptime E: type, in_stream: &io.InStream(E), is_64: &bool) !u64 {
1075 const first_32_bits = try in_stream.readIntLe(u32);1043 const first_32_bits = try in_stream.readIntLe(u32);
1076 *is_64 = (first_32_bits == 0xffffffff);1044 is_64.* = (first_32_bits == 0xffffffff);
1077 if (*is_64) {1045 if (is_64.*) {
1078 return in_stream.readIntLe(u64);1046 return in_stream.readIntLe(u64);
1079 } else {1047 } else {
1080 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;1048 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
...@@ -1091,13 +1059,11 @@ fn readULeb128(in_stream: var) !u64 {...@@ -1091,13 +1059,11 @@ fn readULeb128(in_stream: var) !u64 {
10911059
1092 var operand: u64 = undefined;1060 var operand: u64 = undefined;
10931061
1094 if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))1062 if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand)) return error.InvalidDebugInfo;
1095 return error.InvalidDebugInfo;
10961063
1097 result |= operand;1064 result |= operand;
10981065
1099 if ((byte & 0b10000000) == 0)1066 if ((byte & 0b10000000) == 0) return result;
1100 return result;
11011067
1102 shift += 7;1068 shift += 7;
1103 }1069 }
...@@ -1112,15 +1078,13 @@ fn readILeb128(in_stream: var) !i64 {...@@ -1112,15 +1078,13 @@ fn readILeb128(in_stream: var) !i64 {
11121078
1113 var operand: i64 = undefined;1079 var operand: i64 = undefined;
11141080
1115 if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))1081 if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand)) return error.InvalidDebugInfo;
1116 return error.InvalidDebugInfo;
11171082
1118 result |= operand;1083 result |= operand;
1119 shift += 7;1084 shift += 7;
11201085
1121 if ((byte & 0b10000000) == 0) {1086 if ((byte & 0b10000000) == 0) {
1122 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)1087 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << u6(shift));
1123 result |= -(i64(1) << u6(shift));
1124 return result;1088 return result;
1125 }1089 }
1126 }1090 }
...@@ -1131,7 +1095,6 @@ pub const global_allocator = &global_fixed_allocator.allocator;...@@ -1131,7 +1095,6 @@ pub const global_allocator = &global_fixed_allocator.allocator;
1131var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]);1095var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]);
1132var global_allocator_mem: [100 * 1024]u8 = undefined;1096var global_allocator_mem: [100 * 1024]u8 = undefined;
11331097
1134
1135// TODO make thread safe1098// TODO make thread safe
1136var debug_info_allocator: ?&mem.Allocator = null;1099var debug_info_allocator: ?&mem.Allocator = null;
1137var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;1100var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;
std/event.zig+20-33
...@@ -6,7 +6,7 @@ const mem = std.mem;...@@ -6,7 +6,7 @@ const mem = std.mem;
6const posix = std.os.posix;6const posix = std.os.posix;
77
8pub const TcpServer = struct {8pub const TcpServer = struct {
9 handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File) void,9 handleRequestFn: async<&mem.Allocator> fn(&TcpServer, &const std.net.Address, &const std.os.File) void,
1010
11 loop: &Loop,11 loop: &Loop,
12 sockfd: i32,12 sockfd: i32,
...@@ -18,13 +18,11 @@ pub const TcpServer = struct {...@@ -18,13 +18,11 @@ pub const TcpServer = struct {
18 const PromiseNode = std.LinkedList(promise).Node;18 const PromiseNode = std.LinkedList(promise).Node;
1919
20 pub fn init(loop: &Loop) !TcpServer {20 pub fn init(loop: &Loop) !TcpServer {
21 const sockfd = try std.os.posixSocket(posix.AF_INET,21 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
22 posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK,
23 posix.PROTO_tcp);
24 errdefer std.os.close(sockfd);22 errdefer std.os.close(sockfd);
2523
26 // TODO can't initialize handler coroutine here because we need well defined copy elision24 // TODO can't initialize handler coroutine here because we need well defined copy elision
27 return TcpServer {25 return TcpServer{
28 .loop = loop,26 .loop = loop,
29 .sockfd = sockfd,27 .sockfd = sockfd,
30 .accept_coro = null,28 .accept_coro = null,
...@@ -34,9 +32,7 @@ pub const TcpServer = struct {...@@ -34,9 +32,7 @@ pub const TcpServer = struct {
34 };32 };
35 }33 }
3634
37 pub fn listen(self: &TcpServer, address: &const std.net.Address,35 pub fn listen(self: &TcpServer, address: &const std.net.Address, handleRequestFn: async<&mem.Allocator> fn(&TcpServer, &const std.net.Address, &const std.os.File) void) !void {
38 handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File)void) !void
39 {
40 self.handleRequestFn = handleRequestFn;36 self.handleRequestFn = handleRequestFn;
4137
42 try std.os.posixBind(self.sockfd, &address.os_addr);38 try std.os.posixBind(self.sockfd, &address.os_addr);
...@@ -48,7 +44,6 @@ pub const TcpServer = struct {...@@ -48,7 +44,6 @@ pub const TcpServer = struct {
4844
49 try self.loop.addFd(self.sockfd, ??self.accept_coro);45 try self.loop.addFd(self.sockfd, ??self.accept_coro);
50 errdefer self.loop.removeFd(self.sockfd);46 errdefer self.loop.removeFd(self.sockfd);
51
52 }47 }
5348
54 pub fn deinit(self: &TcpServer) void {49 pub fn deinit(self: &TcpServer) void {
...@@ -60,9 +55,7 @@ pub const TcpServer = struct {...@@ -60,9 +55,7 @@ pub const TcpServer = struct {
60 pub async fn handler(self: &TcpServer) void {55 pub async fn handler(self: &TcpServer) void {
61 while (true) {56 while (true) {
62 var accepted_addr: std.net.Address = undefined;57 var accepted_addr: std.net.Address = undefined;
63 if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr,58 if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr, posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd| {
64 posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|
65 {
66 var socket = std.os.File.openHandle(accepted_fd);59 var socket = std.os.File.openHandle(accepted_fd);
67 _ = async<self.loop.allocator> self.handleRequestFn(self, accepted_addr, socket) catch |err| switch (err) {60 _ = async<self.loop.allocator> self.handleRequestFn(self, accepted_addr, socket) catch |err| switch (err) {
68 error.OutOfMemory => {61 error.OutOfMemory => {
...@@ -110,7 +103,7 @@ pub const Loop = struct {...@@ -110,7 +103,7 @@ pub const Loop = struct {
110103
111 fn init(allocator: &mem.Allocator) !Loop {104 fn init(allocator: &mem.Allocator) !Loop {
112 const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);105 const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);
113 return Loop {106 return Loop{
114 .keep_running = true,107 .keep_running = true,
115 .allocator = allocator,108 .allocator = allocator,
116 .epollfd = epollfd,109 .epollfd = epollfd,
...@@ -118,11 +111,9 @@ pub const Loop = struct {...@@ -118,11 +111,9 @@ pub const Loop = struct {
118 }111 }
119112
120 pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {113 pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {
121 var ev = std.os.linux.epoll_event {114 var ev = std.os.linux.epoll_event{
122 .events = std.os.linux.EPOLLIN|std.os.linux.EPOLLOUT|std.os.linux.EPOLLET,115 .events = std.os.linux.EPOLLIN | std.os.linux.EPOLLOUT | std.os.linux.EPOLLET,
123 .data = std.os.linux.epoll_data {116 .data = std.os.linux.epoll_data{ .ptr = @ptrToInt(prom) },
124 .ptr = @ptrToInt(prom),
125 },
126 };117 };
127 try std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev);118 try std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev);
128 }119 }
...@@ -157,9 +148,9 @@ pub const Loop = struct {...@@ -157,9 +148,9 @@ pub const Loop = struct {
157};148};
158149
159pub async fn connect(loop: &Loop, _address: &const std.net.Address) !std.os.File {150pub async fn connect(loop: &Loop, _address: &const std.net.Address) !std.os.File {
160 var address = *_address; // TODO https://github.com/zig-lang/zig/issues/733151 var address = _address.*; // TODO https://github.com/ziglang/zig/issues/733
161152
162 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK, posix.PROTO_tcp);153 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
163 errdefer std.os.close(sockfd);154 errdefer std.os.close(sockfd);
164155
165 try std.os.posixConnectAsync(sockfd, &address.os_addr);156 try std.os.posixConnectAsync(sockfd, &address.os_addr);
...@@ -179,11 +170,9 @@ test "listen on a port, send bytes, receive bytes" {...@@ -179,11 +170,9 @@ test "listen on a port, send bytes, receive bytes" {
179170
180 const Self = this;171 const Self = this;
181172
182 async<&mem.Allocator> fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address,173 async<&mem.Allocator> fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address, _socket: &const std.os.File) void {
183 _socket: &const std.os.File) void
184 {
185 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);174 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
186 var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733175 var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733
187 defer socket.close();176 defer socket.close();
188 const next_handler = async errorableHandler(self, _addr, socket) catch |err| switch (err) {177 const next_handler = async errorableHandler(self, _addr, socket) catch |err| switch (err) {
189 error.OutOfMemory => @panic("unable to handle connection: out of memory"),178 error.OutOfMemory => @panic("unable to handle connection: out of memory"),
...@@ -191,14 +180,14 @@ test "listen on a port, send bytes, receive bytes" {...@@ -191,14 +180,14 @@ test "listen on a port, send bytes, receive bytes" {
191 (await next_handler) catch |err| {180 (await next_handler) catch |err| {
192 std.debug.panic("unable to handle connection: {}\n", err);181 std.debug.panic("unable to handle connection: {}\n", err);
193 };182 };
194 suspend |p| { cancel p; }183 suspend |p| {
184 cancel p;
185 }
195 }186 }
196187
197 async fn errorableHandler(self: &Self, _addr: &const std.net.Address,188 async fn errorableHandler(self: &Self, _addr: &const std.net.Address, _socket: &const std.os.File) !void {
198 _socket: &const std.os.File) !void189 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/733
199 {190 var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733
200 const addr = *_addr; // TODO https://github.com/zig-lang/zig/issues/733
201 var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
202191
203 var adapter = std.io.FileOutStream.init(&socket);192 var adapter = std.io.FileOutStream.init(&socket);
204 var stream = &adapter.stream;193 var stream = &adapter.stream;
...@@ -210,9 +199,7 @@ test "listen on a port, send bytes, receive bytes" {...@@ -210,9 +199,7 @@ test "listen on a port, send bytes, receive bytes" {
210 const addr = std.net.Address.initIp4(ip4addr, 0);199 const addr = std.net.Address.initIp4(ip4addr, 0);
211200
212 var loop = try Loop.init(std.debug.global_allocator);201 var loop = try Loop.init(std.debug.global_allocator);
213 var server = MyServer {202 var server = MyServer{ .tcp_server = try TcpServer.init(&loop) };
214 .tcp_server = try TcpServer.init(&loop),
215 };
216 defer server.tcp_server.deinit();203 defer server.tcp_server.deinit();
217 try server.tcp_server.listen(addr, MyServer.handler);204 try server.tcp_server.listen(addr, MyServer.handler);
218205
std/fmt/errol/index.zig+22-32
...@@ -86,7 +86,7 @@ pub fn errol3(value: f64, buffer: []u8) FloatDecimal {...@@ -86,7 +86,7 @@ pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
86 const data = enum3_data[i];86 const data = enum3_data[i];
87 const digits = buffer[1..data.str.len + 1];87 const digits = buffer[1..data.str.len + 1];
88 mem.copy(u8, digits, data.str);88 mem.copy(u8, digits, data.str);
89 return FloatDecimal {89 return FloatDecimal{
90 .digits = digits,90 .digits = digits,
91 .exp = data.exp,91 .exp = data.exp,
92 };92 };
...@@ -105,7 +105,6 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {...@@ -105,7 +105,6 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
105 return errolFixed(val, buffer);105 return errolFixed(val, buffer);
106 }106 }
107107
108
109 // normalize the midpoint108 // normalize the midpoint
110109
111 const e = math.frexp(val).exponent;110 const e = math.frexp(val).exponent;
...@@ -137,11 +136,11 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {...@@ -137,11 +136,11 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
137 }136 }
138137
139 // compute boundaries138 // compute boundaries
140 var high = HP {139 var high = HP{
141 .val = mid.val,140 .val = mid.val,
142 .off = mid.off + (fpnext(val) - val) * lten * ten / 2.0,141 .off = mid.off + (fpnext(val) - val) * lten * ten / 2.0,
143 };142 };
144 var low = HP {143 var low = HP{
145 .val = mid.val,144 .val = mid.val,
146 .off = mid.off + (fpprev(val) - val) * lten * ten / 2.0,145 .off = mid.off + (fpprev(val) - val) * lten * ten / 2.0,
147 };146 };
...@@ -171,15 +170,12 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {...@@ -171,15 +170,12 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
171 var buf_index: usize = 1;170 var buf_index: usize = 1;
172 while (true) {171 while (true) {
173 var hdig = u8(math.floor(high.val));172 var hdig = u8(math.floor(high.val));
174 if ((high.val == f64(hdig)) and (high.off < 0))173 if ((high.val == f64(hdig)) and (high.off < 0)) hdig -= 1;
175 hdig -= 1;
176174
177 var ldig = u8(math.floor(low.val));175 var ldig = u8(math.floor(low.val));
178 if ((low.val == f64(ldig)) and (low.off < 0))176 if ((low.val == f64(ldig)) and (low.off < 0)) ldig -= 1;
179 ldig -= 1;
180177
181 if (ldig != hdig)178 if (ldig != hdig) break;
182 break;
183179
184 buffer[buf_index] = hdig + '0';180 buffer[buf_index] = hdig + '0';
185 buf_index += 1;181 buf_index += 1;
...@@ -191,13 +187,12 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {...@@ -191,13 +187,12 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
191187
192 const tmp = (high.val + low.val) / 2.0;188 const tmp = (high.val + low.val) / 2.0;
193 var mdig = u8(math.floor(tmp + 0.5));189 var mdig = u8(math.floor(tmp + 0.5));
194 if ((f64(mdig) - tmp) == 0.5 and (mdig & 0x1) != 0)190 if ((f64(mdig) - tmp) == 0.5 and (mdig & 0x1) != 0) mdig -= 1;
195 mdig -= 1;
196191
197 buffer[buf_index] = mdig + '0';192 buffer[buf_index] = mdig + '0';
198 buf_index += 1;193 buf_index += 1;
199194
200 return FloatDecimal {195 return FloatDecimal{
201 .digits = buffer[1..buf_index],196 .digits = buffer[1..buf_index],
202 .exp = exp,197 .exp = exp,
203 };198 };
...@@ -235,7 +230,7 @@ fn hpProd(in: &const HP, val: f64) HP {...@@ -235,7 +230,7 @@ fn hpProd(in: &const HP, val: f64) HP {
235 const p = in.val * val;230 const p = in.val * val;
236 const e = ((hi * hi2 - p) + lo * hi2 + hi * lo2) + lo * lo2;231 const e = ((hi * hi2 - p) + lo * hi2 + hi * lo2) + lo * lo2;
237232
238 return HP {233 return HP{
239 .val = p,234 .val = p,
240 .off = in.off * val + e,235 .off = in.off * val + e,
241 };236 };
...@@ -246,8 +241,8 @@ fn hpProd(in: &const HP, val: f64) HP {...@@ -246,8 +241,8 @@ fn hpProd(in: &const HP, val: f64) HP {
246/// @hi: The high bits.241/// @hi: The high bits.
247/// @lo: The low bits.242/// @lo: The low bits.
248fn split(val: f64, hi: &f64, lo: &f64) void {243fn split(val: f64, hi: &f64, lo: &f64) void {
249 *hi = gethi(val);244 hi.* = gethi(val);
250 *lo = val - *hi;245 lo.* = val - hi.*;
251}246}
252247
253fn gethi(in: f64) f64 {248fn gethi(in: f64) f64 {
...@@ -301,7 +296,6 @@ fn hpMul10(hp: &HP) void {...@@ -301,7 +296,6 @@ fn hpMul10(hp: &HP) void {
301 hpNormalize(hp);296 hpNormalize(hp);
302}297}
303298
304
305/// Integer conversion algorithm, guaranteed correct, optimal, and best.299/// Integer conversion algorithm, guaranteed correct, optimal, and best.
306/// @val: The val.300/// @val: The val.
307/// @buf: The output buffer.301/// @buf: The output buffer.
...@@ -343,8 +337,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {...@@ -343,8 +337,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
343 }337 }
344 const m64 = @truncate(u64, @divTrunc(mid, x));338 const m64 = @truncate(u64, @divTrunc(mid, x));
345339
346 if (lf != hf)340 if (lf != hf) mi += 19;
347 mi += 19;
348341
349 var buf_index = u64toa(m64, buffer) - 1;342 var buf_index = u64toa(m64, buffer) - 1;
350343
...@@ -354,7 +347,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {...@@ -354,7 +347,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
354 buf_index += 1;347 buf_index += 1;
355 }348 }
356349
357 return FloatDecimal {350 return FloatDecimal{
358 .digits = buffer[0..buf_index],351 .digits = buffer[0..buf_index],
359 .exp = i32(buf_index) + mi,352 .exp = i32(buf_index) + mi,
360 };353 };
...@@ -396,25 +389,24 @@ fn errolFixed(val: f64, buffer: []u8) FloatDecimal {...@@ -396,25 +389,24 @@ fn errolFixed(val: f64, buffer: []u8) FloatDecimal {
396 buffer[j] = u8(mdig + '0');389 buffer[j] = u8(mdig + '0');
397 j += 1;390 j += 1;
398391
399 if(hdig != ldig or j > 50)392 if (hdig != ldig or j > 50) break;
400 break;
401 }393 }
402394
403 if (mid > 0.5) {395 if (mid > 0.5) {
404 buffer[j-1] += 1;396 buffer[j - 1] += 1;
405 } else if ((mid == 0.5) and (buffer[j-1] & 0x1) != 0) {397 } else if ((mid == 0.5) and (buffer[j - 1] & 0x1) != 0) {
406 buffer[j-1] += 1;398 buffer[j - 1] += 1;
407 }399 }
408 } else {400 } else {
409 while (buffer[j-1] == '0') {401 while (buffer[j - 1] == '0') {
410 buffer[j-1] = 0;402 buffer[j - 1] = 0;
411 j -= 1;403 j -= 1;
412 }404 }
413 }405 }
414406
415 buffer[j] = 0;407 buffer[j] = 0;
416408
417 return FloatDecimal {409 return FloatDecimal{
418 .digits = buffer[0..j],410 .digits = buffer[0..j],
419 .exp = exp,411 .exp = exp,
420 };412 };
...@@ -587,7 +579,7 @@ fn u64toa(value_param: u64, buffer: []u8) usize {...@@ -587,7 +579,7 @@ fn u64toa(value_param: u64, buffer: []u8) usize {
587 buffer[buf_index] = c_digits_lut[d8 + 1];579 buffer[buf_index] = c_digits_lut[d8 + 1];
588 buf_index += 1;580 buf_index += 1;
589 } else {581 } else {
590 const a = u32(value / kTen16); // 1 to 1844582 const a = u32(value / kTen16); // 1 to 1844
591 value %= kTen16;583 value %= kTen16;
592584
593 if (a < 10) {585 if (a < 10) {
...@@ -686,7 +678,6 @@ fn fpeint(from: f64) u128 {...@@ -686,7 +678,6 @@ fn fpeint(from: f64) u128 {
686 return u128(1) << @truncate(u7, (bits >> 52) -% 1023);678 return u128(1) << @truncate(u7, (bits >> 52) -% 1023);
687}679}
688680
689
690/// Given two different integers with the same length in terms of the number681/// Given two different integers with the same length in terms of the number
691/// of decimal digits, index the digits from the right-most position starting682/// of decimal digits, index the digits from the right-most position starting
692/// from zero, find the first index where the digits in the two integers683/// from zero, find the first index where the digits in the two integers
...@@ -713,7 +704,6 @@ fn mismatch10(a: u64, b: u64) i32 {...@@ -713,7 +704,6 @@ fn mismatch10(a: u64, b: u64) i32 {
713 a_copy /= 10;704 a_copy /= 10;
714 b_copy /= 10;705 b_copy /= 10;
715706
716 if (a_copy == b_copy)707 if (a_copy == b_copy) return i;
717 return i;
718 }708 }
719}709}
std/fmt/index.zig+137-67
...@@ -11,9 +11,7 @@ const max_int_digits = 65;...@@ -11,9 +11,7 @@ const max_int_digits = 65;
11/// Renders fmt string with args, calling output with slices of bytes.11/// Renders fmt string with args, calling output with slices of bytes.
12/// If `output` returns an error, the error is returned from `format` and12/// If `output` returns an error, the error is returned from `format` and
13/// `output` is not called again.13/// `output` is not called again.
14pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void,14pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
15 comptime fmt: []const u8, args: ...) Errors!void
16{
17 const State = enum {15 const State = enum {
18 Start,16 Start,
19 OpenBrace,17 OpenBrace,
...@@ -27,6 +25,9 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),...@@ -27,6 +25,9 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
27 Character,25 Character,
28 Buf,26 Buf,
29 BufWidth,27 BufWidth,
28 Bytes,
29 BytesBase,
30 BytesWidth,
30 };31 };
3132
32 comptime var start_index = 0;33 comptime var start_index = 0;
...@@ -95,6 +96,11 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),...@@ -95,6 +96,11 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
95 '.' => {96 '.' => {
96 state = State.Float;97 state = State.Float;
97 },98 },
99 'B' => {
100 width = 0;
101 radix = 1000;
102 state = State.Bytes;
103 },
98 else => @compileError("Unknown format character: " ++ []u8{c}),104 else => @compileError("Unknown format character: " ++ []u8{c}),
99 },105 },
100 State.Buf => switch (c) {106 State.Buf => switch (c) {
...@@ -206,6 +212,47 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),...@@ -206,6 +212,47 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
206 },212 },
207 else => @compileError("Unexpected character in format string: " ++ []u8{c}),213 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
208 },214 },
215 State.Bytes => switch (c) {
216 '}' => {
217 try formatBytes(args[next_arg], 0, radix, context, Errors, output);
218 next_arg += 1;
219 state = State.Start;
220 start_index = i + 1;
221 },
222 'i' => {
223 radix = 1024;
224 state = State.BytesBase;
225 },
226 '0' ... '9' => {
227 width_start = i;
228 state = State.BytesWidth;
229 },
230 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
231 },
232 State.BytesBase => switch (c) {
233 '}' => {
234 try formatBytes(args[next_arg], 0, radix, context, Errors, output);
235 next_arg += 1;
236 state = State.Start;
237 start_index = i + 1;
238 },
239 '0' ... '9' => {
240 width_start = i;
241 state = State.BytesWidth;
242 },
243 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
244 },
245 State.BytesWidth => switch (c) {
246 '}' => {
247 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
248 try formatBytes(args[next_arg], width, radix, context, Errors, output);
249 next_arg += 1;
250 state = State.Start;
251 start_index = i + 1;
252 },
253 '0' ... '9' => {},
254 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
255 },
209 }256 }
210 }257 }
211 comptime {258 comptime {
...@@ -221,7 +268,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),...@@ -221,7 +268,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
221 }268 }
222}269}
223270
224pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {271pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
225 const T = @typeOf(value);272 const T = @typeOf(value);
226 switch (@typeId(T)) {273 switch (@typeId(T)) {
227 builtin.TypeId.Int => {274 builtin.TypeId.Int => {
...@@ -256,7 +303,7 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@...@@ -256,7 +303,7 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@
256 },303 },
257 builtin.TypeId.Pointer => {304 builtin.TypeId.Pointer => {
258 if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) {305 if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) {
259 return output(context, (*value)[0..]);306 return output(context, (value.*)[0..]);
260 } else {307 } else {
261 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));308 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
262 }309 }
...@@ -270,13 +317,11 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@...@@ -270,13 +317,11 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@
270 }317 }
271}318}
272319
273pub fn formatAsciiChar(c: u8, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {320pub fn formatAsciiChar(c: u8, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
274 return output(context, (&c)[0..1]);321 return output(context, (&c)[0..1]);
275}322}
276323
277pub fn formatBuf(buf: []const u8, width: usize,324pub fn formatBuf(buf: []const u8, width: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
278 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
279{
280 try output(context, buf);325 try output(context, buf);
281326
282 var leftover_padding = if (width > buf.len) (width - buf.len) else return;327 var leftover_padding = if (width > buf.len) (width - buf.len) else return;
...@@ -289,7 +334,7 @@ pub fn formatBuf(buf: []const u8, width: usize,...@@ -289,7 +334,7 @@ pub fn formatBuf(buf: []const u8, width: usize,
289// Print a float in scientific notation to the specified precision. Null uses full precision.334// Print a float in scientific notation to the specified precision. Null uses full precision.
290// It should be the case that every full precision, printed value can be re-parsed back to the335// It should be the case that every full precision, printed value can be re-parsed back to the
291// same type unambiguously.336// same type unambiguously.
292pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {337pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
293 var x = f64(value);338 var x = f64(value);
294339
295 // Errol doesn't handle these special cases.340 // Errol doesn't handle these special cases.
...@@ -338,7 +383,7 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,...@@ -338,7 +383,7 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,
338 var printed: usize = 0;383 var printed: usize = 0;
339 if (float_decimal.digits.len > 1) {384 if (float_decimal.digits.len > 1) {
340 const num_digits = math.min(float_decimal.digits.len, precision + 1);385 const num_digits = math.min(float_decimal.digits.len, precision + 1);
341 try output(context, float_decimal.digits[1 .. num_digits]);386 try output(context, float_decimal.digits[1..num_digits]);
342 printed += num_digits - 1;387 printed += num_digits - 1;
343 }388 }
344389
...@@ -350,12 +395,9 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,...@@ -350,12 +395,9 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,
350 try output(context, float_decimal.digits[0..1]);395 try output(context, float_decimal.digits[0..1]);
351 try output(context, ".");396 try output(context, ".");
352 if (float_decimal.digits.len > 1) {397 if (float_decimal.digits.len > 1) {
353 const num_digits = if (@typeOf(value) == f32)398 const num_digits = if (@typeOf(value) == f32) math.min(usize(9), float_decimal.digits.len) else float_decimal.digits.len;
354 math.min(usize(9), float_decimal.digits.len)
355 else
356 float_decimal.digits.len;
357399
358 try output(context, float_decimal.digits[1 .. num_digits]);400 try output(context, float_decimal.digits[1..num_digits]);
359 } else {401 } else {
360 try output(context, "0");402 try output(context, "0");
361 }403 }
...@@ -381,7 +423,7 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,...@@ -381,7 +423,7 @@ pub fn formatFloatScientific(value: var, maybe_precision: ?usize, context: var,
381423
382// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.424// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
383// By default floats are printed at full precision (no rounding).425// By default floats are printed at full precision (no rounding).
384pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void {426pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
385 var x = f64(value);427 var x = f64(value);
386428
387 // Errol doesn't handle these special cases.429 // Errol doesn't handle these special cases.
...@@ -431,14 +473,14 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com...@@ -431,14 +473,14 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
431473
432 if (num_digits_whole > 0) {474 if (num_digits_whole > 0) {
433 // We may have to zero pad, for instance 1e4 requires zero padding.475 // We may have to zero pad, for instance 1e4 requires zero padding.
434 try output(context, float_decimal.digits[0 .. num_digits_whole_no_pad]);476 try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
435477
436 var i = num_digits_whole_no_pad;478 var i = num_digits_whole_no_pad;
437 while (i < num_digits_whole) : (i += 1) {479 while (i < num_digits_whole) : (i += 1) {
438 try output(context, "0");480 try output(context, "0");
439 }481 }
440 } else {482 } else {
441 try output(context , "0");483 try output(context, "0");
442 }484 }
443485
444 // {.0} special case doesn't want a trailing '.'486 // {.0} special case doesn't want a trailing '.'
...@@ -470,10 +512,10 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com...@@ -470,10 +512,10 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
470 // Remaining fractional portion, zero-padding if insufficient.512 // Remaining fractional portion, zero-padding if insufficient.
471 debug.assert(precision >= printed);513 debug.assert(precision >= printed);
472 if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {514 if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
473 try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);515 try output(context, float_decimal.digits[num_digits_whole_no_pad..num_digits_whole_no_pad + precision - printed]);
474 return;516 return;
475 } else {517 } else {
476 try output(context, float_decimal.digits[num_digits_whole_no_pad ..]);518 try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
477 printed += float_decimal.digits.len - num_digits_whole_no_pad;519 printed += float_decimal.digits.len - num_digits_whole_no_pad;
478520
479 while (printed < precision) : (printed += 1) {521 while (printed < precision) : (printed += 1) {
...@@ -489,14 +531,14 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com...@@ -489,14 +531,14 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
489531
490 if (num_digits_whole > 0) {532 if (num_digits_whole > 0) {
491 // We may have to zero pad, for instance 1e4 requires zero padding.533 // We may have to zero pad, for instance 1e4 requires zero padding.
492 try output(context, float_decimal.digits[0 .. num_digits_whole_no_pad]);534 try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
493535
494 var i = num_digits_whole_no_pad;536 var i = num_digits_whole_no_pad;
495 while (i < num_digits_whole) : (i += 1) {537 while (i < num_digits_whole) : (i += 1) {
496 try output(context, "0");538 try output(context, "0");
497 }539 }
498 } else {540 } else {
499 try output(context , "0");541 try output(context, "0");
500 }542 }
501543
502 // Omit `.` if no fractional portion544 // Omit `.` if no fractional portion
...@@ -516,10 +558,39 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com...@@ -516,10 +558,39 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
516 }558 }
517 }559 }
518560
519 try output(context, float_decimal.digits[num_digits_whole_no_pad ..]);561 try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
520 }562 }
521}563}
522564
565pub fn formatBytes(value: var, width: ?usize, comptime radix: usize,
566 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
567{
568 if (value == 0) {
569 return output(context, "0B");
570 }
571
572 const mags = " KMGTPEZY";
573 const magnitude = switch (radix) {
574 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags.len - 1),
575 1024 => math.min(math.log2(value) / 10, mags.len - 1),
576 else => unreachable,
577 };
578 const new_value = f64(value) / math.pow(f64, f64(radix), f64(magnitude));
579 const suffix = mags[magnitude];
580
581 try formatFloatDecimal(new_value, width, context, Errors, output);
582
583 if (suffix == ' ') {
584 return output(context, "B");
585 }
586
587 const buf = switch (radix) {
588 1000 => []u8 { suffix, 'B' },
589 1024 => []u8 { suffix, 'i', 'B' },
590 else => unreachable,
591 };
592 return output(context, buf);
593}
523594
524pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,595pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
525 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void596 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
...@@ -531,9 +602,7 @@ pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,...@@ -531,9 +602,7 @@ pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
531 }602 }
532}603}
533604
534fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,605fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
535 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
536{
537 const uint = @IntType(false, @typeOf(value).bit_count);606 const uint = @IntType(false, @typeOf(value).bit_count);
538 if (value < 0) {607 if (value < 0) {
539 const minus_sign: u8 = '-';608 const minus_sign: u8 = '-';
...@@ -552,9 +621,7 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,...@@ -552,9 +621,7 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
552 }621 }
553}622}
554623
555fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,624fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void {
556 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
557{
558 // max_int_digits accounts for the minus sign. when printing an unsigned625 // max_int_digits accounts for the minus sign. when printing an unsigned
559 // number we don't need to do that.626 // number we don't need to do that.
560 var buf: [max_int_digits - 1]u8 = undefined;627 var buf: [max_int_digits - 1]u8 = undefined;
...@@ -566,8 +633,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,...@@ -566,8 +633,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
566 index -= 1;633 index -= 1;
567 buf[index] = digitToChar(u8(digit), uppercase);634 buf[index] = digitToChar(u8(digit), uppercase);
568 a /= base;635 a /= base;
569 if (a == 0)636 if (a == 0) break;
570 break;
571 }637 }
572638
573 const digits_buf = buf[index..];639 const digits_buf = buf[index..];
...@@ -579,8 +645,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,...@@ -579,8 +645,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
579 while (true) {645 while (true) {
580 try output(context, (&zero_byte)[0..1]);646 try output(context, (&zero_byte)[0..1]);
581 leftover_padding -= 1;647 leftover_padding -= 1;
582 if (leftover_padding == 0)648 if (leftover_padding == 0) break;
583 break;
584 }649 }
585 mem.set(u8, buf[0..index], '0');650 mem.set(u8, buf[0..index], '0');
586 return output(context, buf);651 return output(context, buf);
...@@ -592,7 +657,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,...@@ -592,7 +657,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
592}657}
593658
594pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: usize) usize {659pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: usize) usize {
595 var context = FormatIntBuf {660 var context = FormatIntBuf{
596 .out_buf = out_buf,661 .out_buf = out_buf,
597 .index = 0,662 .index = 0,
598 };663 };
...@@ -609,10 +674,8 @@ fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) (error{}!void) {...@@ -609,10 +674,8 @@ fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) (error{}!void) {
609}674}
610675
611pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {676pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
612 if (!T.is_signed)677 if (!T.is_signed) return parseUnsigned(T, buf, radix);
613 return parseUnsigned(T, buf, radix);678 if (buf.len == 0) return T(0);
614 if (buf.len == 0)
615 return T(0);
616 if (buf[0] == '-') {679 if (buf[0] == '-') {
617 return math.negate(try parseUnsigned(T, buf[1..], radix));680 return math.negate(try parseUnsigned(T, buf[1..], radix));
618 } else if (buf[0] == '+') {681 } else if (buf[0] == '+') {
...@@ -632,9 +695,10 @@ test "fmt.parseInt" {...@@ -632,9 +695,10 @@ test "fmt.parseInt" {
632 assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);695 assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
633}696}
634697
635const ParseUnsignedError = error {698const ParseUnsignedError = error{
636 /// The result cannot fit in the type specified699 /// The result cannot fit in the type specified
637 Overflow,700 Overflow,
701
638 /// The input had a byte that was not a digit702 /// The input had a byte that was not a digit
639 InvalidCharacter,703 InvalidCharacter,
640};704};
...@@ -659,8 +723,7 @@ pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {...@@ -659,8 +723,7 @@ pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
659 else => return error.InvalidCharacter,723 else => return error.InvalidCharacter,
660 };724 };
661725
662 if (value >= radix)726 if (value >= radix) return error.InvalidCharacter;
663 return error.InvalidCharacter;
664727
665 return value;728 return value;
666}729}
...@@ -684,20 +747,21 @@ fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) !void {...@@ -684,20 +747,21 @@ fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) !void {
684}747}
685748
686pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {749pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
687 var context = BufPrintContext { .remaining = buf, };750 var context = BufPrintContext{ .remaining = buf };
688 try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);751 try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
689 return buf[0..buf.len - context.remaining.len];752 return buf[0..buf.len - context.remaining.len];
690}753}
691754
692pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) ![]u8 {755pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) ![]u8 {
693 var size: usize = 0;756 var size: usize = 0;
694 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};757 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {
758 };
695 const buf = try allocator.alloc(u8, size);759 const buf = try allocator.alloc(u8, size);
696 return bufPrint(buf, fmt, args);760 return bufPrint(buf, fmt, args);
697}761}
698762
699fn countSize(size: &usize, bytes: []const u8) (error{}!void) {763fn countSize(size: &usize, bytes: []const u8) (error{}!void) {
700 *size += bytes.len;764 size.* += bytes.len;
701}765}
702766
703test "buf print int" {767test "buf print int" {
...@@ -738,44 +802,34 @@ test "parse unsigned comptime" {...@@ -738,44 +802,34 @@ test "parse unsigned comptime" {
738802
739test "fmt.format" {803test "fmt.format" {
740 {804 {
741 var buf1: [32]u8 = undefined;
742 const value: ?i32 = 1234;805 const value: ?i32 = 1234;
743 const result = try bufPrint(buf1[0..], "nullable: {}\n", value);806 try testFmt("nullable: 1234\n", "nullable: {}\n", value);
744 assert(mem.eql(u8, result, "nullable: 1234\n"));
745 }807 }
746 {808 {
747 var buf1: [32]u8 = undefined;
748 const value: ?i32 = null;809 const value: ?i32 = null;
749 const result = try bufPrint(buf1[0..], "nullable: {}\n", value);810 try testFmt("nullable: null\n", "nullable: {}\n", value);
750 assert(mem.eql(u8, result, "nullable: null\n"));
751 }811 }
752 {812 {
753 var buf1: [32]u8 = undefined;
754 const value: error!i32 = 1234;813 const value: error!i32 = 1234;
755 const result = try bufPrint(buf1[0..], "error union: {}\n", value);814 try testFmt("error union: 1234\n", "error union: {}\n", value);
756 assert(mem.eql(u8, result, "error union: 1234\n"));
757 }815 }
758 {816 {
759 var buf1: [32]u8 = undefined;
760 const value: error!i32 = error.InvalidChar;817 const value: error!i32 = error.InvalidChar;
761 const result = try bufPrint(buf1[0..], "error union: {}\n", value);818 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
762 assert(mem.eql(u8, result, "error union: error.InvalidChar\n"));
763 }819 }
764 {820 {
765 var buf1: [32]u8 = undefined;
766 const value: u3 = 0b101;821 const value: u3 = 0b101;
767 const result = try bufPrint(buf1[0..], "u3: {}\n", value);822 try testFmt("u3: 5\n", "u3: {}\n", value);
768 assert(mem.eql(u8, result, "u3: 5\n"));
769 }823 }
824 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
825 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
770 {826 {
771 // Dummy field because of https://github.com/zig-lang/zig/issues/557.827 // Dummy field because of https://github.com/ziglang/zig/issues/557.
772 const Struct = struct {828 const Struct = struct {
773 unused: u8,829 unused: u8,
774 };830 };
775 var buf1: [32]u8 = undefined;831 var buf1: [32]u8 = undefined;
776 const value = Struct {832 const value = Struct{ .unused = 42 };
777 .unused = 42,
778 };
779 const result = try bufPrint(buf1[0..], "pointer: {}\n", &value);833 const result = try bufPrint(buf1[0..], "pointer: {}\n", &value);
780 assert(mem.startsWith(u8, result, "pointer: Struct@"));834 assert(mem.startsWith(u8, result, "pointer: Struct@"));
781 }835 }
...@@ -986,9 +1040,23 @@ test "fmt.format" {...@@ -986,9 +1040,23 @@ test "fmt.format" {
986 }1040 }
987}1041}
9881042
1043fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
1044 var buf: [100]u8 = undefined;
1045 const result = try bufPrint(buf[0..], template, args);
1046 if (mem.eql(u8, result, expected))
1047 return;
1048
1049 std.debug.warn("\n====== expected this output: =========\n");
1050 std.debug.warn("{}", expected);
1051 std.debug.warn("\n======== instead found this: =========\n");
1052 std.debug.warn("{}", result);
1053 std.debug.warn("\n======================================\n");
1054 return error.TestFailed;
1055}
1056
989pub fn trim(buf: []const u8) []const u8 {1057pub fn trim(buf: []const u8) []const u8 {
990 var start: usize = 0;1058 var start: usize = 0;
991 while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) { }1059 while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
9921060
993 var end: usize = buf.len;1061 var end: usize = buf.len;
994 while (true) {1062 while (true) {
...@@ -1000,7 +1068,6 @@ pub fn trim(buf: []const u8) []const u8 {...@@ -1000,7 +1068,6 @@ pub fn trim(buf: []const u8) []const u8 {
1000 }1068 }
1001 }1069 }
1002 break;1070 break;
1003
1004 }1071 }
1005 return buf[start..end];1072 return buf[start..end];
1006}1073}
...@@ -1015,7 +1082,10 @@ test "fmt.trim" {...@@ -1015,7 +1082,10 @@ test "fmt.trim" {
10151082
1016pub fn isWhiteSpace(byte: u8) bool {1083pub fn isWhiteSpace(byte: u8) bool {
1017 return switch (byte) {1084 return switch (byte) {
1018 ' ', '\t', '\n', '\r' => true,1085 ' ',
1086 '\t',
1087 '\n',
1088 '\r' => true,
1019 else => false,1089 else => false,
1020 };1090 };
1021}1091}
std/hash/crc.zig+16-16
...@@ -9,9 +9,9 @@ const std = @import("../index.zig");...@@ -9,9 +9,9 @@ const std = @import("../index.zig");
9const debug = std.debug;9const debug = std.debug;
1010
11pub const Polynomial = struct {11pub const Polynomial = struct {
12 const IEEE = 0xedb88320;12 const IEEE = 0xedb88320;
13 const Castagnoli = 0x82f63b78;13 const Castagnoli = 0x82f63b78;
14 const Koopman = 0xeb31d82e;14 const Koopman = 0xeb31d82e;
15};15};
1616
17// IEEE is by far the most common CRC and so is aliased by default.17// IEEE is by far the most common CRC and so is aliased by default.
...@@ -27,20 +27,22 @@ pub fn Crc32WithPoly(comptime poly: u32) type {...@@ -27,20 +27,22 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
2727
28 for (tables[0]) |*e, i| {28 for (tables[0]) |*e, i| {
29 var crc = u32(i);29 var crc = u32(i);
30 var j: usize = 0; while (j < 8) : (j += 1) {30 var j: usize = 0;
31 while (j < 8) : (j += 1) {
31 if (crc & 1 == 1) {32 if (crc & 1 == 1) {
32 crc = (crc >> 1) ^ poly;33 crc = (crc >> 1) ^ poly;
33 } else {34 } else {
34 crc = (crc >> 1);35 crc = (crc >> 1);
35 }36 }
36 }37 }
37 *e = crc;38 e.* = crc;
38 }39 }
3940
40 var i: usize = 0;41 var i: usize = 0;
41 while (i < 256) : (i += 1) {42 while (i < 256) : (i += 1) {
42 var crc = tables[0][i];43 var crc = tables[0][i];
43 var j: usize = 1; while (j < 8) : (j += 1) {44 var j: usize = 1;
45 while (j < 8) : (j += 1) {
44 const index = @truncate(u8, crc);46 const index = @truncate(u8, crc);
45 crc = tables[0][index] ^ (crc >> 8);47 crc = tables[0][index] ^ (crc >> 8);
46 tables[j][i] = crc;48 tables[j][i] = crc;
...@@ -53,22 +55,21 @@ pub fn Crc32WithPoly(comptime poly: u32) type {...@@ -53,22 +55,21 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
53 crc: u32,55 crc: u32,
5456
55 pub fn init() Self {57 pub fn init() Self {
56 return Self {58 return Self{ .crc = 0xffffffff };
57 .crc = 0xffffffff,
58 };
59 }59 }
6060
61 pub fn update(self: &Self, input: []const u8) void {61 pub fn update(self: &Self, input: []const u8) void {
62 var i: usize = 0;62 var i: usize = 0;
63 while (i + 8 <= input.len) : (i += 8) {63 while (i + 8 <= input.len) : (i += 8) {
64 const p = input[i..i+8];64 const p = input[i..i + 8];
6565
66 // Unrolling this way gives ~50Mb/s increase66 // Unrolling this way gives ~50Mb/s increase
67 self.crc ^= (u32(p[0]) << 0);67 self.crc ^= (u32(p[0]) << 0);
68 self.crc ^= (u32(p[1]) << 8);68 self.crc ^= (u32(p[1]) << 8);
69 self.crc ^= (u32(p[2]) << 16);69 self.crc ^= (u32(p[2]) << 16);
70 self.crc ^= (u32(p[3]) << 24);70 self.crc ^= (u32(p[3]) << 24);
7171
72
72 self.crc =73 self.crc =
73 lookup_tables[0][p[7]] ^74 lookup_tables[0][p[7]] ^
74 lookup_tables[1][p[6]] ^75 lookup_tables[1][p[6]] ^
...@@ -123,14 +124,15 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {...@@ -123,14 +124,15 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
123124
124 for (table) |*e, i| {125 for (table) |*e, i| {
125 var crc = u32(i * 16);126 var crc = u32(i * 16);
126 var j: usize = 0; while (j < 8) : (j += 1) {127 var j: usize = 0;
128 while (j < 8) : (j += 1) {
127 if (crc & 1 == 1) {129 if (crc & 1 == 1) {
128 crc = (crc >> 1) ^ poly;130 crc = (crc >> 1) ^ poly;
129 } else {131 } else {
130 crc = (crc >> 1);132 crc = (crc >> 1);
131 }133 }
132 }134 }
133 *e = crc;135 e.* = crc;
134 }136 }
135137
136 break :block table;138 break :block table;
...@@ -139,9 +141,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {...@@ -139,9 +141,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
139 crc: u32,141 crc: u32,
140142
141 pub fn init() Self {143 pub fn init() Self {
142 return Self {144 return Self{ .crc = 0xffffffff };
143 .crc = 0xffffffff,
144 };
145 }145 }
146146
147 pub fn update(self: &Self, input: []const u8) void {147 pub fn update(self: &Self, input: []const u8) void {
std/hash_map.zig+57-45
...@@ -9,10 +9,7 @@ const builtin = @import("builtin");...@@ -9,10 +9,7 @@ const builtin = @import("builtin");
9const want_modification_safety = builtin.mode != builtin.Mode.ReleaseFast;9const want_modification_safety = builtin.mode != builtin.Mode.ReleaseFast;
10const debug_u32 = if (want_modification_safety) u32 else void;10const debug_u32 = if (want_modification_safety) u32 else void;
1111
12pub fn HashMap(comptime K: type, comptime V: type,12pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn(key: K) u32, comptime eql: fn(a: K, b: K) bool) type {
13 comptime hash: fn(key: K)u32,
14 comptime eql: fn(a: K, b: K)bool) type
15{
16 return struct {13 return struct {
17 entries: []Entry,14 entries: []Entry,
18 size: usize,15 size: usize,
...@@ -65,7 +62,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -65,7 +62,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
65 };62 };
6663
67 pub fn init(allocator: &Allocator) Self {64 pub fn init(allocator: &Allocator) Self {
68 return Self {65 return Self{
69 .entries = []Entry{},66 .entries = []Entry{},
70 .allocator = allocator,67 .allocator = allocator,
71 .size = 0,68 .size = 0,
...@@ -129,34 +126,36 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -129,34 +126,36 @@ pub fn HashMap(comptime K: type, comptime V: type,
129 if (hm.entries.len == 0) return null;126 if (hm.entries.len == 0) return null;
130 hm.incrementModificationCount();127 hm.incrementModificationCount();
131 const start_index = hm.keyToIndex(key);128 const start_index = hm.keyToIndex(key);
132 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {129 {
133 const index = (start_index + roll_over) % hm.entries.len;130 var roll_over: usize = 0;
134 var entry = &hm.entries[index];131 while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
135132 const index = (start_index + roll_over) % hm.entries.len;
136 if (!entry.used)133 var entry = &hm.entries[index];
137 return null;134
138135 if (!entry.used) return null;
139 if (!eql(entry.key, key)) continue;136
140137 if (!eql(entry.key, key)) continue;
141 while (roll_over < hm.entries.len) : (roll_over += 1) {138
142 const next_index = (start_index + roll_over + 1) % hm.entries.len;139 while (roll_over < hm.entries.len) : (roll_over += 1) {
143 const next_entry = &hm.entries[next_index];140 const next_index = (start_index + roll_over + 1) % hm.entries.len;
144 if (!next_entry.used or next_entry.distance_from_start_index == 0) {141 const next_entry = &hm.entries[next_index];
145 entry.used = false;142 if (!next_entry.used or next_entry.distance_from_start_index == 0) {
146 hm.size -= 1;143 entry.used = false;
147 return entry;144 hm.size -= 1;
145 return entry;
146 }
147 entry.* = next_entry.*;
148 entry.distance_from_start_index -= 1;
149 entry = next_entry;
148 }150 }
149 *entry = *next_entry;151 unreachable; // shifting everything in the table
150 entry.distance_from_start_index -= 1;
151 entry = next_entry;
152 }152 }
153 unreachable; // shifting everything in the table153 }
154 }}
155 return null;154 return null;
156 }155 }
157156
158 pub fn iterator(hm: &const Self) Iterator {157 pub fn iterator(hm: &const Self) Iterator {
159 return Iterator {158 return Iterator{
160 .hm = hm,159 .hm = hm,
161 .count = 0,160 .count = 0,
162 .index = 0,161 .index = 0,
...@@ -182,21 +181,23 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -182,21 +181,23 @@ pub fn HashMap(comptime K: type, comptime V: type,
182 /// Returns the value that was already there.181 /// Returns the value that was already there.
183 fn internalPut(hm: &Self, orig_key: K, orig_value: &const V) ?V {182 fn internalPut(hm: &Self, orig_key: K, orig_value: &const V) ?V {
184 var key = orig_key;183 var key = orig_key;
185 var value = *orig_value;184 var value = orig_value.*;
186 const start_index = hm.keyToIndex(key);185 const start_index = hm.keyToIndex(key);
187 var roll_over: usize = 0;186 var roll_over: usize = 0;
188 var distance_from_start_index: usize = 0;187 var distance_from_start_index: usize = 0;
189 while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1;}) {188 while (roll_over < hm.entries.len) : ({
189 roll_over += 1;
190 distance_from_start_index += 1;
191 }) {
190 const index = (start_index + roll_over) % hm.entries.len;192 const index = (start_index + roll_over) % hm.entries.len;
191 const entry = &hm.entries[index];193 const entry = &hm.entries[index];
192194
193 if (entry.used and !eql(entry.key, key)) {195 if (entry.used and !eql(entry.key, key)) {
194 if (entry.distance_from_start_index < distance_from_start_index) {196 if (entry.distance_from_start_index < distance_from_start_index) {
195 // robin hood to the rescue197 // robin hood to the rescue
196 const tmp = *entry;198 const tmp = entry.*;
197 hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index,199 hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index, distance_from_start_index);
198 distance_from_start_index);200 entry.* = Entry{
199 *entry = Entry {
200 .used = true,201 .used = true,
201 .distance_from_start_index = distance_from_start_index,202 .distance_from_start_index = distance_from_start_index,
202 .key = key,203 .key = key,
...@@ -219,7 +220,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -219,7 +220,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
219 }220 }
220221
221 hm.max_distance_from_start_index = math.max(distance_from_start_index, hm.max_distance_from_start_index);222 hm.max_distance_from_start_index = math.max(distance_from_start_index, hm.max_distance_from_start_index);
222 *entry = Entry {223 entry.* = Entry{
223 .used = true,224 .used = true,
224 .distance_from_start_index = distance_from_start_index,225 .distance_from_start_index = distance_from_start_index,
225 .key = key,226 .key = key,
...@@ -232,13 +233,16 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -232,13 +233,16 @@ pub fn HashMap(comptime K: type, comptime V: type,
232233
233 fn internalGet(hm: &const Self, key: K) ?&Entry {234 fn internalGet(hm: &const Self, key: K) ?&Entry {
234 const start_index = hm.keyToIndex(key);235 const start_index = hm.keyToIndex(key);
235 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {236 {
236 const index = (start_index + roll_over) % hm.entries.len;237 var roll_over: usize = 0;
237 const entry = &hm.entries[index];238 while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
238239 const index = (start_index + roll_over) % hm.entries.len;
239 if (!entry.used) return null;240 const entry = &hm.entries[index];
240 if (eql(entry.key, key)) return entry;241
241 }}242 if (!entry.used) return null;
243 if (eql(entry.key, key)) return entry;
244 }
245 }
242 return null;246 return null;
243 }247 }
244248
...@@ -282,11 +286,19 @@ test "iterator hash map" {...@@ -282,11 +286,19 @@ test "iterator hash map" {
282 assert((reset_map.put(2, 22) catch unreachable) == null);286 assert((reset_map.put(2, 22) catch unreachable) == null);
283 assert((reset_map.put(3, 33) catch unreachable) == null);287 assert((reset_map.put(3, 33) catch unreachable) == null);
284288
285 var keys = []i32 { 1, 2, 3 };289 var keys = []i32{
286 var values = []i32 { 11, 22, 33 };290 1,
291 2,
292 3,
293 };
294 var values = []i32{
295 11,
296 22,
297 33,
298 };
287299
288 var it = reset_map.iterator();300 var it = reset_map.iterator();
289 var count : usize = 0;301 var count: usize = 0;
290 while (it.next()) |next| {302 while (it.next()) |next| {
291 assert(next.key == keys[count]);303 assert(next.key == keys[count]);
292 assert(next.value == values[count]);304 assert(next.value == values[count]);
...@@ -305,7 +317,7 @@ test "iterator hash map" {...@@ -305,7 +317,7 @@ test "iterator hash map" {
305 }317 }
306318
307 it.reset();319 it.reset();
308 var entry = ?? it.next();320 var entry = ??it.next();
309 assert(entry.key == keys[0]);321 assert(entry.key == keys[0]);
310 assert(entry.value == values[0]);322 assert(entry.value == values[0]);
311}323}
std/heap.zig+52-54
...@@ -10,7 +10,7 @@ const c = std.c;...@@ -10,7 +10,7 @@ const c = std.c;
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
1111
12pub const c_allocator = &c_allocator_state;12pub const c_allocator = &c_allocator_state;
13var c_allocator_state = Allocator {13var c_allocator_state = Allocator{
14 .allocFn = cAlloc,14 .allocFn = cAlloc,
15 .reallocFn = cRealloc,15 .reallocFn = cRealloc,
16 .freeFn = cFree,16 .freeFn = cFree,
...@@ -18,10 +18,7 @@ var c_allocator_state = Allocator {...@@ -18,10 +18,7 @@ var c_allocator_state = Allocator {
1818
19fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 {19fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 {
20 assert(alignment <= @alignOf(c_longdouble));20 assert(alignment <= @alignOf(c_longdouble));
21 return if (c.malloc(n)) |buf|21 return if (c.malloc(n)) |buf| @ptrCast(&u8, buf)[0..n] else error.OutOfMemory;
22 @ptrCast(&u8, buf)[0..n]
23 else
24 error.OutOfMemory;
25}22}
2623
27fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {24fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
...@@ -48,8 +45,8 @@ pub const DirectAllocator = struct {...@@ -48,8 +45,8 @@ pub const DirectAllocator = struct {
48 const HeapHandle = if (builtin.os == Os.windows) os.windows.HANDLE else void;45 const HeapHandle = if (builtin.os == Os.windows) os.windows.HANDLE else void;
4946
50 pub fn init() DirectAllocator {47 pub fn init() DirectAllocator {
51 return DirectAllocator {48 return DirectAllocator{
52 .allocator = Allocator {49 .allocator = Allocator{
53 .allocFn = alloc,50 .allocFn = alloc,
54 .reallocFn = realloc,51 .reallocFn = realloc,
55 .freeFn = free,52 .freeFn = free,
...@@ -71,39 +68,39 @@ pub const DirectAllocator = struct {...@@ -71,39 +68,39 @@ pub const DirectAllocator = struct {
71 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);68 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
7269
73 switch (builtin.os) {70 switch (builtin.os) {
74 Os.linux, Os.macosx, Os.ios => {71 Os.linux,
72 Os.macosx,
73 Os.ios => {
75 const p = os.posix;74 const p = os.posix;
76 const alloc_size = if(alignment <= os.page_size) n else n + alignment;75 const alloc_size = if (alignment <= os.page_size) n else n + alignment;
77 const addr = p.mmap(null, alloc_size, p.PROT_READ|p.PROT_WRITE, 76 const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0);
78 p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0);77 if (addr == p.MAP_FAILED) return error.OutOfMemory;
79 if(addr == p.MAP_FAILED) return error.OutOfMemory;78
80 79 if (alloc_size == n) return @intToPtr(&u8, addr)[0..n];
81 if(alloc_size == n) return @intToPtr(&u8, addr)[0..n];80
82
83 var aligned_addr = addr & ~usize(alignment - 1);81 var aligned_addr = addr & ~usize(alignment - 1);
84 aligned_addr += alignment;82 aligned_addr += alignment;
85 83
86 //We can unmap the unused portions of our mmap, but we must only84 //We can unmap the unused portions of our mmap, but we must only
87 // pass munmap bytes that exist outside our allocated pages or it85 // pass munmap bytes that exist outside our allocated pages or it
88 // will happily eat us too86 // will happily eat us too
89 87
90 //Since alignment > page_size, we are by definition on a page boundry88 //Since alignment > page_size, we are by definition on a page boundry
91 const unused_start = addr;89 const unused_start = addr;
92 const unused_len = aligned_addr - 1 - unused_start;90 const unused_len = aligned_addr - 1 - unused_start;
9391
94 var err = p.munmap(unused_start, unused_len);92 var err = p.munmap(unused_start, unused_len);
95 debug.assert(p.getErrno(err) == 0);93 debug.assert(p.getErrno(err) == 0);
96 94
97 //It is impossible that there is an unoccupied page at the top of our95 //It is impossible that there is an unoccupied page at the top of our
98 // mmap.96 // mmap.
99 97
100 return @intToPtr(&u8, aligned_addr)[0..n];98 return @intToPtr(&u8, aligned_addr)[0..n];
101 },99 },
102 Os.windows => {100 Os.windows => {
103 const amt = n + alignment + @sizeOf(usize);101 const amt = n + alignment + @sizeOf(usize);
104 const heap_handle = self.heap_handle ?? blk: {102 const heap_handle = self.heap_handle ?? blk: {
105 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0)103 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) ?? return error.OutOfMemory;
106 ?? return error.OutOfMemory;
107 self.heap_handle = hh;104 self.heap_handle = hh;
108 break :blk hh;105 break :blk hh;
109 };106 };
...@@ -113,7 +110,7 @@ pub const DirectAllocator = struct {...@@ -113,7 +110,7 @@ pub const DirectAllocator = struct {
113 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);110 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
114 const adjusted_addr = root_addr + march_forward_bytes;111 const adjusted_addr = root_addr + march_forward_bytes;
115 const record_addr = adjusted_addr + n;112 const record_addr = adjusted_addr + n;
116 *@intToPtr(&align(1) usize, record_addr) = root_addr;113 @intToPtr(&align(1) usize, record_addr).* = root_addr;
117 return @intToPtr(&u8, adjusted_addr)[0..n];114 return @intToPtr(&u8, adjusted_addr)[0..n];
118 },115 },
119 else => @compileError("Unsupported OS"),116 else => @compileError("Unsupported OS"),
...@@ -124,7 +121,9 @@ pub const DirectAllocator = struct {...@@ -124,7 +121,9 @@ pub const DirectAllocator = struct {
124 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);121 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
125122
126 switch (builtin.os) {123 switch (builtin.os) {
127 Os.linux, Os.macosx, Os.ios => {124 Os.linux,
125 Os.macosx,
126 Os.ios => {
128 if (new_size <= old_mem.len) {127 if (new_size <= old_mem.len) {
129 const base_addr = @ptrToInt(old_mem.ptr);128 const base_addr = @ptrToInt(old_mem.ptr);
130 const old_addr_end = base_addr + old_mem.len;129 const old_addr_end = base_addr + old_mem.len;
...@@ -144,13 +143,13 @@ pub const DirectAllocator = struct {...@@ -144,13 +143,13 @@ pub const DirectAllocator = struct {
144 Os.windows => {143 Os.windows => {
145 const old_adjusted_addr = @ptrToInt(old_mem.ptr);144 const old_adjusted_addr = @ptrToInt(old_mem.ptr);
146 const old_record_addr = old_adjusted_addr + old_mem.len;145 const old_record_addr = old_adjusted_addr + old_mem.len;
147 const root_addr = *@intToPtr(&align(1) usize, old_record_addr);146 const root_addr = @intToPtr(&align(1) usize, old_record_addr).*;
148 const old_ptr = @intToPtr(os.windows.LPVOID, root_addr);147 const old_ptr = @intToPtr(os.windows.LPVOID, root_addr);
149 const amt = new_size + alignment + @sizeOf(usize);148 const amt = new_size + alignment + @sizeOf(usize);
150 const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: {149 const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: {
151 if (new_size > old_mem.len) return error.OutOfMemory;150 if (new_size > old_mem.len) return error.OutOfMemory;
152 const new_record_addr = old_record_addr - new_size + old_mem.len;151 const new_record_addr = old_record_addr - new_size + old_mem.len;
153 *@intToPtr(&align(1) usize, new_record_addr) = root_addr;152 @intToPtr(&align(1) usize, new_record_addr).* = root_addr;
154 return old_mem[0..new_size];153 return old_mem[0..new_size];
155 };154 };
156 const offset = old_adjusted_addr - root_addr;155 const offset = old_adjusted_addr - root_addr;
...@@ -158,7 +157,7 @@ pub const DirectAllocator = struct {...@@ -158,7 +157,7 @@ pub const DirectAllocator = struct {
158 const new_adjusted_addr = new_root_addr + offset;157 const new_adjusted_addr = new_root_addr + offset;
159 assert(new_adjusted_addr % alignment == 0);158 assert(new_adjusted_addr % alignment == 0);
160 const new_record_addr = new_adjusted_addr + new_size;159 const new_record_addr = new_adjusted_addr + new_size;
161 *@intToPtr(&align(1) usize, new_record_addr) = new_root_addr;160 @intToPtr(&align(1) usize, new_record_addr).* = new_root_addr;
162 return @intToPtr(&u8, new_adjusted_addr)[0..new_size];161 return @intToPtr(&u8, new_adjusted_addr)[0..new_size];
163 },162 },
164 else => @compileError("Unsupported OS"),163 else => @compileError("Unsupported OS"),
...@@ -169,12 +168,14 @@ pub const DirectAllocator = struct {...@@ -169,12 +168,14 @@ pub const DirectAllocator = struct {
169 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);168 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
170169
171 switch (builtin.os) {170 switch (builtin.os) {
172 Os.linux, Os.macosx, Os.ios => {171 Os.linux,
172 Os.macosx,
173 Os.ios => {
173 _ = os.posix.munmap(@ptrToInt(bytes.ptr), bytes.len);174 _ = os.posix.munmap(@ptrToInt(bytes.ptr), bytes.len);
174 },175 },
175 Os.windows => {176 Os.windows => {
176 const record_addr = @ptrToInt(bytes.ptr) + bytes.len;177 const record_addr = @ptrToInt(bytes.ptr) + bytes.len;
177 const root_addr = *@intToPtr(&align(1) usize, record_addr);178 const root_addr = @intToPtr(&align(1) usize, record_addr).*;
178 const ptr = @intToPtr(os.windows.LPVOID, root_addr);179 const ptr = @intToPtr(os.windows.LPVOID, root_addr);
179 _ = os.windows.HeapFree(??self.heap_handle, 0, ptr);180 _ = os.windows.HeapFree(??self.heap_handle, 0, ptr);
180 },181 },
...@@ -195,8 +196,8 @@ pub const ArenaAllocator = struct {...@@ -195,8 +196,8 @@ pub const ArenaAllocator = struct {
195 const BufNode = std.LinkedList([]u8).Node;196 const BufNode = std.LinkedList([]u8).Node;
196197
197 pub fn init(child_allocator: &Allocator) ArenaAllocator {198 pub fn init(child_allocator: &Allocator) ArenaAllocator {
198 return ArenaAllocator {199 return ArenaAllocator{
199 .allocator = Allocator {200 .allocator = Allocator{
200 .allocFn = alloc,201 .allocFn = alloc,
201 .reallocFn = realloc,202 .reallocFn = realloc,
202 .freeFn = free,203 .freeFn = free,
...@@ -228,7 +229,7 @@ pub const ArenaAllocator = struct {...@@ -228,7 +229,7 @@ pub const ArenaAllocator = struct {
228 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);229 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
229 const buf_node_slice = ([]BufNode)(buf[0..@sizeOf(BufNode)]);230 const buf_node_slice = ([]BufNode)(buf[0..@sizeOf(BufNode)]);
230 const buf_node = &buf_node_slice[0];231 const buf_node = &buf_node_slice[0];
231 *buf_node = BufNode {232 buf_node.* = BufNode{
232 .data = buf,233 .data = buf,
233 .prev = null,234 .prev = null,
234 .next = null,235 .next = null,
...@@ -253,7 +254,7 @@ pub const ArenaAllocator = struct {...@@ -253,7 +254,7 @@ pub const ArenaAllocator = struct {
253 cur_node = try self.createNode(cur_buf.len, n + alignment);254 cur_node = try self.createNode(cur_buf.len, n + alignment);
254 continue;255 continue;
255 }256 }
256 const result = cur_buf[adjusted_index .. new_end_index];257 const result = cur_buf[adjusted_index..new_end_index];
257 self.end_index = new_end_index;258 self.end_index = new_end_index;
258 return result;259 return result;
259 }260 }
...@@ -269,7 +270,7 @@ pub const ArenaAllocator = struct {...@@ -269,7 +270,7 @@ pub const ArenaAllocator = struct {
269 }270 }
270 }271 }
271272
272 fn free(allocator: &Allocator, bytes: []u8) void { }273 fn free(allocator: &Allocator, bytes: []u8) void {}
273};274};
274275
275pub const FixedBufferAllocator = struct {276pub const FixedBufferAllocator = struct {
...@@ -278,8 +279,8 @@ pub const FixedBufferAllocator = struct {...@@ -278,8 +279,8 @@ pub const FixedBufferAllocator = struct {
278 buffer: []u8,279 buffer: []u8,
279280
280 pub fn init(buffer: []u8) FixedBufferAllocator {281 pub fn init(buffer: []u8) FixedBufferAllocator {
281 return FixedBufferAllocator {282 return FixedBufferAllocator{
282 .allocator = Allocator {283 .allocator = Allocator{
283 .allocFn = alloc,284 .allocFn = alloc,
284 .reallocFn = realloc,285 .reallocFn = realloc,
285 .freeFn = free,286 .freeFn = free,
...@@ -299,7 +300,7 @@ pub const FixedBufferAllocator = struct {...@@ -299,7 +300,7 @@ pub const FixedBufferAllocator = struct {
299 if (new_end_index > self.buffer.len) {300 if (new_end_index > self.buffer.len) {
300 return error.OutOfMemory;301 return error.OutOfMemory;
301 }302 }
302 const result = self.buffer[adjusted_index .. new_end_index];303 const result = self.buffer[adjusted_index..new_end_index];
303 self.end_index = new_end_index;304 self.end_index = new_end_index;
304305
305 return result;306 return result;
...@@ -315,7 +316,7 @@ pub const FixedBufferAllocator = struct {...@@ -315,7 +316,7 @@ pub const FixedBufferAllocator = struct {
315 }316 }
316 }317 }
317318
318 fn free(allocator: &Allocator, bytes: []u8) void { }319 fn free(allocator: &Allocator, bytes: []u8) void {}
319};320};
320321
321/// lock free322/// lock free
...@@ -325,8 +326,8 @@ pub const ThreadSafeFixedBufferAllocator = struct {...@@ -325,8 +326,8 @@ pub const ThreadSafeFixedBufferAllocator = struct {
325 buffer: []u8,326 buffer: []u8,
326327
327 pub fn init(buffer: []u8) ThreadSafeFixedBufferAllocator {328 pub fn init(buffer: []u8) ThreadSafeFixedBufferAllocator {
328 return ThreadSafeFixedBufferAllocator {329 return ThreadSafeFixedBufferAllocator{
329 .allocator = Allocator {330 .allocator = Allocator{
330 .allocFn = alloc,331 .allocFn = alloc,
331 .reallocFn = realloc,332 .reallocFn = realloc,
332 .freeFn = free,333 .freeFn = free,
...@@ -348,8 +349,7 @@ pub const ThreadSafeFixedBufferAllocator = struct {...@@ -348,8 +349,7 @@ pub const ThreadSafeFixedBufferAllocator = struct {
348 if (new_end_index > self.buffer.len) {349 if (new_end_index > self.buffer.len) {
349 return error.OutOfMemory;350 return error.OutOfMemory;
350 }351 }
351 end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index,352 end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) ?? return self.buffer[adjusted_index..new_end_index];
352 builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) ?? return self.buffer[adjusted_index .. new_end_index];
353 }353 }
354 }354 }
355355
...@@ -363,11 +363,9 @@ pub const ThreadSafeFixedBufferAllocator = struct {...@@ -363,11 +363,9 @@ pub const ThreadSafeFixedBufferAllocator = struct {
363 }363 }
364 }364 }
365365
366 fn free(allocator: &Allocator, bytes: []u8) void { }366 fn free(allocator: &Allocator, bytes: []u8) void {}
367};367};
368368
369
370
371test "c_allocator" {369test "c_allocator" {
372 if (builtin.link_libc) {370 if (builtin.link_libc) {
373 var slice = c_allocator.alloc(u8, 50) catch return;371 var slice = c_allocator.alloc(u8, 50) catch return;
...@@ -415,8 +413,8 @@ fn testAllocator(allocator: &mem.Allocator) !void {...@@ -415,8 +413,8 @@ fn testAllocator(allocator: &mem.Allocator) !void {
415 var slice = try allocator.alloc(&i32, 100);413 var slice = try allocator.alloc(&i32, 100);
416414
417 for (slice) |*item, i| {415 for (slice) |*item, i| {
418 *item = try allocator.create(i32);416 item.* = try allocator.create(i32);
419 **item = i32(i);417 item.*.* = i32(i);
420 }418 }
421419
422 for (slice) |item, i| {420 for (slice) |item, i| {
...@@ -434,26 +432,26 @@ fn testAllocator(allocator: &mem.Allocator) !void {...@@ -434,26 +432,26 @@ fn testAllocator(allocator: &mem.Allocator) !void {
434fn testAllocatorLargeAlignment(allocator: &mem.Allocator) mem.Allocator.Error!void {432fn testAllocatorLargeAlignment(allocator: &mem.Allocator) mem.Allocator.Error!void {
435 //Maybe a platform's page_size is actually the same as or 433 //Maybe a platform's page_size is actually the same as or
436 // very near usize?434 // very near usize?
437 if(os.page_size << 2 > @maxValue(usize)) return;435 if (os.page_size << 2 > @maxValue(usize)) return;
438 436
439 const USizeShift = @IntType(false, std.math.log2(usize.bit_count));437 const USizeShift = @IntType(false, std.math.log2(usize.bit_count));
440 const large_align = u29(os.page_size << 2);438 const large_align = u29(os.page_size << 2);
441 439
442 var align_mask: usize = undefined;440 var align_mask: usize = undefined;
443 _ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(large_align)), &align_mask);441 _ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(large_align)), &align_mask);
444 442
445 var slice = try allocator.allocFn(allocator, 500, large_align);443 var slice = try allocator.allocFn(allocator, 500, large_align);
446 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));444 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
447 445
448 slice = try allocator.reallocFn(allocator, slice, 100, large_align);446 slice = try allocator.reallocFn(allocator, slice, 100, large_align);
449 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));447 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
450 448
451 slice = try allocator.reallocFn(allocator, slice, 5000, large_align);449 slice = try allocator.reallocFn(allocator, slice, 5000, large_align);
452 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));450 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
453 451
454 slice = try allocator.reallocFn(allocator, slice, 10, large_align);452 slice = try allocator.reallocFn(allocator, slice, 10, large_align);
455 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));453 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
456 454
457 slice = try allocator.reallocFn(allocator, slice, 20000, large_align);455 slice = try allocator.reallocFn(allocator, slice, 20000, large_align);
458 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));456 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
459457
std/io.zig+18-47
...@@ -18,32 +18,17 @@ const is_windows = builtin.os == builtin.Os.windows;...@@ -18,32 +18,17 @@ const is_windows = builtin.os == builtin.Os.windows;
18const GetStdIoErrs = os.WindowsGetStdHandleErrs;18const GetStdIoErrs = os.WindowsGetStdHandleErrs;
1919
20pub fn getStdErr() GetStdIoErrs!File {20pub fn getStdErr() GetStdIoErrs!File {
21 const handle = if (is_windows)21 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE) else if (is_posix) os.posix.STDERR_FILENO else unreachable;
22 try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE)
23 else if (is_posix)
24 os.posix.STDERR_FILENO
25 else
26 unreachable;
27 return File.openHandle(handle);22 return File.openHandle(handle);
28}23}
2924
30pub fn getStdOut() GetStdIoErrs!File {25pub fn getStdOut() GetStdIoErrs!File {
31 const handle = if (is_windows)26 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE) else if (is_posix) os.posix.STDOUT_FILENO else unreachable;
32 try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE)
33 else if (is_posix)
34 os.posix.STDOUT_FILENO
35 else
36 unreachable;
37 return File.openHandle(handle);27 return File.openHandle(handle);
38}28}
3929
40pub fn getStdIn() GetStdIoErrs!File {30pub fn getStdIn() GetStdIoErrs!File {
41 const handle = if (is_windows)31 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE) else if (is_posix) os.posix.STDIN_FILENO else unreachable;
42 try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE)
43 else if (is_posix)
44 os.posix.STDIN_FILENO
45 else
46 unreachable;
47 return File.openHandle(handle);32 return File.openHandle(handle);
48}33}
4934
...@@ -56,11 +41,9 @@ pub const FileInStream = struct {...@@ -56,11 +41,9 @@ pub const FileInStream = struct {
56 pub const Stream = InStream(Error);41 pub const Stream = InStream(Error);
5742
58 pub fn init(file: &File) FileInStream {43 pub fn init(file: &File) FileInStream {
59 return FileInStream {44 return FileInStream{
60 .file = file,45 .file = file,
61 .stream = Stream {46 .stream = Stream{ .readFn = readFn },
62 .readFn = readFn,
63 },
64 };47 };
65 }48 }
6649
...@@ -79,11 +62,9 @@ pub const FileOutStream = struct {...@@ -79,11 +62,9 @@ pub const FileOutStream = struct {
79 pub const Stream = OutStream(Error);62 pub const Stream = OutStream(Error);
8063
81 pub fn init(file: &File) FileOutStream {64 pub fn init(file: &File) FileOutStream {
82 return FileOutStream {65 return FileOutStream{
83 .file = file,66 .file = file,
84 .stream = Stream {67 .stream = Stream{ .writeFn = writeFn },
85 .writeFn = writeFn,
86 },
87 };68 };
88 }69 }
8970
...@@ -121,8 +102,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -121,8 +102,7 @@ pub fn InStream(comptime ReadError: type) type {
121 }102 }
122103
123 const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);104 const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);
124 if (new_buf_size == actual_buf_len)105 if (new_buf_size == actual_buf_len) return error.StreamTooLong;
125 return error.StreamTooLong;
126 try buffer.resize(new_buf_size);106 try buffer.resize(new_buf_size);
127 }107 }
128 }108 }
...@@ -165,9 +145,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -165,9 +145,7 @@ pub fn InStream(comptime ReadError: type) type {
165 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.145 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
166 /// Caller owns returned memory.146 /// Caller owns returned memory.
167 /// If this function returns an error, the contents from the stream read so far are lost.147 /// If this function returns an error, the contents from the stream read so far are lost.
168 pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator,148 pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator, delimiter: u8, max_size: usize) ![]u8 {
169 delimiter: u8, max_size: usize) ![]u8
170 {
171 var buf = Buffer.initNull(allocator);149 var buf = Buffer.initNull(allocator);
172 defer buf.deinit();150 defer buf.deinit();
173151
...@@ -283,7 +261,7 @@ pub fn BufferedInStream(comptime Error: type) type {...@@ -283,7 +261,7 @@ pub fn BufferedInStream(comptime Error: type) type {
283pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {261pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {
284 return struct {262 return struct {
285 const Self = this;263 const Self = this;
286 const Stream = InStream(Error); 264 const Stream = InStream(Error);
287265
288 pub stream: Stream,266 pub stream: Stream,
289267
...@@ -294,7 +272,7 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)...@@ -294,7 +272,7 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
294 end_index: usize,272 end_index: usize,
295273
296 pub fn init(unbuffered_in_stream: &Stream) Self {274 pub fn init(unbuffered_in_stream: &Stream) Self {
297 return Self {275 return Self{
298 .unbuffered_in_stream = unbuffered_in_stream,276 .unbuffered_in_stream = unbuffered_in_stream,
299 .buffer = undefined,277 .buffer = undefined,
300278
...@@ -305,9 +283,7 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)...@@ -305,9 +283,7 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
305 .start_index = buffer_size,283 .start_index = buffer_size,
306 .end_index = buffer_size,284 .end_index = buffer_size,
307285
308 .stream = Stream {286 .stream = Stream{ .readFn = readFn },
309 .readFn = readFn,
310 },
311 };287 };
312 }288 }
313289
...@@ -368,13 +344,11 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamEr...@@ -368,13 +344,11 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamEr
368 index: usize,344 index: usize,
369345
370 pub fn init(unbuffered_out_stream: &Stream) Self {346 pub fn init(unbuffered_out_stream: &Stream) Self {
371 return Self {347 return Self{
372 .unbuffered_out_stream = unbuffered_out_stream,348 .unbuffered_out_stream = unbuffered_out_stream,
373 .buffer = undefined,349 .buffer = undefined,
374 .index = 0,350 .index = 0,
375 .stream = Stream {351 .stream = Stream{ .writeFn = writeFn },
376 .writeFn = writeFn,
377 },
378 };352 };
379 }353 }
380354
...@@ -416,11 +390,9 @@ pub const BufferOutStream = struct {...@@ -416,11 +390,9 @@ pub const BufferOutStream = struct {
416 pub const Stream = OutStream(Error);390 pub const Stream = OutStream(Error);
417391
418 pub fn init(buffer: &Buffer) BufferOutStream {392 pub fn init(buffer: &Buffer) BufferOutStream {
419 return BufferOutStream {393 return BufferOutStream{
420 .buffer = buffer,394 .buffer = buffer,
421 .stream = Stream {395 .stream = Stream{ .writeFn = writeFn },
422 .writeFn = writeFn,
423 },
424 };396 };
425 }397 }
426398
...@@ -430,7 +402,6 @@ pub const BufferOutStream = struct {...@@ -430,7 +402,6 @@ pub const BufferOutStream = struct {
430 }402 }
431};403};
432404
433
434pub const BufferedAtomicFile = struct {405pub const BufferedAtomicFile = struct {
435 atomic_file: os.AtomicFile,406 atomic_file: os.AtomicFile,
436 file_stream: FileOutStream,407 file_stream: FileOutStream,
...@@ -441,7 +412,7 @@ pub const BufferedAtomicFile = struct {...@@ -441,7 +412,7 @@ pub const BufferedAtomicFile = struct {
441 var self = try allocator.create(BufferedAtomicFile);412 var self = try allocator.create(BufferedAtomicFile);
442 errdefer allocator.destroy(self);413 errdefer allocator.destroy(self);
443414
444 *self = BufferedAtomicFile {415 self.* = BufferedAtomicFile{
445 .atomic_file = undefined,416 .atomic_file = undefined,
446 .file_stream = undefined,417 .file_stream = undefined,
447 .buffered_stream = undefined,418 .buffered_stream = undefined,
...@@ -489,7 +460,7 @@ pub fn readLine(buf: []u8) !usize {...@@ -489,7 +460,7 @@ pub fn readLine(buf: []u8) !usize {
489 '\r' => {460 '\r' => {
490 // trash the following \n461 // trash the following \n
491 _ = stream.readByte() catch return error.EndOfFile;462 _ = stream.readByte() catch return error.EndOfFile;
492 return index;463 return index;
493 },464 },
494 '\n' => return index,465 '\n' => return index,
495 else => {466 else => {
std/io_test.zig+17-1
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("index.zig");1const std = @import("index.zig");
2const io = std.io;2const io = std.io;
3const allocator = std.debug.global_allocator;
4const DefaultPrng = std.rand.DefaultPrng;3const DefaultPrng = std.rand.DefaultPrng;
5const assert = std.debug.assert;4const assert = std.debug.assert;
6const mem = std.mem;5const mem = std.mem;
...@@ -8,6 +7,9 @@ const os = std.os;...@@ -8,6 +7,9 @@ const os = std.os;
8const builtin = @import("builtin");7const builtin = @import("builtin");
98
10test "write a file, read it, then delete it" {9test "write a file, read it, then delete it" {
10 var raw_bytes: [200 * 1024]u8 = undefined;
11 var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator;
12
11 var data: [1024]u8 = undefined;13 var data: [1024]u8 = undefined;
12 var prng = DefaultPrng.init(1234);14 var prng = DefaultPrng.init(1234);
13 prng.random.bytes(data[0..]);15 prng.random.bytes(data[0..]);
...@@ -44,3 +46,17 @@ test "write a file, read it, then delete it" {...@@ -44,3 +46,17 @@ test "write a file, read it, then delete it" {
44 }46 }
45 try os.deleteFile(allocator, tmp_file_name);47 try os.deleteFile(allocator, tmp_file_name);
46}48}
49
50test "BufferOutStream" {
51 var bytes: [100]u8 = undefined;
52 var allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
53
54 var buffer = try std.Buffer.initSize(allocator, 0);
55 var buf_stream = &std.io.BufferOutStream.init(&buffer).stream;
56
57 const x: i32 = 42;
58 const y: i32 = 1234;
59 try buf_stream.print("x: {}\ny: {}\n", x, y);
60
61 assert(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n"));
62}
std/json.zig+126-85
...@@ -35,7 +35,7 @@ pub const Token = struct {...@@ -35,7 +35,7 @@ pub const Token = struct {
35 };35 };
3636
37 pub fn init(id: Id, count: usize, offset: u1) Token {37 pub fn init(id: Id, count: usize, offset: u1) Token {
38 return Token {38 return Token{
39 .id = id,39 .id = id,
40 .offset = offset,40 .offset = offset,
41 .string_has_escape = false,41 .string_has_escape = false,
...@@ -45,7 +45,7 @@ pub const Token = struct {...@@ -45,7 +45,7 @@ pub const Token = struct {
45 }45 }
4646
47 pub fn initString(count: usize, has_unicode_escape: bool) Token {47 pub fn initString(count: usize, has_unicode_escape: bool) Token {
48 return Token {48 return Token{
49 .id = Id.String,49 .id = Id.String,
50 .offset = 0,50 .offset = 0,
51 .string_has_escape = has_unicode_escape,51 .string_has_escape = has_unicode_escape,
...@@ -55,7 +55,7 @@ pub const Token = struct {...@@ -55,7 +55,7 @@ pub const Token = struct {
55 }55 }
5656
57 pub fn initNumber(count: usize, number_is_integer: bool) Token {57 pub fn initNumber(count: usize, number_is_integer: bool) Token {
58 return Token {58 return Token{
59 .id = Id.Number,59 .id = Id.Number,
60 .offset = 0,60 .offset = 0,
61 .string_has_escape = false,61 .string_has_escape = false,
...@@ -66,7 +66,7 @@ pub const Token = struct {...@@ -66,7 +66,7 @@ pub const Token = struct {
6666
67 // A marker token is a zero-length67 // A marker token is a zero-length
68 pub fn initMarker(id: Id) Token {68 pub fn initMarker(id: Id) Token {
69 return Token {69 return Token{
70 .id = id,70 .id = id,
71 .offset = 0,71 .offset = 0,
72 .string_has_escape = false,72 .string_has_escape = false,
...@@ -77,7 +77,7 @@ pub const Token = struct {...@@ -77,7 +77,7 @@ pub const Token = struct {
7777
78 // Slice into the underlying input string.78 // Slice into the underlying input string.
79 pub fn slice(self: &const Token, input: []const u8, i: usize) []const u8 {79 pub fn slice(self: &const Token, input: []const u8, i: usize) []const u8 {
80 return input[i + self.offset - self.count .. i + self.offset];80 return input[i + self.offset - self.count..i + self.offset];
81 }81 }
82};82};
8383
...@@ -86,7 +86,7 @@ pub const Token = struct {...@@ -86,7 +86,7 @@ pub const Token = struct {
86// parsing state requires ~40-50 bytes of stack space.86// parsing state requires ~40-50 bytes of stack space.
87//87//
88// Conforms strictly to RFC8529.88// Conforms strictly to RFC8529.
89const StreamingJsonParser = struct {89pub const StreamingJsonParser = struct {
90 // Current state90 // Current state
91 state: State,91 state: State,
92 // How many bytes we have counted for the current token92 // How many bytes we have counted for the current token
...@@ -105,8 +105,8 @@ const StreamingJsonParser = struct {...@@ -105,8 +105,8 @@ const StreamingJsonParser = struct {
105 stack: u256,105 stack: u256,
106 stack_used: u8,106 stack_used: u8,
107107
108 const object_bit = 0;108 const object_bit = 0;
109 const array_bit = 1;109 const array_bit = 1;
110 const max_stack_size = @maxValue(u8);110 const max_stack_size = @maxValue(u8);
111111
112 pub fn init() StreamingJsonParser {112 pub fn init() StreamingJsonParser {
...@@ -120,7 +120,7 @@ const StreamingJsonParser = struct {...@@ -120,7 +120,7 @@ const StreamingJsonParser = struct {
120 p.count = 0;120 p.count = 0;
121 // Set before ever read in main transition function121 // Set before ever read in main transition function
122 p.after_string_state = undefined;122 p.after_string_state = undefined;
123 p.after_value_state = State.ValueEnd; // handle end of values normally123 p.after_value_state = State.ValueEnd; // handle end of values normally
124 p.stack = 0;124 p.stack = 0;
125 p.stack_used = 0;125 p.stack_used = 0;
126 p.complete = false;126 p.complete = false;
...@@ -181,7 +181,7 @@ const StreamingJsonParser = struct {...@@ -181,7 +181,7 @@ const StreamingJsonParser = struct {
181 }181 }
182 };182 };
183183
184 pub const Error = error {184 pub const Error = error{
185 InvalidTopLevel,185 InvalidTopLevel,
186 TooManyNestedItems,186 TooManyNestedItems,
187 TooManyClosingItems,187 TooManyClosingItems,
...@@ -206,8 +206,8 @@ const StreamingJsonParser = struct {...@@ -206,8 +206,8 @@ const StreamingJsonParser = struct {
206 //206 //
207 // There is currently no error recovery on a bad stream.207 // There is currently no error recovery on a bad stream.
208 pub fn feed(p: &StreamingJsonParser, c: u8, token1: &?Token, token2: &?Token) Error!void {208 pub fn feed(p: &StreamingJsonParser, c: u8, token1: &?Token, token2: &?Token) Error!void {
209 *token1 = null;209 token1.* = null;
210 *token2 = null;210 token2.* = null;
211 p.count += 1;211 p.count += 1;
212212
213 // unlikely213 // unlikely
...@@ -228,7 +228,7 @@ const StreamingJsonParser = struct {...@@ -228,7 +228,7 @@ const StreamingJsonParser = struct {
228 p.state = State.ValueBegin;228 p.state = State.ValueBegin;
229 p.after_string_state = State.ObjectSeparator;229 p.after_string_state = State.ObjectSeparator;
230230
231 *token = Token.initMarker(Token.Id.ObjectBegin);231 token.* = Token.initMarker(Token.Id.ObjectBegin);
232 },232 },
233 '[' => {233 '[' => {
234 p.stack <<= 1;234 p.stack <<= 1;
...@@ -238,7 +238,7 @@ const StreamingJsonParser = struct {...@@ -238,7 +238,7 @@ const StreamingJsonParser = struct {
238 p.state = State.ValueBegin;238 p.state = State.ValueBegin;
239 p.after_string_state = State.ValueEnd;239 p.after_string_state = State.ValueEnd;
240240
241 *token = Token.initMarker(Token.Id.ArrayBegin);241 token.* = Token.initMarker(Token.Id.ArrayBegin);
242 },242 },
243 '-' => {243 '-' => {
244 p.number_is_integer = true;244 p.number_is_integer = true;
...@@ -281,7 +281,10 @@ const StreamingJsonParser = struct {...@@ -281,7 +281,10 @@ const StreamingJsonParser = struct {
281 p.after_value_state = State.TopLevelEnd;281 p.after_value_state = State.TopLevelEnd;
282 p.count = 0;282 p.count = 0;
283 },283 },
284 0x09, 0x0A, 0x0D, 0x20 => {284 0x09,
285 0x0A,
286 0x0D,
287 0x20 => {
285 // whitespace288 // whitespace
286 },289 },
287 else => {290 else => {
...@@ -290,7 +293,10 @@ const StreamingJsonParser = struct {...@@ -290,7 +293,10 @@ const StreamingJsonParser = struct {
290 },293 },
291294
292 State.TopLevelEnd => switch (c) {295 State.TopLevelEnd => switch (c) {
293 0x09, 0x0A, 0x0D, 0x20 => {296 0x09,
297 0x0A,
298 0x0D,
299 0x20 => {
294 // whitespace300 // whitespace
295 },301 },
296 else => {302 else => {
...@@ -324,7 +330,7 @@ const StreamingJsonParser = struct {...@@ -324,7 +330,7 @@ const StreamingJsonParser = struct {
324 else => {},330 else => {},
325 }331 }
326332
327 *token = Token.initMarker(Token.Id.ObjectEnd);333 token.* = Token.initMarker(Token.Id.ObjectEnd);
328 },334 },
329 ']' => {335 ']' => {
330 if (p.stack & 1 != array_bit) {336 if (p.stack & 1 != array_bit) {
...@@ -348,7 +354,7 @@ const StreamingJsonParser = struct {...@@ -348,7 +354,7 @@ const StreamingJsonParser = struct {
348 else => {},354 else => {},
349 }355 }
350356
351 *token = Token.initMarker(Token.Id.ArrayEnd);357 token.* = Token.initMarker(Token.Id.ArrayEnd);
352 },358 },
353 '{' => {359 '{' => {
354 if (p.stack_used == max_stack_size) {360 if (p.stack_used == max_stack_size) {
...@@ -362,7 +368,7 @@ const StreamingJsonParser = struct {...@@ -362,7 +368,7 @@ const StreamingJsonParser = struct {
362 p.state = State.ValueBegin;368 p.state = State.ValueBegin;
363 p.after_string_state = State.ObjectSeparator;369 p.after_string_state = State.ObjectSeparator;
364370
365 *token = Token.initMarker(Token.Id.ObjectBegin);371 token.* = Token.initMarker(Token.Id.ObjectBegin);
366 },372 },
367 '[' => {373 '[' => {
368 if (p.stack_used == max_stack_size) {374 if (p.stack_used == max_stack_size) {
...@@ -376,7 +382,7 @@ const StreamingJsonParser = struct {...@@ -376,7 +382,7 @@ const StreamingJsonParser = struct {
376 p.state = State.ValueBegin;382 p.state = State.ValueBegin;
377 p.after_string_state = State.ValueEnd;383 p.after_string_state = State.ValueEnd;
378384
379 *token = Token.initMarker(Token.Id.ArrayBegin);385 token.* = Token.initMarker(Token.Id.ArrayBegin);
380 },386 },
381 '-' => {387 '-' => {
382 p.state = State.Number;388 p.state = State.Number;
...@@ -406,7 +412,10 @@ const StreamingJsonParser = struct {...@@ -406,7 +412,10 @@ const StreamingJsonParser = struct {
406 p.state = State.NullLiteral1;412 p.state = State.NullLiteral1;
407 p.count = 0;413 p.count = 0;
408 },414 },
409 0x09, 0x0A, 0x0D, 0x20 => {415 0x09,
416 0x0A,
417 0x0D,
418 0x20 => {
410 // whitespace419 // whitespace
411 },420 },
412 else => {421 else => {
...@@ -428,7 +437,7 @@ const StreamingJsonParser = struct {...@@ -428,7 +437,7 @@ const StreamingJsonParser = struct {
428 p.state = State.ValueBegin;437 p.state = State.ValueBegin;
429 p.after_string_state = State.ObjectSeparator;438 p.after_string_state = State.ObjectSeparator;
430439
431 *token = Token.initMarker(Token.Id.ObjectBegin);440 token.* = Token.initMarker(Token.Id.ObjectBegin);
432 },441 },
433 '[' => {442 '[' => {
434 if (p.stack_used == max_stack_size) {443 if (p.stack_used == max_stack_size) {
...@@ -442,7 +451,7 @@ const StreamingJsonParser = struct {...@@ -442,7 +451,7 @@ const StreamingJsonParser = struct {
442 p.state = State.ValueBegin;451 p.state = State.ValueBegin;
443 p.after_string_state = State.ValueEnd;452 p.after_string_state = State.ValueEnd;
444453
445 *token = Token.initMarker(Token.Id.ArrayBegin);454 token.* = Token.initMarker(Token.Id.ArrayBegin);
446 },455 },
447 '-' => {456 '-' => {
448 p.state = State.Number;457 p.state = State.Number;
...@@ -472,7 +481,10 @@ const StreamingJsonParser = struct {...@@ -472,7 +481,10 @@ const StreamingJsonParser = struct {
472 p.state = State.NullLiteral1;481 p.state = State.NullLiteral1;
473 p.count = 0;482 p.count = 0;
474 },483 },
475 0x09, 0x0A, 0x0D, 0x20 => {484 0x09,
485 0x0A,
486 0x0D,
487 0x20 => {
476 // whitespace488 // whitespace
477 },489 },
478 else => {490 else => {
...@@ -501,7 +513,7 @@ const StreamingJsonParser = struct {...@@ -501,7 +513,7 @@ const StreamingJsonParser = struct {
501 p.state = State.TopLevelEnd;513 p.state = State.TopLevelEnd;
502 }514 }
503515
504 *token = Token.initMarker(Token.Id.ArrayEnd);516 token.* = Token.initMarker(Token.Id.ArrayEnd);
505 },517 },
506 '}' => {518 '}' => {
507 if (p.stack_used == 0) {519 if (p.stack_used == 0) {
...@@ -519,9 +531,12 @@ const StreamingJsonParser = struct {...@@ -519,9 +531,12 @@ const StreamingJsonParser = struct {
519 p.state = State.TopLevelEnd;531 p.state = State.TopLevelEnd;
520 }532 }
521533
522 *token = Token.initMarker(Token.Id.ObjectEnd);534 token.* = Token.initMarker(Token.Id.ObjectEnd);
523 },535 },
524 0x09, 0x0A, 0x0D, 0x20 => {536 0x09,
537 0x0A,
538 0x0D,
539 0x20 => {
525 // whitespace540 // whitespace
526 },541 },
527 else => {542 else => {
...@@ -534,7 +549,10 @@ const StreamingJsonParser = struct {...@@ -534,7 +549,10 @@ const StreamingJsonParser = struct {
534 p.state = State.ValueBegin;549 p.state = State.ValueBegin;
535 p.after_string_state = State.ValueEnd;550 p.after_string_state = State.ValueEnd;
536 },551 },
537 0x09, 0x0A, 0x0D, 0x20 => {552 0x09,
553 0x0A,
554 0x0D,
555 0x20 => {
538 // whitespace556 // whitespace
539 },557 },
540 else => {558 else => {
...@@ -553,12 +571,15 @@ const StreamingJsonParser = struct {...@@ -553,12 +571,15 @@ const StreamingJsonParser = struct {
553 p.complete = true;571 p.complete = true;
554 }572 }
555573
556 *token = Token.initString(p.count - 1, p.string_has_escape);574 token.* = Token.initString(p.count - 1, p.string_has_escape);
557 },575 },
558 '\\' => {576 '\\' => {
559 p.state = State.StringEscapeCharacter;577 p.state = State.StringEscapeCharacter;
560 },578 },
561 0x20, 0x21, 0x23 ... 0x5B, 0x5D ... 0x7F => {579 0x20,
580 0x21,
581 0x23 ... 0x5B,
582 0x5D ... 0x7F => {
562 // non-control ascii583 // non-control ascii
563 },584 },
564 0xC0 ... 0xDF => {585 0xC0 ... 0xDF => {
...@@ -599,7 +620,14 @@ const StreamingJsonParser = struct {...@@ -599,7 +620,14 @@ const StreamingJsonParser = struct {
599 // The current JSONTestSuite tests rely on both of this behaviour being present620 // The current JSONTestSuite tests rely on both of this behaviour being present
600 // however, so we default to the status quo where both are accepted until this621 // however, so we default to the status quo where both are accepted until this
601 // is further clarified.622 // is further clarified.
602 '"', '\\', '/', 'b', 'f', 'n', 'r', 't' => {623 '"',
624 '\\',
625 '/',
626 'b',
627 'f',
628 'n',
629 'r',
630 't' => {
603 p.string_has_escape = true;631 p.string_has_escape = true;
604 p.state = State.String;632 p.state = State.String;
605 },633 },
...@@ -613,28 +641,36 @@ const StreamingJsonParser = struct {...@@ -613,28 +641,36 @@ const StreamingJsonParser = struct {
613 },641 },
614642
615 State.StringEscapeHexUnicode4 => switch (c) {643 State.StringEscapeHexUnicode4 => switch (c) {
616 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {644 '0' ... '9',
645 'A' ... 'F',
646 'a' ... 'f' => {
617 p.state = State.StringEscapeHexUnicode3;647 p.state = State.StringEscapeHexUnicode3;
618 },648 },
619 else => return error.InvalidUnicodeHexSymbol,649 else => return error.InvalidUnicodeHexSymbol,
620 },650 },
621651
622 State.StringEscapeHexUnicode3 => switch (c) {652 State.StringEscapeHexUnicode3 => switch (c) {
623 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {653 '0' ... '9',
654 'A' ... 'F',
655 'a' ... 'f' => {
624 p.state = State.StringEscapeHexUnicode2;656 p.state = State.StringEscapeHexUnicode2;
625 },657 },
626 else => return error.InvalidUnicodeHexSymbol,658 else => return error.InvalidUnicodeHexSymbol,
627 },659 },
628660
629 State.StringEscapeHexUnicode2 => switch (c) {661 State.StringEscapeHexUnicode2 => switch (c) {
630 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {662 '0' ... '9',
663 'A' ... 'F',
664 'a' ... 'f' => {
631 p.state = State.StringEscapeHexUnicode1;665 p.state = State.StringEscapeHexUnicode1;
632 },666 },
633 else => return error.InvalidUnicodeHexSymbol,667 else => return error.InvalidUnicodeHexSymbol,
634 },668 },
635669
636 State.StringEscapeHexUnicode1 => switch (c) {670 State.StringEscapeHexUnicode1 => switch (c) {
637 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {671 '0' ... '9',
672 'A' ... 'F',
673 'a' ... 'f' => {
638 p.state = State.String;674 p.state = State.String;
639 },675 },
640 else => return error.InvalidUnicodeHexSymbol,676 else => return error.InvalidUnicodeHexSymbol,
...@@ -662,13 +698,14 @@ const StreamingJsonParser = struct {...@@ -662,13 +698,14 @@ const StreamingJsonParser = struct {
662 p.number_is_integer = false;698 p.number_is_integer = false;
663 p.state = State.NumberFractionalRequired;699 p.state = State.NumberFractionalRequired;
664 },700 },
665 'e', 'E' => {701 'e',
702 'E' => {
666 p.number_is_integer = false;703 p.number_is_integer = false;
667 p.state = State.NumberExponent;704 p.state = State.NumberExponent;
668 },705 },
669 else => {706 else => {
670 p.state = p.after_value_state;707 p.state = p.after_value_state;
671 *token = Token.initNumber(p.count, p.number_is_integer);708 token.* = Token.initNumber(p.count, p.number_is_integer);
672 return true;709 return true;
673 },710 },
674 }711 }
...@@ -681,7 +718,8 @@ const StreamingJsonParser = struct {...@@ -681,7 +718,8 @@ const StreamingJsonParser = struct {
681 p.number_is_integer = false;718 p.number_is_integer = false;
682 p.state = State.NumberFractionalRequired;719 p.state = State.NumberFractionalRequired;
683 },720 },
684 'e', 'E' => {721 'e',
722 'E' => {
685 p.number_is_integer = false;723 p.number_is_integer = false;
686 p.state = State.NumberExponent;724 p.state = State.NumberExponent;
687 },725 },
...@@ -690,7 +728,7 @@ const StreamingJsonParser = struct {...@@ -690,7 +728,7 @@ const StreamingJsonParser = struct {
690 },728 },
691 else => {729 else => {
692 p.state = p.after_value_state;730 p.state = p.after_value_state;
693 *token = Token.initNumber(p.count, p.number_is_integer);731 token.* = Token.initNumber(p.count, p.number_is_integer);
694 return true;732 return true;
695 },733 },
696 }734 }
...@@ -714,13 +752,14 @@ const StreamingJsonParser = struct {...@@ -714,13 +752,14 @@ const StreamingJsonParser = struct {
714 '0' ... '9' => {752 '0' ... '9' => {
715 // another digit753 // another digit
716 },754 },
717 'e', 'E' => {755 'e',
756 'E' => {
718 p.number_is_integer = false;757 p.number_is_integer = false;
719 p.state = State.NumberExponent;758 p.state = State.NumberExponent;
720 },759 },
721 else => {760 else => {
722 p.state = p.after_value_state;761 p.state = p.after_value_state;
723 *token = Token.initNumber(p.count, p.number_is_integer);762 token.* = Token.initNumber(p.count, p.number_is_integer);
724 return true;763 return true;
725 },764 },
726 }765 }
...@@ -729,20 +768,22 @@ const StreamingJsonParser = struct {...@@ -729,20 +768,22 @@ const StreamingJsonParser = struct {
729 State.NumberMaybeExponent => {768 State.NumberMaybeExponent => {
730 p.complete = p.after_value_state == State.TopLevelEnd;769 p.complete = p.after_value_state == State.TopLevelEnd;
731 switch (c) {770 switch (c) {
732 'e', 'E' => {771 'e',
772 'E' => {
733 p.number_is_integer = false;773 p.number_is_integer = false;
734 p.state = State.NumberExponent;774 p.state = State.NumberExponent;
735 },775 },
736 else => {776 else => {
737 p.state = p.after_value_state;777 p.state = p.after_value_state;
738 *token = Token.initNumber(p.count, p.number_is_integer);778 token.* = Token.initNumber(p.count, p.number_is_integer);
739 return true;779 return true;
740 },780 },
741 }781 }
742 },782 },
743783
744 State.NumberExponent => switch (c) {784 State.NumberExponent => switch (c) {
745 '-', '+', => {785 '-',
786 '+' => {
746 p.complete = false;787 p.complete = false;
747 p.state = State.NumberExponentDigitsRequired;788 p.state = State.NumberExponentDigitsRequired;
748 },789 },
...@@ -773,7 +814,7 @@ const StreamingJsonParser = struct {...@@ -773,7 +814,7 @@ const StreamingJsonParser = struct {
773 },814 },
774 else => {815 else => {
775 p.state = p.after_value_state;816 p.state = p.after_value_state;
776 *token = Token.initNumber(p.count, p.number_is_integer);817 token.* = Token.initNumber(p.count, p.number_is_integer);
777 return true;818 return true;
778 },819 },
779 }820 }
...@@ -793,7 +834,7 @@ const StreamingJsonParser = struct {...@@ -793,7 +834,7 @@ const StreamingJsonParser = struct {
793 'e' => {834 'e' => {
794 p.state = p.after_value_state;835 p.state = p.after_value_state;
795 p.complete = p.state == State.TopLevelEnd;836 p.complete = p.state == State.TopLevelEnd;
796 *token = Token.init(Token.Id.True, p.count + 1, 1);837 token.* = Token.init(Token.Id.True, p.count + 1, 1);
797 },838 },
798 else => {839 else => {
799 return error.InvalidLiteral;840 return error.InvalidLiteral;
...@@ -819,7 +860,7 @@ const StreamingJsonParser = struct {...@@ -819,7 +860,7 @@ const StreamingJsonParser = struct {
819 'e' => {860 'e' => {
820 p.state = p.after_value_state;861 p.state = p.after_value_state;
821 p.complete = p.state == State.TopLevelEnd;862 p.complete = p.state == State.TopLevelEnd;
822 *token = Token.init(Token.Id.False, p.count + 1, 1);863 token.* = Token.init(Token.Id.False, p.count + 1, 1);
823 },864 },
824 else => {865 else => {
825 return error.InvalidLiteral;866 return error.InvalidLiteral;
...@@ -840,7 +881,7 @@ const StreamingJsonParser = struct {...@@ -840,7 +881,7 @@ const StreamingJsonParser = struct {
840 'l' => {881 'l' => {
841 p.state = p.after_value_state;882 p.state = p.after_value_state;
842 p.complete = p.state == State.TopLevelEnd;883 p.complete = p.state == State.TopLevelEnd;
843 *token = Token.init(Token.Id.Null, p.count + 1, 1);884 token.* = Token.init(Token.Id.Null, p.count + 1, 1);
844 },885 },
845 else => {886 else => {
846 return error.InvalidLiteral;887 return error.InvalidLiteral;
...@@ -895,7 +936,7 @@ pub const Value = union(enum) {...@@ -895,7 +936,7 @@ pub const Value = union(enum) {
895 Object: ObjectMap,936 Object: ObjectMap,
896937
897 pub fn dump(self: &const Value) void {938 pub fn dump(self: &const Value) void {
898 switch (*self) {939 switch (self.*) {
899 Value.Null => {940 Value.Null => {
900 std.debug.warn("null");941 std.debug.warn("null");
901 },942 },
...@@ -950,7 +991,7 @@ pub const Value = union(enum) {...@@ -950,7 +991,7 @@ pub const Value = union(enum) {
950 }991 }
951992
952 fn dumpIndentLevel(self: &const Value, indent: usize, level: usize) void {993 fn dumpIndentLevel(self: &const Value, indent: usize, level: usize) void {
953 switch (*self) {994 switch (self.*) {
954 Value.Null => {995 Value.Null => {
955 std.debug.warn("null");996 std.debug.warn("null");
956 },997 },
...@@ -1012,7 +1053,7 @@ pub const Value = union(enum) {...@@ -1012,7 +1053,7 @@ pub const Value = union(enum) {
1012};1053};
10131054
1014// A non-stream JSON parser which constructs a tree of Value's.1055// A non-stream JSON parser which constructs a tree of Value's.
1015const JsonParser = struct {1056pub const JsonParser = struct {
1016 allocator: &Allocator,1057 allocator: &Allocator,
1017 state: State,1058 state: State,
1018 copy_strings: bool,1059 copy_strings: bool,
...@@ -1027,7 +1068,7 @@ const JsonParser = struct {...@@ -1027,7 +1068,7 @@ const JsonParser = struct {
1027 };1068 };
10281069
1029 pub fn init(allocator: &Allocator, copy_strings: bool) JsonParser {1070 pub fn init(allocator: &Allocator, copy_strings: bool) JsonParser {
1030 return JsonParser {1071 return JsonParser{
1031 .allocator = allocator,1072 .allocator = allocator,
1032 .state = State.Simple,1073 .state = State.Simple,
1033 .copy_strings = copy_strings,1074 .copy_strings = copy_strings,
...@@ -1082,7 +1123,7 @@ const JsonParser = struct {...@@ -1082,7 +1123,7 @@ const JsonParser = struct {
10821123
1083 std.debug.assert(p.stack.len == 1);1124 std.debug.assert(p.stack.len == 1);
10841125
1085 return ValueTree {1126 return ValueTree{
1086 .arena = arena,1127 .arena = arena,
1087 .root = p.stack.at(0),1128 .root = p.stack.at(0),
1088 };1129 };
...@@ -1115,11 +1156,11 @@ const JsonParser = struct {...@@ -1115,11 +1156,11 @@ const JsonParser = struct {
11151156
1116 switch (token.id) {1157 switch (token.id) {
1117 Token.Id.ObjectBegin => {1158 Token.Id.ObjectBegin => {
1118 try p.stack.append(Value { .Object = ObjectMap.init(allocator) });1159 try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
1119 p.state = State.ObjectKey;1160 p.state = State.ObjectKey;
1120 },1161 },
1121 Token.Id.ArrayBegin => {1162 Token.Id.ArrayBegin => {
1122 try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });1163 try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
1123 p.state = State.ArrayValue;1164 p.state = State.ArrayValue;
1124 },1165 },
1125 Token.Id.String => {1166 Token.Id.String => {
...@@ -1133,12 +1174,12 @@ const JsonParser = struct {...@@ -1133,12 +1174,12 @@ const JsonParser = struct {
1133 p.state = State.ObjectKey;1174 p.state = State.ObjectKey;
1134 },1175 },
1135 Token.Id.True => {1176 Token.Id.True => {
1136 _ = try object.put(key, Value { .Bool = true });1177 _ = try object.put(key, Value{ .Bool = true });
1137 _ = p.stack.pop();1178 _ = p.stack.pop();
1138 p.state = State.ObjectKey;1179 p.state = State.ObjectKey;
1139 },1180 },
1140 Token.Id.False => {1181 Token.Id.False => {
1141 _ = try object.put(key, Value { .Bool = false });1182 _ = try object.put(key, Value{ .Bool = false });
1142 _ = p.stack.pop();1183 _ = p.stack.pop();
1143 p.state = State.ObjectKey;1184 p.state = State.ObjectKey;
1144 },1185 },
...@@ -1165,11 +1206,11 @@ const JsonParser = struct {...@@ -1165,11 +1206,11 @@ const JsonParser = struct {
1165 try p.pushToParent(value);1206 try p.pushToParent(value);
1166 },1207 },
1167 Token.Id.ObjectBegin => {1208 Token.Id.ObjectBegin => {
1168 try p.stack.append(Value { .Object = ObjectMap.init(allocator) });1209 try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
1169 p.state = State.ObjectKey;1210 p.state = State.ObjectKey;
1170 },1211 },
1171 Token.Id.ArrayBegin => {1212 Token.Id.ArrayBegin => {
1172 try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });1213 try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
1173 p.state = State.ArrayValue;1214 p.state = State.ArrayValue;
1174 },1215 },
1175 Token.Id.String => {1216 Token.Id.String => {
...@@ -1179,10 +1220,10 @@ const JsonParser = struct {...@@ -1179,10 +1220,10 @@ const JsonParser = struct {
1179 try array.append(try p.parseNumber(token, input, i));1220 try array.append(try p.parseNumber(token, input, i));
1180 },1221 },
1181 Token.Id.True => {1222 Token.Id.True => {
1182 try array.append(Value { .Bool = true });1223 try array.append(Value{ .Bool = true });
1183 },1224 },
1184 Token.Id.False => {1225 Token.Id.False => {
1185 try array.append(Value { .Bool = false });1226 try array.append(Value{ .Bool = false });
1186 },1227 },
1187 Token.Id.Null => {1228 Token.Id.Null => {
1188 try array.append(Value.Null);1229 try array.append(Value.Null);
...@@ -1194,11 +1235,11 @@ const JsonParser = struct {...@@ -1194,11 +1235,11 @@ const JsonParser = struct {
1194 },1235 },
1195 State.Simple => switch (token.id) {1236 State.Simple => switch (token.id) {
1196 Token.Id.ObjectBegin => {1237 Token.Id.ObjectBegin => {
1197 try p.stack.append(Value { .Object = ObjectMap.init(allocator) });1238 try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
1198 p.state = State.ObjectKey;1239 p.state = State.ObjectKey;
1199 },1240 },
1200 Token.Id.ArrayBegin => {1241 Token.Id.ArrayBegin => {
1201 try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });1242 try p.stack.append(Value{ .Array = ArrayList(Value).init(allocator) });
1202 p.state = State.ArrayValue;1243 p.state = State.ArrayValue;
1203 },1244 },
1204 Token.Id.String => {1245 Token.Id.String => {
...@@ -1208,15 +1249,16 @@ const JsonParser = struct {...@@ -1208,15 +1249,16 @@ const JsonParser = struct {
1208 try p.stack.append(try p.parseNumber(token, input, i));1249 try p.stack.append(try p.parseNumber(token, input, i));
1209 },1250 },
1210 Token.Id.True => {1251 Token.Id.True => {
1211 try p.stack.append(Value { .Bool = true });1252 try p.stack.append(Value{ .Bool = true });
1212 },1253 },
1213 Token.Id.False => {1254 Token.Id.False => {
1214 try p.stack.append(Value { .Bool = false });1255 try p.stack.append(Value{ .Bool = false });
1215 },1256 },
1216 Token.Id.Null => {1257 Token.Id.Null => {
1217 try p.stack.append(Value.Null);1258 try p.stack.append(Value.Null);
1218 },1259 },
1219 Token.Id.ObjectEnd, Token.Id.ArrayEnd => {1260 Token.Id.ObjectEnd,
1261 Token.Id.ArrayEnd => {
1220 unreachable;1262 unreachable;
1221 },1263 },
1222 },1264 },
...@@ -1248,15 +1290,14 @@ const JsonParser = struct {...@@ -1248,15 +1290,14 @@ const JsonParser = struct {
1248 // TODO: We don't strictly have to copy values which do not contain any escape1290 // TODO: We don't strictly have to copy values which do not contain any escape
1249 // characters if flagged with the option.1291 // characters if flagged with the option.
1250 const slice = token.slice(input, i);1292 const slice = token.slice(input, i);
1251 return Value { .String = try mem.dupe(p.allocator, u8, slice) };1293 return Value{ .String = try mem.dupe(p.allocator, u8, slice) };
1252 }1294 }
12531295
1254 fn parseNumber(p: &JsonParser, token: &const Token, input: []const u8, i: usize) !Value {1296 fn parseNumber(p: &JsonParser, token: &const Token, input: []const u8, i: usize) !Value {
1255 return if (token.number_is_integer)1297 return if (token.number_is_integer)
1256 Value { .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }1298 Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
1257 else1299 else
1258 @panic("TODO: fmt.parseFloat not yet implemented")1300 @panic("TODO: fmt.parseFloat not yet implemented");
1259 ;
1260 }1301 }
1261};1302};
12621303
...@@ -1267,21 +1308,21 @@ test "json parser dynamic" {...@@ -1267,21 +1308,21 @@ test "json parser dynamic" {
1267 defer p.deinit();1308 defer p.deinit();
12681309
1269 const s =1310 const s =
1270 \\{1311 \\{
1271 \\ "Image": {1312 \\ "Image": {
1272 \\ "Width": 800,1313 \\ "Width": 800,
1273 \\ "Height": 600,1314 \\ "Height": 600,
1274 \\ "Title": "View from 15th Floor",1315 \\ "Title": "View from 15th Floor",
1275 \\ "Thumbnail": {1316 \\ "Thumbnail": {
1276 \\ "Url": "http://www.example.com/image/481989943",1317 \\ "Url": "http://www.example.com/image/481989943",
1277 \\ "Height": 125,1318 \\ "Height": 125,
1278 \\ "Width": 1001319 \\ "Width": 100
1279 \\ },1320 \\ },
1280 \\ "Animated" : false,1321 \\ "Animated" : false,
1281 \\ "IDs": [116, 943, 234, 38793]1322 \\ "IDs": [116, 943, 234, 38793]
1282 \\ }1323 \\ }
1283 \\}1324 \\}
1284 ;1325 ;
12851326
1286 var tree = try p.parse(s);1327 var tree = try p.parse(s);
1287 defer tree.deinit();1328 defer tree.deinit();
std/json_test.zig+15-45
...@@ -431,15 +431,11 @@ test "y_string_two-byte-utf-8" {...@@ -431,15 +431,11 @@ test "y_string_two-byte-utf-8" {
431}431}
432432
433test "y_string_u+2028_line_sep" {433test "y_string_u+2028_line_sep" {
434 ok(434 ok("[\"\xe2\x80\xa8\"]");
435 \\["
"]
436 );
437}435}
438436
439test "y_string_u+2029_par_sep" {437test "y_string_u+2029_par_sep" {
440 ok(438 ok("[\"\xe2\x80\xa9\"]");
441 \\["
"]
442 );
443}439}
444440
445test "y_string_uescaped_newline" {441test "y_string_uescaped_newline" {
...@@ -455,9 +451,7 @@ test "y_string_uEscape" {...@@ -455,9 +451,7 @@ test "y_string_uEscape" {
455}451}
456452
457test "y_string_unescaped_char_delete" {453test "y_string_unescaped_char_delete" {
458 ok(454 ok("[\"\x7f\"]");
459 \\[""]
460 );
461}455}
462456
463test "y_string_unicode_2" {457test "y_string_unicode_2" {
...@@ -527,9 +521,7 @@ test "y_string_utf8" {...@@ -527,9 +521,7 @@ test "y_string_utf8" {
527}521}
528522
529test "y_string_with_del_character" {523test "y_string_with_del_character" {
530 ok(524 ok("[\"a\x7fa\"]");
531 \\["aa"]
532 );
533}525}
534526
535test "y_structure_lonely_false" {527test "y_structure_lonely_false" {
...@@ -718,9 +710,7 @@ test "n_array_number_and_several_commas" {...@@ -718,9 +710,7 @@ test "n_array_number_and_several_commas" {
718}710}
719711
720test "n_array_spaces_vertical_tab_formfeed" {712test "n_array_spaces_vertical_tab_formfeed" {
721 err(713 err("[\"\x0aa\"\\f]");
722 \\[" a"\f]
723 );
724}714}
725715
726test "n_array_star_inside" {716test "n_array_star_inside" {
...@@ -774,9 +764,7 @@ test "n_incomplete_true" {...@@ -774,9 +764,7 @@ test "n_incomplete_true" {
774}764}
775765
776test "n_multidigit_number_then_00" {766test "n_multidigit_number_then_00" {
777 err(767 err("123\x00");
778 \\123
779 );
780}768}
781769
782test "n_number_0.1.2" {770test "n_number_0.1.2" {
...@@ -1309,9 +1297,7 @@ test "n_string_escaped_ctrl_char_tab" {...@@ -1309,9 +1297,7 @@ test "n_string_escaped_ctrl_char_tab" {
1309}1297}
13101298
1311test "n_string_escaped_emoji" {1299test "n_string_escaped_emoji" {
1312 err(1300 err("[\"\x5c\xc3\xb0\xc2\x9f\xc2\x8c\xc2\x80\"]");
1313 \\["\🌀"]
1314 );
1315}1301}
13161302
1317test "n_string_escape_x" {1303test "n_string_escape_x" {
...@@ -1357,9 +1343,7 @@ test "n_string_invalid_unicode_escape" {...@@ -1357,9 +1343,7 @@ test "n_string_invalid_unicode_escape" {
1357}1343}
13581344
1359test "n_string_invalid_utf8_after_escape" {1345test "n_string_invalid_utf8_after_escape" {
1360 err(1346 err("[\"\\\x75\xc3\xa5\"]");
1361 \\["\å"]
1362 );
1363}1347}
13641348
1365test "n_string_invalid-utf-8-in-escape" {1349test "n_string_invalid-utf-8-in-escape" {
...@@ -1405,9 +1389,7 @@ test "n_string_start_escape_unclosed" {...@@ -1405,9 +1389,7 @@ test "n_string_start_escape_unclosed" {
1405}1389}
14061390
1407test "n_string_unescaped_crtl_char" {1391test "n_string_unescaped_crtl_char" {
1408 err(1392 err("[\"a\x00a\"]");
1409 \\["aa"]
1410 );
1411}1393}
14121394
1413test "n_string_unescaped_newline" {1395test "n_string_unescaped_newline" {
...@@ -1418,9 +1400,7 @@ test "n_string_unescaped_newline" {...@@ -1418,9 +1400,7 @@ test "n_string_unescaped_newline" {
1418}1400}
14191401
1420test "n_string_unescaped_tab" {1402test "n_string_unescaped_tab" {
1421 err(1403 err("[\"\t\"]");
1422 \\[" "]
1423 );
1424}1404}
14251405
1426test "n_string_unicode_CapitalU" {1406test "n_string_unicode_CapitalU" {
...@@ -1532,9 +1512,7 @@ test "n_structure_no_data" {...@@ -1532,9 +1512,7 @@ test "n_structure_no_data" {
1532}1512}
15331513
1534test "n_structure_null-byte-outside-string" {1514test "n_structure_null-byte-outside-string" {
1535 err(1515 err("[\x00]");
1536 \\[]
1537 );
1538}1516}
15391517
1540test "n_structure_number_with_trailing_garbage" {1518test "n_structure_number_with_trailing_garbage" {
...@@ -1718,9 +1696,7 @@ test "n_structure_UTF8_BOM_no_data" {...@@ -1718,9 +1696,7 @@ test "n_structure_UTF8_BOM_no_data" {
1718}1696}
17191697
1720test "n_structure_whitespace_formfeed" {1698test "n_structure_whitespace_formfeed" {
1721 err(1699 err("[\x0c]");
1722 \\[ ]
1723 );
1724}1700}
17251701
1726test "n_structure_whitespace_U+2060_word_joiner" {1702test "n_structure_whitespace_U+2060_word_joiner" {
...@@ -1900,21 +1876,15 @@ test "i_string_truncated-utf-8" {...@@ -1900,21 +1876,15 @@ test "i_string_truncated-utf-8" {
1900}1876}
19011877
1902test "i_string_utf16BE_no_BOM" {1878test "i_string_utf16BE_no_BOM" {
1903 any(1879 any("\x00\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d");
1904 \\["é"]
1905 );
1906}1880}
19071881
1908test "i_string_utf16LE_no_BOM" {1882test "i_string_utf16LE_no_BOM" {
1909 any(1883 any("\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00");
1910 \\["é"]
1911 );
1912}1884}
19131885
1914test "i_string_UTF-16LE_with_BOM" {1886test "i_string_UTF-16LE_with_BOM" {
1915 any(1887 any("\xc3\xbf\xc3\xbe\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00");
1916 \\ÿþ["é"]
1917 );
1918}1888}
19191889
1920test "i_string_UTF-8_invalid_sequence" {1890test "i_string_UTF-8_invalid_sequence" {
std/linked_list.zig+55-40
...@@ -26,10 +26,10 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na...@@ -26,10 +26,10 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
26 data: T,26 data: T,
2727
28 pub fn init(value: &const T) Node {28 pub fn init(value: &const T) Node {
29 return Node {29 return Node{
30 .prev = null,30 .prev = null,
31 .next = null,31 .next = null,
32 .data = *value,32 .data = value.*,
33 };33 };
34 }34 }
3535
...@@ -45,18 +45,18 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na...@@ -45,18 +45,18 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
45 };45 };
4646
47 first: ?&Node,47 first: ?&Node,
48 last: ?&Node,48 last: ?&Node,
49 len: usize,49 len: usize,
5050
51 /// Initialize a linked list.51 /// Initialize a linked list.
52 ///52 ///
53 /// Returns:53 /// Returns:
54 /// An empty linked list.54 /// An empty linked list.
55 pub fn init() Self {55 pub fn init() Self {
56 return Self {56 return Self{
57 .first = null,57 .first = null,
58 .last = null,58 .last = null,
59 .len = 0,59 .len = 0,
60 };60 };
61 }61 }
6262
...@@ -131,7 +131,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na...@@ -131,7 +131,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
131 } else {131 } else {
132 // Empty list.132 // Empty list.
133 list.first = new_node;133 list.first = new_node;
134 list.last = new_node;134 list.last = new_node;
135 new_node.prev = null;135 new_node.prev = null;
136 new_node.next = null;136 new_node.next = null;
137137
...@@ -217,7 +217,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na...@@ -217,7 +217,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
217 pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) !&Node {217 pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) !&Node {
218 comptime assert(!isIntrusive());218 comptime assert(!isIntrusive());
219 var node = try list.allocateNode(allocator);219 var node = try list.allocateNode(allocator);
220 *node = Node.init(data);220 node.* = Node.init(data);
221 return node;221 return node;
222 }222 }
223 };223 };
...@@ -227,11 +227,11 @@ test "basic linked list test" {...@@ -227,11 +227,11 @@ test "basic linked list test" {
227 const allocator = debug.global_allocator;227 const allocator = debug.global_allocator;
228 var list = LinkedList(u32).init();228 var list = LinkedList(u32).init();
229229
230 var one = try list.createNode(1, allocator);230 var one = try list.createNode(1, allocator);
231 var two = try list.createNode(2, allocator);231 var two = try list.createNode(2, allocator);
232 var three = try list.createNode(3, allocator);232 var three = try list.createNode(3, allocator);
233 var four = try list.createNode(4, allocator);233 var four = try list.createNode(4, allocator);
234 var five = try list.createNode(5, allocator);234 var five = try list.createNode(5, allocator);
235 defer {235 defer {
236 list.destroyNode(one, allocator);236 list.destroyNode(one, allocator);
237 list.destroyNode(two, allocator);237 list.destroyNode(two, allocator);
...@@ -240,11 +240,11 @@ test "basic linked list test" {...@@ -240,11 +240,11 @@ test "basic linked list test" {
240 list.destroyNode(five, allocator);240 list.destroyNode(five, allocator);
241 }241 }
242242
243 list.append(two); // {2}243 list.append(two); // {2}
244 list.append(five); // {2, 5}244 list.append(five); // {2, 5}
245 list.prepend(one); // {1, 2, 5}245 list.prepend(one); // {1, 2, 5}
246 list.insertBefore(five, four); // {1, 2, 4, 5}246 list.insertBefore(five, four); // {1, 2, 4, 5}
247 list.insertAfter(two, three); // {1, 2, 3, 4, 5}247 list.insertAfter(two, three); // {1, 2, 3, 4, 5}
248248
249 // Traverse forwards.249 // Traverse forwards.
250 {250 {
...@@ -266,13 +266,13 @@ test "basic linked list test" {...@@ -266,13 +266,13 @@ test "basic linked list test" {
266 }266 }
267 }267 }
268268
269 var first = list.popFirst(); // {2, 3, 4, 5}269 var first = list.popFirst(); // {2, 3, 4, 5}
270 var last = list.pop(); // {2, 3, 4}270 var last = list.pop(); // {2, 3, 4}
271 list.remove(three); // {2, 4}271 list.remove(three); // {2, 4}
272272
273 assert ((??list.first).data == 2);273 assert((??list.first).data == 2);
274 assert ((??list.last ).data == 4);274 assert((??list.last).data == 4);
275 assert (list.len == 2);275 assert(list.len == 2);
276}276}
277277
278const ElementList = IntrusiveLinkedList(Element, "link");278const ElementList = IntrusiveLinkedList(Element, "link");
...@@ -285,17 +285,32 @@ test "basic intrusive linked list test" {...@@ -285,17 +285,32 @@ test "basic intrusive linked list test" {
285 const allocator = debug.global_allocator;285 const allocator = debug.global_allocator;
286 var list = ElementList.init();286 var list = ElementList.init();
287287
288 var one = Element { .value = 1, .link = ElementList.Node.initIntrusive() };288 var one = Element{
289 var two = Element { .value = 2, .link = ElementList.Node.initIntrusive() };289 .value = 1,
290 var three = Element { .value = 3, .link = ElementList.Node.initIntrusive() };290 .link = ElementList.Node.initIntrusive(),
291 var four = Element { .value = 4, .link = ElementList.Node.initIntrusive() };291 };
292 var five = Element { .value = 5, .link = ElementList.Node.initIntrusive() };292 var two = Element{
293 .value = 2,
294 .link = ElementList.Node.initIntrusive(),
295 };
296 var three = Element{
297 .value = 3,
298 .link = ElementList.Node.initIntrusive(),
299 };
300 var four = Element{
301 .value = 4,
302 .link = ElementList.Node.initIntrusive(),
303 };
304 var five = Element{
305 .value = 5,
306 .link = ElementList.Node.initIntrusive(),
307 };
293308
294 list.append(&two.link); // {2}309 list.append(&two.link); // {2}
295 list.append(&five.link); // {2, 5}310 list.append(&five.link); // {2, 5}
296 list.prepend(&one.link); // {1, 2, 5}311 list.prepend(&one.link); // {1, 2, 5}
297 list.insertBefore(&five.link, &four.link); // {1, 2, 4, 5}312 list.insertBefore(&five.link, &four.link); // {1, 2, 4, 5}
298 list.insertAfter(&two.link, &three.link); // {1, 2, 3, 4, 5}313 list.insertAfter(&two.link, &three.link); // {1, 2, 3, 4, 5}
299314
300 // Traverse forwards.315 // Traverse forwards.
301 {316 {
...@@ -317,11 +332,11 @@ test "basic intrusive linked list test" {...@@ -317,11 +332,11 @@ test "basic intrusive linked list test" {
317 }332 }
318 }333 }
319334
320 var first = list.popFirst(); // {2, 3, 4, 5}335 var first = list.popFirst(); // {2, 3, 4, 5}
321 var last = list.pop(); // {2, 3, 4}336 var last = list.pop(); // {2, 3, 4}
322 list.remove(&three.link); // {2, 4}337 list.remove(&three.link); // {2, 4}
323338
324 assert ((??list.first).toData().value == 2);339 assert((??list.first).toData().value == 2);
325 assert ((??list.last ).toData().value == 4);340 assert((??list.last).toData().value == 4);
326 assert (list.len == 2);341 assert(list.len == 2);
327}342}
std/math/acos.zig+7-7
...@@ -16,7 +16,7 @@ pub fn acos(x: var) @typeOf(x) {...@@ -16,7 +16,7 @@ pub fn acos(x: var) @typeOf(x) {
16}16}
1717
18fn r32(z: f32) f32 {18fn r32(z: f32) f32 {
19 const pS0 = 1.6666586697e-01;19 const pS0 = 1.6666586697e-01;
20 const pS1 = -4.2743422091e-02;20 const pS1 = -4.2743422091e-02;
21 const pS2 = -8.6563630030e-03;21 const pS2 = -8.6563630030e-03;
22 const qS1 = -7.0662963390e-01;22 const qS1 = -7.0662963390e-01;
...@@ -74,16 +74,16 @@ fn acos32(x: f32) f32 {...@@ -74,16 +74,16 @@ fn acos32(x: f32) f32 {
74}74}
7575
76fn r64(z: f64) f64 {76fn r64(z: f64) f64 {
77 const pS0: f64 = 1.66666666666666657415e-01;77 const pS0: f64 = 1.66666666666666657415e-01;
78 const pS1: f64 = -3.25565818622400915405e-01;78 const pS1: f64 = -3.25565818622400915405e-01;
79 const pS2: f64 = 2.01212532134862925881e-01;79 const pS2: f64 = 2.01212532134862925881e-01;
80 const pS3: f64 = -4.00555345006794114027e-02;80 const pS3: f64 = -4.00555345006794114027e-02;
81 const pS4: f64 = 7.91534994289814532176e-04;81 const pS4: f64 = 7.91534994289814532176e-04;
82 const pS5: f64 = 3.47933107596021167570e-05;82 const pS5: f64 = 3.47933107596021167570e-05;
83 const qS1: f64 = -2.40339491173441421878e+00;83 const qS1: f64 = -2.40339491173441421878e+00;
84 const qS2: f64 = 2.02094576023350569471e+00;84 const qS2: f64 = 2.02094576023350569471e+00;
85 const qS3: f64 = -6.88283971605453293030e-01;85 const qS3: f64 = -6.88283971605453293030e-01;
86 const qS4: f64 = 7.70381505559019352791e-02;86 const qS4: f64 = 7.70381505559019352791e-02;
8787
88 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));88 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
89 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));89 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
std/math/asin.zig+9-9
...@@ -17,7 +17,7 @@ pub fn asin(x: var) @typeOf(x) {...@@ -17,7 +17,7 @@ pub fn asin(x: var) @typeOf(x) {
17}17}
1818
19fn r32(z: f32) f32 {19fn r32(z: f32) f32 {
20 const pS0 = 1.6666586697e-01;20 const pS0 = 1.6666586697e-01;
21 const pS1 = -4.2743422091e-02;21 const pS1 = -4.2743422091e-02;
22 const pS2 = -8.6563630030e-03;22 const pS2 = -8.6563630030e-03;
23 const qS1 = -7.0662963390e-01;23 const qS1 = -7.0662963390e-01;
...@@ -37,9 +37,9 @@ fn asin32(x: f32) f32 {...@@ -37,9 +37,9 @@ fn asin32(x: f32) f32 {
37 if (ix >= 0x3F800000) {37 if (ix >= 0x3F800000) {
38 // |x| >= 138 // |x| >= 1
39 if (ix == 0x3F800000) {39 if (ix == 0x3F800000) {
40 return x * pio2 + 0x1.0p-120; // asin(+-1) = +-pi/2 with inexact40 return x * pio2 + 0x1.0p-120; // asin(+-1) = +-pi/2 with inexact
41 } else {41 } else {
42 return math.nan(f32); // asin(|x| > 1) is nan42 return math.nan(f32); // asin(|x| > 1) is nan
43 }43 }
44 }44 }
4545
...@@ -66,16 +66,16 @@ fn asin32(x: f32) f32 {...@@ -66,16 +66,16 @@ fn asin32(x: f32) f32 {
66}66}
6767
68fn r64(z: f64) f64 {68fn r64(z: f64) f64 {
69 const pS0: f64 = 1.66666666666666657415e-01;69 const pS0: f64 = 1.66666666666666657415e-01;
70 const pS1: f64 = -3.25565818622400915405e-01;70 const pS1: f64 = -3.25565818622400915405e-01;
71 const pS2: f64 = 2.01212532134862925881e-01;71 const pS2: f64 = 2.01212532134862925881e-01;
72 const pS3: f64 = -4.00555345006794114027e-02;72 const pS3: f64 = -4.00555345006794114027e-02;
73 const pS4: f64 = 7.91534994289814532176e-04;73 const pS4: f64 = 7.91534994289814532176e-04;
74 const pS5: f64 = 3.47933107596021167570e-05;74 const pS5: f64 = 3.47933107596021167570e-05;
75 const qS1: f64 = -2.40339491173441421878e+00;75 const qS1: f64 = -2.40339491173441421878e+00;
76 const qS2: f64 = 2.02094576023350569471e+00;76 const qS2: f64 = 2.02094576023350569471e+00;
77 const qS3: f64 = -6.88283971605453293030e-01;77 const qS3: f64 = -6.88283971605453293030e-01;
78 const qS4: f64 = 7.70381505559019352791e-02;78 const qS4: f64 = 7.70381505559019352791e-02;
7979
80 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));80 const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
81 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));81 const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
std/math/atan2.zig+34-32
...@@ -31,7 +31,7 @@ pub fn atan2(comptime T: type, x: T, y: T) T {...@@ -31,7 +31,7 @@ pub fn atan2(comptime T: type, x: T, y: T) T {
31}31}
3232
33fn atan2_32(y: f32, x: f32) f32 {33fn atan2_32(y: f32, x: f32) f32 {
34 const pi: f32 = 3.1415927410e+00;34 const pi: f32 = 3.1415927410e+00;
35 const pi_lo: f32 = -8.7422776573e-08;35 const pi_lo: f32 = -8.7422776573e-08;
3636
37 if (math.isNan(x) or math.isNan(y)) {37 if (math.isNan(x) or math.isNan(y)) {
...@@ -53,9 +53,10 @@ fn atan2_32(y: f32, x: f32) f32 {...@@ -53,9 +53,10 @@ fn atan2_32(y: f32, x: f32) f32 {
5353
54 if (iy == 0) {54 if (iy == 0) {
55 switch (m) {55 switch (m) {
56 0, 1 => return y, // atan(+-0, +...)56 0,
57 2 => return pi, // atan(+0, -...)57 1 => return y, // atan(+-0, +...)
58 3 => return -pi, // atan(-0, -...)58 2 => return pi, // atan(+0, -...)
59 3 => return -pi, // atan(-0, -...)
59 else => unreachable,60 else => unreachable,
60 }61 }
61 }62 }
...@@ -71,18 +72,18 @@ fn atan2_32(y: f32, x: f32) f32 {...@@ -71,18 +72,18 @@ fn atan2_32(y: f32, x: f32) f32 {
71 if (ix == 0x7F800000) {72 if (ix == 0x7F800000) {
72 if (iy == 0x7F800000) {73 if (iy == 0x7F800000) {
73 switch (m) {74 switch (m) {
74 0 => return pi / 4, // atan(+inf, +inf)75 0 => return pi / 4, // atan(+inf, +inf)
75 1 => return -pi / 4, // atan(-inf, +inf)76 1 => return -pi / 4, // atan(-inf, +inf)
76 2 => return 3*pi / 4, // atan(+inf, -inf)77 2 => return 3 * pi / 4, // atan(+inf, -inf)
77 3 => return -3*pi / 4, // atan(-inf, -inf)78 3 => return -3 * pi / 4, // atan(-inf, -inf)
78 else => unreachable,79 else => unreachable,
79 }80 }
80 } else {81 } else {
81 switch (m) {82 switch (m) {
82 0 => return 0.0, // atan(+..., +inf)83 0 => return 0.0, // atan(+..., +inf)
83 1 => return -0.0, // atan(-..., +inf)84 1 => return -0.0, // atan(-..., +inf)
84 2 => return pi, // atan(+..., -inf)85 2 => return pi, // atan(+..., -inf)
85 3 => return -pi, // atan(-...f, -inf)86 3 => return -pi, // atan(-...f, -inf)
86 else => unreachable,87 else => unreachable,
87 }88 }
88 }89 }
...@@ -107,16 +108,16 @@ fn atan2_32(y: f32, x: f32) f32 {...@@ -107,16 +108,16 @@ fn atan2_32(y: f32, x: f32) f32 {
107 };108 };
108109
109 switch (m) {110 switch (m) {
110 0 => return z, // atan(+, +)111 0 => return z, // atan(+, +)
111 1 => return -z, // atan(-, +)112 1 => return -z, // atan(-, +)
112 2 => return pi - (z - pi_lo), // atan(+, -)113 2 => return pi - (z - pi_lo), // atan(+, -)
113 3 => return (z - pi_lo) - pi, // atan(-, -)114 3 => return (z - pi_lo) - pi, // atan(-, -)
114 else => unreachable,115 else => unreachable,
115 }116 }
116}117}
117118
118fn atan2_64(y: f64, x: f64) f64 {119fn atan2_64(y: f64, x: f64) f64 {
119 const pi: f64 = 3.1415926535897931160E+00;120 const pi: f64 = 3.1415926535897931160E+00;
120 const pi_lo: f64 = 1.2246467991473531772E-16;121 const pi_lo: f64 = 1.2246467991473531772E-16;
121122
122 if (math.isNan(x) or math.isNan(y)) {123 if (math.isNan(x) or math.isNan(y)) {
...@@ -143,9 +144,10 @@ fn atan2_64(y: f64, x: f64) f64 {...@@ -143,9 +144,10 @@ fn atan2_64(y: f64, x: f64) f64 {
143144
144 if (iy | ly == 0) {145 if (iy | ly == 0) {
145 switch (m) {146 switch (m) {
146 0, 1 => return y, // atan(+-0, +...)147 0,
147 2 => return pi, // atan(+0, -...)148 1 => return y, // atan(+-0, +...)
148 3 => return -pi, // atan(-0, -...)149 2 => return pi, // atan(+0, -...)
150 3 => return -pi, // atan(-0, -...)
149 else => unreachable,151 else => unreachable,
150 }152 }
151 }153 }
...@@ -161,18 +163,18 @@ fn atan2_64(y: f64, x: f64) f64 {...@@ -161,18 +163,18 @@ fn atan2_64(y: f64, x: f64) f64 {
161 if (ix == 0x7FF00000) {163 if (ix == 0x7FF00000) {
162 if (iy == 0x7FF00000) {164 if (iy == 0x7FF00000) {
163 switch (m) {165 switch (m) {
164 0 => return pi / 4, // atan(+inf, +inf)166 0 => return pi / 4, // atan(+inf, +inf)
165 1 => return -pi / 4, // atan(-inf, +inf)167 1 => return -pi / 4, // atan(-inf, +inf)
166 2 => return 3*pi / 4, // atan(+inf, -inf)168 2 => return 3 * pi / 4, // atan(+inf, -inf)
167 3 => return -3*pi / 4, // atan(-inf, -inf)169 3 => return -3 * pi / 4, // atan(-inf, -inf)
168 else => unreachable,170 else => unreachable,
169 }171 }
170 } else {172 } else {
171 switch (m) {173 switch (m) {
172 0 => return 0.0, // atan(+..., +inf)174 0 => return 0.0, // atan(+..., +inf)
173 1 => return -0.0, // atan(-..., +inf)175 1 => return -0.0, // atan(-..., +inf)
174 2 => return pi, // atan(+..., -inf)176 2 => return pi, // atan(+..., -inf)
175 3 => return -pi, // atan(-...f, -inf)177 3 => return -pi, // atan(-...f, -inf)
176 else => unreachable,178 else => unreachable,
177 }179 }
178 }180 }
...@@ -197,10 +199,10 @@ fn atan2_64(y: f64, x: f64) f64 {...@@ -197,10 +199,10 @@ fn atan2_64(y: f64, x: f64) f64 {
197 };199 };
198200
199 switch (m) {201 switch (m) {
200 0 => return z, // atan(+, +)202 0 => return z, // atan(+, +)
201 1 => return -z, // atan(-, +)203 1 => return -z, // atan(-, +)
202 2 => return pi - (z - pi_lo), // atan(+, -)204 2 => return pi - (z - pi_lo), // atan(+, -)
203 3 => return (z - pi_lo) - pi, // atan(-, -)205 3 => return (z - pi_lo) - pi, // atan(-, -)
204 else => unreachable,206 else => unreachable,
205 }207 }
206}208}
std/math/cbrt.zig+5-5
...@@ -58,15 +58,15 @@ fn cbrt32(x: f32) f32 {...@@ -58,15 +58,15 @@ fn cbrt32(x: f32) f32 {
58}58}
5959
60fn cbrt64(x: f64) f64 {60fn cbrt64(x: f64) f64 {
61 const B1: u32 = 715094163; // (1023 - 1023 / 3 - 0.03306235651 * 2^2061 const B1: u32 = 715094163; // (1023 - 1023 / 3 - 0.03306235651 * 2^20
62 const B2: u32 = 696219795; // (1023 - 1023 / 3 - 54 / 3 - 0.03306235651 * 2^2062 const B2: u32 = 696219795; // (1023 - 1023 / 3 - 54 / 3 - 0.03306235651 * 2^20
6363
64 // |1 / cbrt(x) - p(x)| < 2^(23.5)64 // |1 / cbrt(x) - p(x)| < 2^(23.5)
65 const P0: f64 = 1.87595182427177009643;65 const P0: f64 = 1.87595182427177009643;
66 const P1: f64 = -1.88497979543377169875;66 const P1: f64 = -1.88497979543377169875;
67 const P2: f64 = 1.621429720105354466140;67 const P2: f64 = 1.621429720105354466140;
68 const P3: f64 = -0.758397934778766047437;68 const P3: f64 = -0.758397934778766047437;
69 const P4: f64 = 0.145996192886612446982;69 const P4: f64 = 0.145996192886612446982;
7070
71 var u = @bitCast(u64, x);71 var u = @bitCast(u64, x);
72 var hx = u32(u >> 32) & 0x7FFFFFFF;72 var hx = u32(u >> 32) & 0x7FFFFFFF;
std/math/ceil.zig+2-2
...@@ -56,7 +56,7 @@ fn ceil64(x: f64) f64 {...@@ -56,7 +56,7 @@ fn ceil64(x: f64) f64 {
56 const e = (u >> 52) & 0x7FF;56 const e = (u >> 52) & 0x7FF;
57 var y: f64 = undefined;57 var y: f64 = undefined;
5858
59 if (e >= 0x3FF+52 or x == 0) {59 if (e >= 0x3FF + 52 or x == 0) {
60 return x;60 return x;
61 }61 }
6262
...@@ -68,7 +68,7 @@ fn ceil64(x: f64) f64 {...@@ -68,7 +68,7 @@ fn ceil64(x: f64) f64 {
68 y = x + math.f64_toint - math.f64_toint - x;68 y = x + math.f64_toint - math.f64_toint - x;
69 }69 }
7070
71 if (e <= 0x3FF-1) {71 if (e <= 0x3FF - 1) {
72 math.forceEval(y);72 math.forceEval(y);
73 if (u >> 63 != 0) {73 if (u >> 63 != 0) {
74 return -0.0;74 return -0.0;
std/math/complex/exp.zig+11-17
...@@ -19,8 +19,8 @@ pub fn exp(z: var) Complex(@typeOf(z.re)) {...@@ -19,8 +19,8 @@ pub fn exp(z: var) Complex(@typeOf(z.re)) {
19fn exp32(z: &const Complex(f32)) Complex(f32) {19fn exp32(z: &const Complex(f32)) Complex(f32) {
20 @setFloatMode(this, @import("builtin").FloatMode.Strict);20 @setFloatMode(this, @import("builtin").FloatMode.Strict);
2121
22 const exp_overflow = 0x42b17218; // max_exp * ln2 ~= 88.7228395522 const exp_overflow = 0x42b17218; // max_exp * ln2 ~= 88.72283955
23 const cexp_overflow = 0x43400074; // (max_exp - min_denom_exp) * ln223 const cexp_overflow = 0x43400074; // (max_exp - min_denom_exp) * ln2
2424
25 const x = z.re;25 const x = z.re;
26 const y = z.im;26 const y = z.im;
...@@ -41,12 +41,10 @@ fn exp32(z: &const Complex(f32)) Complex(f32) {...@@ -41,12 +41,10 @@ fn exp32(z: &const Complex(f32)) Complex(f32) {
41 // cexp(finite|nan +- i inf|nan) = nan + i nan41 // cexp(finite|nan +- i inf|nan) = nan + i nan
42 if ((hx & 0x7fffffff) != 0x7f800000) {42 if ((hx & 0x7fffffff) != 0x7f800000) {
43 return Complex(f32).new(y - y, y - y);43 return Complex(f32).new(y - y, y - y);
44 }44 } // cexp(-inf +- i inf|nan) = 0 + i0
45 // cexp(-inf +- i inf|nan) = 0 + i0
46 else if (hx & 0x80000000 != 0) {45 else if (hx & 0x80000000 != 0) {
47 return Complex(f32).new(0, 0);46 return Complex(f32).new(0, 0);
48 }47 } // cexp(+inf +- i inf|nan) = inf + i nan
49 // cexp(+inf +- i inf|nan) = inf + i nan
50 else {48 else {
51 return Complex(f32).new(x, y - y);49 return Complex(f32).new(x, y - y);
52 }50 }
...@@ -55,8 +53,7 @@ fn exp32(z: &const Complex(f32)) Complex(f32) {...@@ -55,8 +53,7 @@ fn exp32(z: &const Complex(f32)) Complex(f32) {
55 // 88.7 <= x <= 192 so must scale53 // 88.7 <= x <= 192 so must scale
56 if (hx >= exp_overflow and hx <= cexp_overflow) {54 if (hx >= exp_overflow and hx <= cexp_overflow) {
57 return ldexp_cexp(z, 0);55 return ldexp_cexp(z, 0);
58 }56 } // - x < exp_overflow => exp(x) won't overflow (common)
59 // - x < exp_overflow => exp(x) won't overflow (common)
60 // - x > cexp_overflow, so exp(x) * s overflows for s > 057 // - x > cexp_overflow, so exp(x) * s overflows for s > 0
61 // - x = +-inf58 // - x = +-inf
62 // - x = nan59 // - x = nan
...@@ -67,8 +64,8 @@ fn exp32(z: &const Complex(f32)) Complex(f32) {...@@ -67,8 +64,8 @@ fn exp32(z: &const Complex(f32)) Complex(f32) {
67}64}
6865
69fn exp64(z: &const Complex(f64)) Complex(f64) {66fn exp64(z: &const Complex(f64)) Complex(f64) {
70 const exp_overflow = 0x40862e42; // high bits of max_exp * ln2 ~= 71067 const exp_overflow = 0x40862e42; // high bits of max_exp * ln2 ~= 710
71 const cexp_overflow = 0x4096b8e4; // (max_exp - min_denorm_exp) * ln268 const cexp_overflow = 0x4096b8e4; // (max_exp - min_denorm_exp) * ln2
7269
73 const x = z.re;70 const x = z.re;
74 const y = z.im;71 const y = z.im;
...@@ -95,12 +92,10 @@ fn exp64(z: &const Complex(f64)) Complex(f64) {...@@ -95,12 +92,10 @@ fn exp64(z: &const Complex(f64)) Complex(f64) {
95 // cexp(finite|nan +- i inf|nan) = nan + i nan92 // cexp(finite|nan +- i inf|nan) = nan + i nan
96 if (lx != 0 or (hx & 0x7fffffff) != 0x7ff00000) {93 if (lx != 0 or (hx & 0x7fffffff) != 0x7ff00000) {
97 return Complex(f64).new(y - y, y - y);94 return Complex(f64).new(y - y, y - y);
98 }95 } // cexp(-inf +- i inf|nan) = 0 + i0
99 // cexp(-inf +- i inf|nan) = 0 + i0
100 else if (hx & 0x80000000 != 0) {96 else if (hx & 0x80000000 != 0) {
101 return Complex(f64).new(0, 0);97 return Complex(f64).new(0, 0);
102 }98 } // cexp(+inf +- i inf|nan) = inf + i nan
103 // cexp(+inf +- i inf|nan) = inf + i nan
104 else {99 else {
105 return Complex(f64).new(x, y - y);100 return Complex(f64).new(x, y - y);
106 }101 }
...@@ -109,9 +104,8 @@ fn exp64(z: &const Complex(f64)) Complex(f64) {...@@ -109,9 +104,8 @@ fn exp64(z: &const Complex(f64)) Complex(f64) {
109 // 709.7 <= x <= 1454.3 so must scale104 // 709.7 <= x <= 1454.3 so must scale
110 if (hx >= exp_overflow and hx <= cexp_overflow) {105 if (hx >= exp_overflow and hx <= cexp_overflow) {
111 const r = ldexp_cexp(z, 0);106 const r = ldexp_cexp(z, 0);
112 return *r;107 return r.*;
113 }108 } // - x < exp_overflow => exp(x) won't overflow (common)
114 // - x < exp_overflow => exp(x) won't overflow (common)
115 // - x > cexp_overflow, so exp(x) * s overflows for s > 0109 // - x > cexp_overflow, so exp(x) * s overflows for s > 0
116 // - x = +-inf110 // - x = +-inf
117 // - x = nan111 // - x = nan
std/math/complex/ldexp.zig+7-10
...@@ -15,12 +15,12 @@ pub fn ldexp_cexp(z: var, expt: i32) Complex(@typeOf(z.re)) {...@@ -15,12 +15,12 @@ pub fn ldexp_cexp(z: var, expt: i32) Complex(@typeOf(z.re)) {
15}15}
1616
17fn frexp_exp32(x: f32, expt: &i32) f32 {17fn frexp_exp32(x: f32, expt: &i32) f32 {
18 const k = 235; // reduction constant18 const k = 235; // reduction constant
19 const kln2 = 162.88958740; // k * ln219 const kln2 = 162.88958740; // k * ln2
2020
21 const exp_x = math.exp(x - kln2);21 const exp_x = math.exp(x - kln2);
22 const hx = @bitCast(u32, exp_x);22 const hx = @bitCast(u32, exp_x);
23 *expt = i32(hx >> 23) - (0x7f + 127) + k;23 expt.* = i32(hx >> 23) - (0x7f + 127) + k;
24 return @bitCast(f32, (hx & 0x7fffff) | ((0x7f + 127) << 23));24 return @bitCast(f32, (hx & 0x7fffff) | ((0x7f + 127) << 23));
25}25}
2626
...@@ -35,15 +35,12 @@ fn ldexp_cexp32(z: &const Complex(f32), expt: i32) Complex(f32) {...@@ -35,15 +35,12 @@ fn ldexp_cexp32(z: &const Complex(f32), expt: i32) Complex(f32) {
35 const half_expt2 = exptf - half_expt1;35 const half_expt2 = exptf - half_expt1;
36 const scale2 = @bitCast(f32, (0x7f + half_expt2) << 23);36 const scale2 = @bitCast(f32, (0x7f + half_expt2) << 23);
3737
38 return Complex(f32).new(38 return Complex(f32).new(math.cos(z.im) * exp_x * scale1 * scale2, math.sin(z.im) * exp_x * scale1 * scale2);
39 math.cos(z.im) * exp_x * scale1 * scale2,
40 math.sin(z.im) * exp_x * scale1 * scale2,
41 );
42}39}
4340
44fn frexp_exp64(x: f64, expt: &i32) f64 {41fn frexp_exp64(x: f64, expt: &i32) f64 {
45 const k = 1799; // reduction constant42 const k = 1799; // reduction constant
46 const kln2 = 1246.97177782734161156; // k * ln243 const kln2 = 1246.97177782734161156; // k * ln2
4744
48 const exp_x = math.exp(x - kln2);45 const exp_x = math.exp(x - kln2);
4946
...@@ -51,7 +48,7 @@ fn frexp_exp64(x: f64, expt: &i32) f64 {...@@ -51,7 +48,7 @@ fn frexp_exp64(x: f64, expt: &i32) f64 {
51 const hx = u32(fx >> 32);48 const hx = u32(fx >> 32);
52 const lx = @truncate(u32, fx);49 const lx = @truncate(u32, fx);
5350
54 *expt = i32(hx >> 20) - (0x3ff + 1023) + k;51 expt.* = i32(hx >> 20) - (0x3ff + 1023) + k;
5552
56 const high_word = (hx & 0xfffff) | ((0x3ff + 1023) << 20);53 const high_word = (hx & 0xfffff) | ((0x3ff + 1023) << 20);
57 return @bitCast(f64, (u64(high_word) << 32) | lx);54 return @bitCast(f64, (u64(high_word) << 32) | lx);
std/math/cos.zig+6-6
...@@ -18,20 +18,20 @@ pub fn cos(x: var) @typeOf(x) {...@@ -18,20 +18,20 @@ pub fn cos(x: var) @typeOf(x) {
18}18}
1919
20// sin polynomial coefficients20// sin polynomial coefficients
21const S0 = 1.58962301576546568060E-10;21const S0 = 1.58962301576546568060E-10;
22const S1 = -2.50507477628578072866E-8;22const S1 = -2.50507477628578072866E-8;
23const S2 = 2.75573136213857245213E-6;23const S2 = 2.75573136213857245213E-6;
24const S3 = -1.98412698295895385996E-4;24const S3 = -1.98412698295895385996E-4;
25const S4 = 8.33333333332211858878E-3;25const S4 = 8.33333333332211858878E-3;
26const S5 = -1.66666666666666307295E-1;26const S5 = -1.66666666666666307295E-1;
2727
28// cos polynomial coeffiecients28// cos polynomial coeffiecients
29const C0 = -1.13585365213876817300E-11;29const C0 = -1.13585365213876817300E-11;
30const C1 = 2.08757008419747316778E-9;30const C1 = 2.08757008419747316778E-9;
31const C2 = -2.75573141792967388112E-7;31const C2 = -2.75573141792967388112E-7;
32const C3 = 2.48015872888517045348E-5;32const C3 = 2.48015872888517045348E-5;
33const C4 = -1.38888888888730564116E-3;33const C4 = -1.38888888888730564116E-3;
34const C5 = 4.16666666666665929218E-2;34const C5 = 4.16666666666665929218E-2;
3535
36// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.36// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.
37//37//
std/math/floor.zig+2-2
...@@ -57,7 +57,7 @@ fn floor64(x: f64) f64 {...@@ -57,7 +57,7 @@ fn floor64(x: f64) f64 {
57 const e = (u >> 52) & 0x7FF;57 const e = (u >> 52) & 0x7FF;
58 var y: f64 = undefined;58 var y: f64 = undefined;
5959
60 if (e >= 0x3FF+52 or x == 0) {60 if (e >= 0x3FF + 52 or x == 0) {
61 return x;61 return x;
62 }62 }
6363
...@@ -69,7 +69,7 @@ fn floor64(x: f64) f64 {...@@ -69,7 +69,7 @@ fn floor64(x: f64) f64 {
69 y = x + math.f64_toint - math.f64_toint - x;69 y = x + math.f64_toint - math.f64_toint - x;
70 }70 }
7171
72 if (e <= 0x3FF-1) {72 if (e <= 0x3FF - 1) {
73 math.forceEval(y);73 math.forceEval(y);
74 if (u >> 63 != 0) {74 if (u >> 63 != 0) {
75 return -1.0;75 return -1.0;
std/math/fma.zig+5-2
...@@ -5,7 +5,7 @@ const assert = std.debug.assert;...@@ -5,7 +5,7 @@ const assert = std.debug.assert;
5pub fn fma(comptime T: type, x: T, y: T, z: T) T {5pub fn fma(comptime T: type, x: T, y: T, z: T) T {
6 return switch (T) {6 return switch (T) {
7 f32 => fma32(x, y, z),7 f32 => fma32(x, y, z),
8 f64 => fma64(x, y ,z),8 f64 => fma64(x, y, z),
9 else => @compileError("fma not implemented for " ++ @typeName(T)),9 else => @compileError("fma not implemented for " ++ @typeName(T)),
10 };10 };
11}11}
...@@ -71,7 +71,10 @@ fn fma64(x: f64, y: f64, z: f64) f64 {...@@ -71,7 +71,10 @@ fn fma64(x: f64, y: f64, z: f64) f64 {
71 }71 }
72}72}
7373
74const dd = struct { hi: f64, lo: f64, };74const dd = struct {
75 hi: f64,
76 lo: f64,
77};
7578
76fn dd_add(a: f64, b: f64) dd {79fn dd_add(a: f64, b: f64) dd {
77 var ret: dd = undefined;80 var ret: dd = undefined;
std/math/hypot.zig+4-4
...@@ -39,11 +39,11 @@ fn hypot32(x: f32, y: f32) f32 {...@@ -39,11 +39,11 @@ fn hypot32(x: f32, y: f32) f32 {
39 }39 }
4040
41 var z: f32 = 1.0;41 var z: f32 = 1.0;
42 if (ux >= (0x7F+60) << 23) {42 if (ux >= (0x7F + 60) << 23) {
43 z = 0x1.0p90;43 z = 0x1.0p90;
44 xx *= 0x1.0p-90;44 xx *= 0x1.0p-90;
45 yy *= 0x1.0p-90;45 yy *= 0x1.0p-90;
46 } else if (uy < (0x7F-60) << 23) {46 } else if (uy < (0x7F - 60) << 23) {
47 z = 0x1.0p-90;47 z = 0x1.0p-90;
48 xx *= 0x1.0p-90;48 xx *= 0x1.0p-90;
49 yy *= 0x1.0p-90;49 yy *= 0x1.0p-90;
...@@ -57,8 +57,8 @@ fn sq(hi: &f64, lo: &f64, x: f64) void {...@@ -57,8 +57,8 @@ fn sq(hi: &f64, lo: &f64, x: f64) void {
57 const xc = x * split;57 const xc = x * split;
58 const xh = x - xc + xc;58 const xh = x - xc + xc;
59 const xl = x - xh;59 const xl = x - xh;
60 *hi = x * x;60 hi.* = x * x;
61 *lo = xh * xh - *hi + 2 * xh * xl + xl * xl;61 lo.* = xh * xh - hi.* + 2 * xh * xl + xl * xl;
62}62}
6363
64fn hypot64(x: f64, y: f64) f64 {64fn hypot64(x: f64, y: f64) f64 {
std/math/index.zig+29-46
...@@ -47,12 +47,12 @@ pub fn forceEval(value: var) void {...@@ -47,12 +47,12 @@ pub fn forceEval(value: var) void {
47 f32 => {47 f32 => {
48 var x: f32 = undefined;48 var x: f32 = undefined;
49 const p = @ptrCast(&volatile f32, &x);49 const p = @ptrCast(&volatile f32, &x);
50 *p = x;50 p.* = x;
51 },51 },
52 f64 => {52 f64 => {
53 var x: f64 = undefined;53 var x: f64 = undefined;
54 const p = @ptrCast(&volatile f64, &x);54 const p = @ptrCast(&volatile f64, &x);
55 *p = x;55 p.* = x;
56 },56 },
57 else => {57 else => {
58 @compileError("forceEval not implemented for " ++ @typeName(T));58 @compileError("forceEval not implemented for " ++ @typeName(T));
...@@ -179,7 +179,6 @@ test "math" {...@@ -179,7 +179,6 @@ test "math" {
179 _ = @import("complex/index.zig");179 _ = @import("complex/index.zig");
180}180}
181181
182
183pub fn min(x: var, y: var) @typeOf(x + y) {182pub fn min(x: var, y: var) @typeOf(x + y) {
184 return if (x < y) x else y;183 return if (x < y) x else y;
185}184}
...@@ -280,10 +279,10 @@ pub fn rotr(comptime T: type, x: T, r: var) T {...@@ -280,10 +279,10 @@ pub fn rotr(comptime T: type, x: T, r: var) T {
280}279}
281280
282test "math.rotr" {281test "math.rotr" {
283 assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001);282 assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
284 assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000);283 assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
285 assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001);284 assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
286 assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000);285 assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
287 assert(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);286 assert(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
288}287}
289288
...@@ -299,14 +298,13 @@ pub fn rotl(comptime T: type, x: T, r: var) T {...@@ -299,14 +298,13 @@ pub fn rotl(comptime T: type, x: T, r: var) T {
299}298}
300299
301test "math.rotl" {300test "math.rotl" {
302 assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001);301 assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
303 assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010);302 assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
304 assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001);303 assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
305 assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000);304 assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
306 assert(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);305 assert(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
307}306}
308307
309
310pub fn Log2Int(comptime T: type) type {308pub fn Log2Int(comptime T: type) type {
311 return @IntType(false, log2(T.bit_count));309 return @IntType(false, log2(T.bit_count));
312}310}
...@@ -323,14 +321,14 @@ fn testOverflow() void {...@@ -323,14 +321,14 @@ fn testOverflow() void {
323 assert((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);321 assert((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
324}322}
325323
326
327pub fn absInt(x: var) !@typeOf(x) {324pub fn absInt(x: var) !@typeOf(x) {
328 const T = @typeOf(x);325 const T = @typeOf(x);
329 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt326 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
330 comptime assert(T.is_signed); // must pass a signed integer to absInt327 comptime assert(T.is_signed); // must pass a signed integer to absInt
331 if (x == @minValue(@typeOf(x)))328
329 if (x == @minValue(@typeOf(x))) {
332 return error.Overflow;330 return error.Overflow;
333 {331 } else {
334 @setRuntimeSafety(false);332 @setRuntimeSafety(false);
335 return if (x < 0) -x else x;333 return if (x < 0) -x else x;
336 }334 }
...@@ -349,10 +347,8 @@ pub const absFloat = @import("fabs.zig").fabs;...@@ -349,10 +347,8 @@ pub const absFloat = @import("fabs.zig").fabs;
349347
350pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {348pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
351 @setRuntimeSafety(false);349 @setRuntimeSafety(false);
352 if (denominator == 0)350 if (denominator == 0) return error.DivisionByZero;
353 return error.DivisionByZero;351 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
354 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
355 return error.Overflow;
356 return @divTrunc(numerator, denominator);352 return @divTrunc(numerator, denominator);
357}353}
358354
...@@ -372,10 +368,8 @@ fn testDivTrunc() void {...@@ -372,10 +368,8 @@ fn testDivTrunc() void {
372368
373pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {369pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
374 @setRuntimeSafety(false);370 @setRuntimeSafety(false);
375 if (denominator == 0)371 if (denominator == 0) return error.DivisionByZero;
376 return error.DivisionByZero;372 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
377 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
378 return error.Overflow;
379 return @divFloor(numerator, denominator);373 return @divFloor(numerator, denominator);
380}374}
381375
...@@ -395,13 +389,10 @@ fn testDivFloor() void {...@@ -395,13 +389,10 @@ fn testDivFloor() void {
395389
396pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {390pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
397 @setRuntimeSafety(false);391 @setRuntimeSafety(false);
398 if (denominator == 0)392 if (denominator == 0) return error.DivisionByZero;
399 return error.DivisionByZero;393 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) return error.Overflow;
400 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
401 return error.Overflow;
402 const result = @divTrunc(numerator, denominator);394 const result = @divTrunc(numerator, denominator);
403 if (result * denominator != numerator)395 if (result * denominator != numerator) return error.UnexpectedRemainder;
404 return error.UnexpectedRemainder;
405 return result;396 return result;
406}397}
407398
...@@ -423,10 +414,8 @@ fn testDivExact() void {...@@ -423,10 +414,8 @@ fn testDivExact() void {
423414
424pub fn mod(comptime T: type, numerator: T, denominator: T) !T {415pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
425 @setRuntimeSafety(false);416 @setRuntimeSafety(false);
426 if (denominator == 0)417 if (denominator == 0) return error.DivisionByZero;
427 return error.DivisionByZero;418 if (denominator < 0) return error.NegativeDenominator;
428 if (denominator < 0)
429 return error.NegativeDenominator;
430 return @mod(numerator, denominator);419 return @mod(numerator, denominator);
431}420}
432421
...@@ -448,10 +437,8 @@ fn testMod() void {...@@ -448,10 +437,8 @@ fn testMod() void {
448437
449pub fn rem(comptime T: type, numerator: T, denominator: T) !T {438pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
450 @setRuntimeSafety(false);439 @setRuntimeSafety(false);
451 if (denominator == 0)440 if (denominator == 0) return error.DivisionByZero;
452 return error.DivisionByZero;441 if (denominator < 0) return error.NegativeDenominator;
453 if (denominator < 0)
454 return error.NegativeDenominator;
455 return @rem(numerator, denominator);442 return @rem(numerator, denominator);
456}443}
457444
...@@ -475,8 +462,7 @@ fn testRem() void {...@@ -475,8 +462,7 @@ fn testRem() void {
475/// Result is an unsigned integer.462/// Result is an unsigned integer.
476pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) {463pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) {
477 const uint = @IntType(false, @typeOf(x).bit_count);464 const uint = @IntType(false, @typeOf(x).bit_count);
478 if (x >= 0)465 if (x >= 0) return uint(x);
479 return uint(x);
480466
481 return uint(-(x + 1)) + 1;467 return uint(-(x + 1)) + 1;
482}468}
...@@ -495,15 +481,12 @@ test "math.absCast" {...@@ -495,15 +481,12 @@ test "math.absCast" {
495/// Returns the negation of the integer parameter.481/// Returns the negation of the integer parameter.
496/// Result is a signed integer.482/// Result is a signed integer.
497pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {483pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
498 if (@typeOf(x).is_signed)484 if (@typeOf(x).is_signed) return negate(x);
499 return negate(x);
500485
501 const int = @IntType(true, @typeOf(x).bit_count);486 const int = @IntType(true, @typeOf(x).bit_count);
502 if (x > -@minValue(int))487 if (x > -@minValue(int)) return error.Overflow;
503 return error.Overflow;
504488
505 if (x == -@minValue(int))489 if (x == -@minValue(int)) return @minValue(int);
506 return @minValue(int);
507490
508 return -int(x);491 return -int(x);
509}492}
...@@ -546,7 +529,7 @@ pub fn floorPowerOfTwo(comptime T: type, value: T) T {...@@ -546,7 +529,7 @@ pub fn floorPowerOfTwo(comptime T: type, value: T) T {
546 var x = value;529 var x = value;
547530
548 comptime var i = 1;531 comptime var i = 1;
549 inline while(T.bit_count > i) : (i *= 2) {532 inline while (T.bit_count > i) : (i *= 2) {
550 x |= (x >> i);533 x |= (x >> i);
551 }534 }
552535
std/math/ln.zig+2-4
...@@ -120,11 +120,9 @@ pub fn ln_64(x_: f64) f64 {...@@ -120,11 +120,9 @@ pub fn ln_64(x_: f64) f64 {
120 k -= 54;120 k -= 54;
121 x *= 0x1.0p54;121 x *= 0x1.0p54;
122 hx = u32(@bitCast(u64, ix) >> 32);122 hx = u32(@bitCast(u64, ix) >> 32);
123 }123 } else if (hx >= 0x7FF00000) {
124 else if (hx >= 0x7FF00000) {
125 return x;124 return x;
126 }125 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
127 else if (hx == 0x3FF00000 and ix << 32 == 0) {
128 return 0;126 return 0;
129 }127 }
130128
std/math/log10.zig+8-10
...@@ -35,10 +35,10 @@ pub fn log10(x: var) @typeOf(x) {...@@ -35,10 +35,10 @@ pub fn log10(x: var) @typeOf(x) {
35}35}
3636
37pub fn log10_32(x_: f32) f32 {37pub fn log10_32(x_: f32) f32 {
38 const ivln10hi: f32 = 4.3432617188e-01;38 const ivln10hi: f32 = 4.3432617188e-01;
39 const ivln10lo: f32 = -3.1689971365e-05;39 const ivln10lo: f32 = -3.1689971365e-05;
40 const log10_2hi: f32 = 3.0102920532e-01;40 const log10_2hi: f32 = 3.0102920532e-01;
41 const log10_2lo: f32 = 7.9034151668e-07;41 const log10_2lo: f32 = 7.9034151668e-07;
42 const Lg1: f32 = 0xaaaaaa.0p-24;42 const Lg1: f32 = 0xaaaaaa.0p-24;
43 const Lg2: f32 = 0xccce13.0p-25;43 const Lg2: f32 = 0xccce13.0p-25;
44 const Lg3: f32 = 0x91e9ee.0p-25;44 const Lg3: f32 = 0x91e9ee.0p-25;
...@@ -95,8 +95,8 @@ pub fn log10_32(x_: f32) f32 {...@@ -95,8 +95,8 @@ pub fn log10_32(x_: f32) f32 {
95}95}
9696
97pub fn log10_64(x_: f64) f64 {97pub fn log10_64(x_: f64) f64 {
98 const ivln10hi: f64 = 4.34294481878168880939e-01;98 const ivln10hi: f64 = 4.34294481878168880939e-01;
99 const ivln10lo: f64 = 2.50829467116452752298e-11;99 const ivln10lo: f64 = 2.50829467116452752298e-11;
100 const log10_2hi: f64 = 3.01029995663611771306e-01;100 const log10_2hi: f64 = 3.01029995663611771306e-01;
101 const log10_2lo: f64 = 3.69423907715893078616e-13;101 const log10_2lo: f64 = 3.69423907715893078616e-13;
102 const Lg1: f64 = 6.666666666666735130e-01;102 const Lg1: f64 = 6.666666666666735130e-01;
...@@ -126,11 +126,9 @@ pub fn log10_64(x_: f64) f64 {...@@ -126,11 +126,9 @@ pub fn log10_64(x_: f64) f64 {
126 k -= 54;126 k -= 54;
127 x *= 0x1.0p54;127 x *= 0x1.0p54;
128 hx = u32(@bitCast(u64, x) >> 32);128 hx = u32(@bitCast(u64, x) >> 32);
129 }129 } else if (hx >= 0x7FF00000) {
130 else if (hx >= 0x7FF00000) {
131 return x;130 return x;
132 }131 } else if (hx == 0x3FF00000 and ix << 32 == 0) {
133 else if (hx == 0x3FF00000 and ix << 32 == 0) {
134 return 0;132 return 0;
135 }133 }
136134
std/math/log2.zig+5-2
...@@ -27,7 +27,10 @@ pub fn log2(x: var) @typeOf(x) {...@@ -27,7 +27,10 @@ pub fn log2(x: var) @typeOf(x) {
27 TypeId.IntLiteral => comptime {27 TypeId.IntLiteral => comptime {
28 var result = 0;28 var result = 0;
29 var x_shifted = x;29 var x_shifted = x;
30 while (b: {x_shifted >>= 1; break :b x_shifted != 0;}) : (result += 1) {}30 while (b: {
31 x_shifted >>= 1;
32 break :b x_shifted != 0;
33 }) : (result += 1) {}
31 return result;34 return result;
32 },35 },
33 TypeId.Int => {36 TypeId.Int => {
...@@ -38,7 +41,7 @@ pub fn log2(x: var) @typeOf(x) {...@@ -38,7 +41,7 @@ pub fn log2(x: var) @typeOf(x) {
38}41}
3942
40pub fn log2_32(x_: f32) f32 {43pub fn log2_32(x_: f32) f32 {
41 const ivln2hi: f32 = 1.4428710938e+00;44 const ivln2hi: f32 = 1.4428710938e+00;
42 const ivln2lo: f32 = -1.7605285393e-04;45 const ivln2lo: f32 = -1.7605285393e-04;
43 const Lg1: f32 = 0xaaaaaa.0p-24;46 const Lg1: f32 = 0xaaaaaa.0p-24;
44 const Lg2: f32 = 0xccce13.0p-25;47 const Lg2: f32 = 0xccce13.0p-25;
std/math/round.zig+4-4
...@@ -24,13 +24,13 @@ fn round32(x_: f32) f32 {...@@ -24,13 +24,13 @@ fn round32(x_: f32) f32 {
24 const e = (u >> 23) & 0xFF;24 const e = (u >> 23) & 0xFF;
25 var y: f32 = undefined;25 var y: f32 = undefined;
2626
27 if (e >= 0x7F+23) {27 if (e >= 0x7F + 23) {
28 return x;28 return x;
29 }29 }
30 if (u >> 31 != 0) {30 if (u >> 31 != 0) {
31 x = -x;31 x = -x;
32 }32 }
33 if (e < 0x7F-1) {33 if (e < 0x7F - 1) {
34 math.forceEval(x + math.f32_toint);34 math.forceEval(x + math.f32_toint);
35 return 0 * @bitCast(f32, u);35 return 0 * @bitCast(f32, u);
36 }36 }
...@@ -61,13 +61,13 @@ fn round64(x_: f64) f64 {...@@ -61,13 +61,13 @@ fn round64(x_: f64) f64 {
61 const e = (u >> 52) & 0x7FF;61 const e = (u >> 52) & 0x7FF;
62 var y: f64 = undefined;62 var y: f64 = undefined;
6363
64 if (e >= 0x3FF+52) {64 if (e >= 0x3FF + 52) {
65 return x;65 return x;
66 }66 }
67 if (u >> 63 != 0) {67 if (u >> 63 != 0) {
68 x = -x;68 x = -x;
69 }69 }
70 if (e < 0x3ff-1) {70 if (e < 0x3ff - 1) {
71 math.forceEval(x + math.f64_toint);71 math.forceEval(x + math.f64_toint);
72 return 0 * @bitCast(f64, u);72 return 0 * @bitCast(f64, u);
73 }73 }
std/math/sin.zig+6-6
...@@ -19,20 +19,20 @@ pub fn sin(x: var) @typeOf(x) {...@@ -19,20 +19,20 @@ pub fn sin(x: var) @typeOf(x) {
19}19}
2020
21// sin polynomial coefficients21// sin polynomial coefficients
22const S0 = 1.58962301576546568060E-10;22const S0 = 1.58962301576546568060E-10;
23const S1 = -2.50507477628578072866E-8;23const S1 = -2.50507477628578072866E-8;
24const S2 = 2.75573136213857245213E-6;24const S2 = 2.75573136213857245213E-6;
25const S3 = -1.98412698295895385996E-4;25const S3 = -1.98412698295895385996E-4;
26const S4 = 8.33333333332211858878E-3;26const S4 = 8.33333333332211858878E-3;
27const S5 = -1.66666666666666307295E-1;27const S5 = -1.66666666666666307295E-1;
2828
29// cos polynomial coeffiecients29// cos polynomial coeffiecients
30const C0 = -1.13585365213876817300E-11;30const C0 = -1.13585365213876817300E-11;
31const C1 = 2.08757008419747316778E-9;31const C1 = 2.08757008419747316778E-9;
32const C2 = -2.75573141792967388112E-7;32const C2 = -2.75573141792967388112E-7;
33const C3 = 2.48015872888517045348E-5;33const C3 = 2.48015872888517045348E-5;
34const C4 = -1.38888888888730564116E-3;34const C4 = -1.38888888888730564116E-3;
35const C5 = 4.16666666666665929218E-2;35const C5 = 4.16666666666665929218E-2;
3636
37// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.37// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.
38//38//
std/math/tan.zig+3-3
...@@ -19,12 +19,12 @@ pub fn tan(x: var) @typeOf(x) {...@@ -19,12 +19,12 @@ pub fn tan(x: var) @typeOf(x) {
19}19}
2020
21const Tp0 = -1.30936939181383777646E4;21const Tp0 = -1.30936939181383777646E4;
22const Tp1 = 1.15351664838587416140E6;22const Tp1 = 1.15351664838587416140E6;
23const Tp2 = -1.79565251976484877988E7;23const Tp2 = -1.79565251976484877988E7;
2424
25const Tq1 = 1.36812963470692954678E4;25const Tq1 = 1.36812963470692954678E4;
26const Tq2 = -1.32089234440210967447E6;26const Tq2 = -1.32089234440210967447E6;
27const Tq3 = 2.50083801823357915839E7;27const Tq3 = 2.50083801823357915839E7;
28const Tq4 = -5.38695755929454629881E7;28const Tq4 = -5.38695755929454629881E7;
2929
30// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.30// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.
std/mem.zig+125-74
...@@ -6,14 +6,14 @@ const builtin = @import("builtin");...@@ -6,14 +6,14 @@ const builtin = @import("builtin");
6const mem = this;6const mem = this;
77
8pub const Allocator = struct {8pub const Allocator = struct {
9 const Error = error {OutOfMemory};9 const Error = error{OutOfMemory};
1010
11 /// Allocate byte_count bytes and return them in a slice, with the11 /// Allocate byte_count bytes and return them in a slice, with the
12 /// slice's pointer aligned at least to alignment bytes.12 /// slice's pointer aligned at least to alignment bytes.
13 /// The returned newly allocated memory is undefined.13 /// The returned newly allocated memory is undefined.
14 /// `alignment` is guaranteed to be >= 114 /// `alignment` is guaranteed to be >= 1
15 /// `alignment` is guaranteed to be a power of 215 /// `alignment` is guaranteed to be a power of 2
16 allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,16 allocFn: fn(self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,
1717
18 /// If `new_byte_count > old_mem.len`:18 /// If `new_byte_count > old_mem.len`:
19 /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.19 /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
...@@ -26,10 +26,10 @@ pub const Allocator = struct {...@@ -26,10 +26,10 @@ pub const Allocator = struct {
26 /// The returned newly allocated memory is undefined.26 /// The returned newly allocated memory is undefined.
27 /// `alignment` is guaranteed to be >= 127 /// `alignment` is guaranteed to be >= 1
28 /// `alignment` is guaranteed to be a power of 228 /// `alignment` is guaranteed to be a power of 2
29 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,29 reallocFn: fn(self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
3030
31 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`31 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
32 freeFn: fn (self: &Allocator, old_mem: []u8) void,32 freeFn: fn(self: &Allocator, old_mem: []u8) void,
3333
34 fn create(self: &Allocator, comptime T: type) !&T {34 fn create(self: &Allocator, comptime T: type) !&T {
35 if (@sizeOf(T) == 0) return &{};35 if (@sizeOf(T) == 0) return &{};
...@@ -47,7 +47,7 @@ pub const Allocator = struct {...@@ -47,7 +47,7 @@ pub const Allocator = struct {
47 if (@sizeOf(T) == 0) return &{};47 if (@sizeOf(T) == 0) return &{};
48 const slice = try self.alloc(T, 1);48 const slice = try self.alloc(T, 1);
49 const ptr = &slice[0];49 const ptr = &slice[0];
50 *ptr = *init;50 ptr.* = init.*;
51 return ptr;51 return ptr;
52 }52 }
5353
...@@ -59,9 +59,7 @@ pub const Allocator = struct {...@@ -59,9 +59,7 @@ pub const Allocator = struct {
59 return self.alignedAlloc(T, @alignOf(T), n);59 return self.alignedAlloc(T, @alignOf(T), n);
60 }60 }
6161
62 fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,62 fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29, n: usize) ![]align(alignment) T {
63 n: usize) ![]align(alignment) T
64 {
65 if (n == 0) {63 if (n == 0) {
66 return (&align(alignment) T)(undefined)[0..0];64 return (&align(alignment) T)(undefined)[0..0];
67 }65 }
...@@ -70,7 +68,7 @@ pub const Allocator = struct {...@@ -70,7 +68,7 @@ pub const Allocator = struct {
70 assert(byte_slice.len == byte_count);68 assert(byte_slice.len == byte_count);
71 // This loop gets optimized out in ReleaseFast mode69 // This loop gets optimized out in ReleaseFast mode
72 for (byte_slice) |*byte| {70 for (byte_slice) |*byte| {
73 *byte = undefined;71 byte.* = undefined;
74 }72 }
75 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));73 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
76 }74 }
...@@ -79,9 +77,7 @@ pub const Allocator = struct {...@@ -79,9 +77,7 @@ pub const Allocator = struct {
79 return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);77 return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
80 }78 }
8179
82 fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29,80 fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) ![]align(alignment) T {
83 old_mem: []align(alignment) T, n: usize) ![]align(alignment) T
84 {
85 if (old_mem.len == 0) {81 if (old_mem.len == 0) {
86 return self.alloc(T, n);82 return self.alloc(T, n);
87 }83 }
...@@ -97,7 +93,7 @@ pub const Allocator = struct {...@@ -97,7 +93,7 @@ pub const Allocator = struct {
97 if (n > old_mem.len) {93 if (n > old_mem.len) {
98 // This loop gets optimized out in ReleaseFast mode94 // This loop gets optimized out in ReleaseFast mode
99 for (byte_slice[old_byte_slice.len..]) |*byte| {95 for (byte_slice[old_byte_slice.len..]) |*byte| {
100 *byte = undefined;96 byte.* = undefined;
101 }97 }
102 }98 }
103 return ([]T)(@alignCast(alignment, byte_slice));99 return ([]T)(@alignCast(alignment, byte_slice));
...@@ -110,9 +106,7 @@ pub const Allocator = struct {...@@ -110,9 +106,7 @@ pub const Allocator = struct {
110 return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);106 return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
111 }107 }
112108
113 fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29,109 fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) []align(alignment) T {
114 old_mem: []align(alignment) T, n: usize) []align(alignment) T
115 {
116 if (n == 0) {110 if (n == 0) {
117 self.free(old_mem);111 self.free(old_mem);
118 return old_mem[0..0];112 return old_mem[0..0];
...@@ -131,8 +125,7 @@ pub const Allocator = struct {...@@ -131,8 +125,7 @@ pub const Allocator = struct {
131125
132 fn free(self: &Allocator, memory: var) void {126 fn free(self: &Allocator, memory: var) void {
133 const bytes = ([]const u8)(memory);127 const bytes = ([]const u8)(memory);
134 if (bytes.len == 0)128 if (bytes.len == 0) return;
135 return;
136 const non_const_ptr = @intToPtr(&u8, @ptrToInt(bytes.ptr));129 const non_const_ptr = @intToPtr(&u8, @ptrToInt(bytes.ptr));
137 self.freeFn(self, non_const_ptr[0..bytes.len]);130 self.freeFn(self, non_const_ptr[0..bytes.len]);
138 }131 }
...@@ -146,11 +139,13 @@ pub fn copy(comptime T: type, dest: []T, source: []const T) void {...@@ -146,11 +139,13 @@ pub fn copy(comptime T: type, dest: []T, source: []const T) void {
146 // this and automatically omit safety checks for loops139 // this and automatically omit safety checks for loops
147 @setRuntimeSafety(false);140 @setRuntimeSafety(false);
148 assert(dest.len >= source.len);141 assert(dest.len >= source.len);
149 for (source) |s, i| dest[i] = s;142 for (source) |s, i|
143 dest[i] = s;
150}144}
151145
152pub fn set(comptime T: type, dest: []T, value: T) void {146pub fn set(comptime T: type, dest: []T, value: T) void {
153 for (dest) |*d| *d = value;147 for (dest) |*d|
148 d.* = value;
154}149}
155150
156/// Returns true if lhs < rhs, false otherwise151/// Returns true if lhs < rhs, false otherwise
...@@ -229,8 +224,7 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {...@@ -229,8 +224,7 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
229 var i: usize = slice.len;224 var i: usize = slice.len;
230 while (i != 0) {225 while (i != 0) {
231 i -= 1;226 i -= 1;
232 if (slice[i] == value)227 if (slice[i] == value) return i;
233 return i;
234 }228 }
235 return null;229 return null;
236}230}
...@@ -238,8 +232,7 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {...@@ -238,8 +232,7 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
238pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {232pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
239 var i: usize = start_index;233 var i: usize = start_index;
240 while (i < slice.len) : (i += 1) {234 while (i < slice.len) : (i += 1) {
241 if (slice[i] == value)235 if (slice[i] == value) return i;
242 return i;
243 }236 }
244 return null;237 return null;
245}238}
...@@ -253,8 +246,7 @@ pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?us...@@ -253,8 +246,7 @@ pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?us
253 while (i != 0) {246 while (i != 0) {
254 i -= 1;247 i -= 1;
255 for (values) |value| {248 for (values) |value| {
256 if (slice[i] == value)249 if (slice[i] == value) return i;
257 return i;
258 }250 }
259 }251 }
260 return null;252 return null;
...@@ -264,8 +256,7 @@ pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, val...@@ -264,8 +256,7 @@ pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, val
264 var i: usize = start_index;256 var i: usize = start_index;
265 while (i < slice.len) : (i += 1) {257 while (i < slice.len) : (i += 1) {
266 for (values) |value| {258 for (values) |value| {
267 if (slice[i] == value)259 if (slice[i] == value) return i;
268 return i;
269 }260 }
270 }261 }
271 return null;262 return null;
...@@ -279,28 +270,23 @@ pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize...@@ -279,28 +270,23 @@ pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize
279/// To start looking at a different index, slice the haystack first.270/// To start looking at a different index, slice the haystack first.
280/// TODO is there even a better algorithm for this?271/// TODO is there even a better algorithm for this?
281pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {272pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {
282 if (needle.len > haystack.len)273 if (needle.len > haystack.len) return null;
283 return null;
284274
285 var i: usize = haystack.len - needle.len;275 var i: usize = haystack.len - needle.len;
286 while (true) : (i -= 1) {276 while (true) : (i -= 1) {
287 if (mem.eql(T, haystack[i..i+needle.len], needle))277 if (mem.eql(T, haystack[i..i + needle.len], needle)) return i;
288 return i;278 if (i == 0) return null;
289 if (i == 0)
290 return null;
291 }279 }
292}280}
293281
294// TODO boyer-moore algorithm282// TODO boyer-moore algorithm
295pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {283pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
296 if (needle.len > haystack.len)284 if (needle.len > haystack.len) return null;
297 return null;
298285
299 var i: usize = start_index;286 var i: usize = start_index;
300 const end = haystack.len - needle.len;287 const end = haystack.len - needle.len;
301 while (i <= end) : (i += 1) {288 while (i <= end) : (i += 1) {
302 if (eql(T, haystack[i .. i + needle.len], needle))289 if (eql(T, haystack[i..i + needle.len], needle)) return i;
303 return i;
304 }290 }
305 return null;291 return null;
306}292}
...@@ -355,9 +341,12 @@ pub fn readIntBE(comptime T: type, bytes: []const u8) T {...@@ -355,9 +341,12 @@ pub fn readIntBE(comptime T: type, bytes: []const u8) T {
355 }341 }
356 assert(bytes.len == @sizeOf(T));342 assert(bytes.len == @sizeOf(T));
357 var result: T = 0;343 var result: T = 0;
358 {comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {344 {
359 result = (result << 8) | T(bytes[i]);345 comptime var i = 0;
360 }}346 inline while (i < @sizeOf(T)) : (i += 1) {
347 result = (result << 8) | T(bytes[i]);
348 }
349 }
361 return result;350 return result;
362}351}
363352
...@@ -369,9 +358,12 @@ pub fn readIntLE(comptime T: type, bytes: []const u8) T {...@@ -369,9 +358,12 @@ pub fn readIntLE(comptime T: type, bytes: []const u8) T {
369 }358 }
370 assert(bytes.len == @sizeOf(T));359 assert(bytes.len == @sizeOf(T));
371 var result: T = 0;360 var result: T = 0;
372 {comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {361 {
373 result |= T(bytes[i]) << i * 8;362 comptime var i = 0;
374 }}363 inline while (i < @sizeOf(T)) : (i += 1) {
364 result |= T(bytes[i]) << i * 8;
365 }
366 }
375 return result;367 return result;
376}368}
377369
...@@ -393,7 +385,7 @@ pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {...@@ -393,7 +385,7 @@ pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {
393 },385 },
394 builtin.Endian.Little => {386 builtin.Endian.Little => {
395 for (buf) |*b| {387 for (buf) |*b| {
396 *b = @truncate(u8, bits);388 b.* = @truncate(u8, bits);
397 bits >>= 8;389 bits >>= 8;
398 }390 }
399 },391 },
...@@ -401,7 +393,6 @@ pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {...@@ -401,7 +393,6 @@ pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {
401 assert(bits == 0);393 assert(bits == 0);
402}394}
403395
404
405pub fn hash_slice_u8(k: []const u8) u32 {396pub fn hash_slice_u8(k: []const u8) u32 {
406 // FNV 32-bit hash397 // FNV 32-bit hash
407 var h: u32 = 2166136261;398 var h: u32 = 2166136261;
...@@ -420,7 +411,7 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {...@@ -420,7 +411,7 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {
420/// split(" abc def ghi ", " ")411/// split(" abc def ghi ", " ")
421/// Will return slices for "abc", "def", "ghi", null, in that order.412/// Will return slices for "abc", "def", "ghi", null, in that order.
422pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {413pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {
423 return SplitIterator {414 return SplitIterator{
424 .index = 0,415 .index = 0,
425 .buffer = buffer,416 .buffer = buffer,
426 .split_bytes = split_bytes,417 .split_bytes = split_bytes,
...@@ -436,7 +427,7 @@ test "mem.split" {...@@ -436,7 +427,7 @@ test "mem.split" {
436}427}
437428
438pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {429pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
439 return if (needle.len > haystack.len) false else eql(T, haystack[0 .. needle.len], needle);430 return if (needle.len > haystack.len) false else eql(T, haystack[0..needle.len], needle);
440}431}
441432
442test "mem.startsWith" {433test "mem.startsWith" {
...@@ -445,10 +436,9 @@ test "mem.startsWith" {...@@ -445,10 +436,9 @@ test "mem.startsWith" {
445}436}
446437
447pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {438pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
448 return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len ..], needle);439 return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len..], needle);
449}440}
450441
451
452test "mem.endsWith" {442test "mem.endsWith" {
453 assert(endsWith(u8, "Needle in haystack", "haystack"));443 assert(endsWith(u8, "Needle in haystack", "haystack"));
454 assert(!endsWith(u8, "Bob", "Bo"));444 assert(!endsWith(u8, "Bob", "Bo"));
...@@ -542,29 +532,47 @@ test "testReadInt" {...@@ -542,29 +532,47 @@ test "testReadInt" {
542}532}
543fn testReadIntImpl() void {533fn testReadIntImpl() void {
544 {534 {
545 const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 };535 const bytes = []u8{
546 assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);536 0x12,
547 assert(readIntBE(u32, bytes) == 0x12345678);537 0x34,
548 assert(readIntBE(i32, bytes) == 0x12345678);538 0x56,
539 0x78,
540 };
541 assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
542 assert(readIntBE(u32, bytes) == 0x12345678);
543 assert(readIntBE(i32, bytes) == 0x12345678);
549 assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412);544 assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412);
550 assert(readIntLE(u32, bytes) == 0x78563412);545 assert(readIntLE(u32, bytes) == 0x78563412);
551 assert(readIntLE(i32, bytes) == 0x78563412);546 assert(readIntLE(i32, bytes) == 0x78563412);
552 }547 }
553 {548 {
554 const buf = []u8{0x00, 0x00, 0x12, 0x34};549 const buf = []u8{
550 0x00,
551 0x00,
552 0x12,
553 0x34,
554 };
555 const answer = readInt(buf, u64, builtin.Endian.Big);555 const answer = readInt(buf, u64, builtin.Endian.Big);
556 assert(answer == 0x00001234);556 assert(answer == 0x00001234);
557 }557 }
558 {558 {
559 const buf = []u8{0x12, 0x34, 0x00, 0x00};559 const buf = []u8{
560 0x12,
561 0x34,
562 0x00,
563 0x00,
564 };
560 const answer = readInt(buf, u64, builtin.Endian.Little);565 const answer = readInt(buf, u64, builtin.Endian.Little);
561 assert(answer == 0x00003412);566 assert(answer == 0x00003412);
562 }567 }
563 {568 {
564 const bytes = []u8{0xff, 0xfe};569 const bytes = []u8{
565 assert(readIntBE(u16, bytes) == 0xfffe);570 0xff,
571 0xfe,
572 };
573 assert(readIntBE(u16, bytes) == 0xfffe);
566 assert(readIntBE(i16, bytes) == -0x0002);574 assert(readIntBE(i16, bytes) == -0x0002);
567 assert(readIntLE(u16, bytes) == 0xfeff);575 assert(readIntLE(u16, bytes) == 0xfeff);
568 assert(readIntLE(i16, bytes) == -0x0101);576 assert(readIntLE(i16, bytes) == -0x0101);
569 }577 }
570}578}
...@@ -577,19 +585,38 @@ fn testWriteIntImpl() void {...@@ -577,19 +585,38 @@ fn testWriteIntImpl() void {
577 var bytes: [4]u8 = undefined;585 var bytes: [4]u8 = undefined;
578586
579 writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big);587 writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big);
580 assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));588 assert(eql(u8, bytes, []u8{
589 0x12,
590 0x34,
591 0x56,
592 0x78,
593 }));
581594
582 writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little);595 writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little);
583 assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));596 assert(eql(u8, bytes, []u8{
597 0x12,
598 0x34,
599 0x56,
600 0x78,
601 }));
584602
585 writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big);603 writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big);
586 assert(eql(u8, bytes, []u8{ 0x00, 0x00, 0x12, 0x34 }));604 assert(eql(u8, bytes, []u8{
605 0x00,
606 0x00,
607 0x12,
608 0x34,
609 }));
587610
588 writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little);611 writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little);
589 assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 }));612 assert(eql(u8, bytes, []u8{
613 0x34,
614 0x12,
615 0x00,
616 0x00,
617 }));
590}618}
591619
592
593pub fn min(comptime T: type, slice: []const T) T {620pub fn min(comptime T: type, slice: []const T) T {
594 var best = slice[0];621 var best = slice[0];
595 for (slice[1..]) |item| {622 for (slice[1..]) |item| {
...@@ -615,9 +642,9 @@ test "mem.max" {...@@ -615,9 +642,9 @@ test "mem.max" {
615}642}
616643
617pub fn swap(comptime T: type, a: &T, b: &T) void {644pub fn swap(comptime T: type, a: &T, b: &T) void {
618 const tmp = *a;645 const tmp = a.*;
619 *a = *b;646 a.* = b.*;
620 *b = tmp;647 b.* = tmp;
621}648}
622649
623/// In-place order reversal of a slice650/// In-place order reversal of a slice
...@@ -630,10 +657,22 @@ pub fn reverse(comptime T: type, items: []T) void {...@@ -630,10 +657,22 @@ pub fn reverse(comptime T: type, items: []T) void {
630}657}
631658
632test "std.mem.reverse" {659test "std.mem.reverse" {
633 var arr = []i32{ 5, 3, 1, 2, 4 };660 var arr = []i32{
661 5,
662 3,
663 1,
664 2,
665 4,
666 };
634 reverse(i32, arr[0..]);667 reverse(i32, arr[0..]);
635668
636 assert(eql(i32, arr, []i32{ 4, 2, 1, 3, 5 }));669 assert(eql(i32, arr, []i32{
670 4,
671 2,
672 1,
673 3,
674 5,
675 }));
637}676}
638677
639/// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)678/// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)
...@@ -645,13 +684,25 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void {...@@ -645,13 +684,25 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void {
645}684}
646685
647test "std.mem.rotate" {686test "std.mem.rotate" {
648 var arr = []i32{ 5, 3, 1, 2, 4 };687 var arr = []i32{
688 5,
689 3,
690 1,
691 2,
692 4,
693 };
649 rotate(i32, arr[0..], 2);694 rotate(i32, arr[0..], 2);
650695
651 assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));696 assert(eql(i32, arr, []i32{
697 1,
698 2,
699 4,
700 5,
701 3,
702 }));
652}703}
653704
654// TODO: When https://github.com/zig-lang/zig/issues/649 is solved these can be done by705// TODO: When https://github.com/ziglang/zig/issues/649 is solved these can be done by
655// endian-casting the pointer and then dereferencing706// endian-casting the pointer and then dereferencing
656707
657pub fn endianSwapIfLe(comptime T: type, x: T) T {708pub fn endianSwapIfLe(comptime T: type, x: T) T {
std/net.zig+16-24
...@@ -19,37 +19,29 @@ pub const Address = struct {...@@ -19,37 +19,29 @@ pub const Address = struct {
19 os_addr: OsAddress,19 os_addr: OsAddress,
2020
21 pub fn initIp4(ip4: u32, port: u16) Address {21 pub fn initIp4(ip4: u32, port: u16) Address {
22 return Address {22 return Address{ .os_addr = posix.sockaddr{ .in = posix.sockaddr_in{
23 .os_addr = posix.sockaddr {23 .family = posix.AF_INET,
24 .in = posix.sockaddr_in {24 .port = std.mem.endianSwapIfLe(u16, port),
25 .family = posix.AF_INET,25 .addr = ip4,
26 .port = std.mem.endianSwapIfLe(u16, port),26 .zero = []u8{0} ** 8,
27 .addr = ip4,27 } } };
28 .zero = []u8{0} ** 8,
29 },
30 },
31 };
32 }28 }
3329
34 pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {30 pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {
35 return Address {31 return Address{
36 .family = posix.AF_INET6,32 .family = posix.AF_INET6,
37 .os_addr = posix.sockaddr {33 .os_addr = posix.sockaddr{ .in6 = posix.sockaddr_in6{
38 .in6 = posix.sockaddr_in6 {34 .family = posix.AF_INET6,
39 .family = posix.AF_INET6,35 .port = std.mem.endianSwapIfLe(u16, port),
40 .port = std.mem.endianSwapIfLe(u16, port),36 .flowinfo = 0,
41 .flowinfo = 0,37 .addr = ip6.addr,
42 .addr = ip6.addr,38 .scope_id = ip6.scope_id,
43 .scope_id = ip6.scope_id,39 } },
44 },
45 },
46 };40 };
47 }41 }
4842
49 pub fn initPosix(addr: &const posix.sockaddr) Address {43 pub fn initPosix(addr: &const posix.sockaddr) Address {
50 return Address {44 return Address{ .os_addr = addr.* };
51 .os_addr = *addr,
52 };
53 }45 }
5446
55 pub fn format(self: &const Address, out_stream: var) !void {47 pub fn format(self: &const Address, out_stream: var) !void {
...@@ -98,7 +90,7 @@ pub fn parseIp4(buf: []const u8) !u32 {...@@ -98,7 +90,7 @@ pub fn parseIp4(buf: []const u8) !u32 {
98 }90 }
99 } else {91 } else {
100 return error.InvalidCharacter;92 return error.InvalidCharacter;
101 } 93 }
102 }94 }
103 if (index == 3 and saw_any_digits) {95 if (index == 3 and saw_any_digits) {
104 out_ptr[index] = x;96 out_ptr[index] = x;
std/os/child_process.zig+106-94
...@@ -49,7 +49,7 @@ pub const ChildProcess = struct {...@@ -49,7 +49,7 @@ pub const ChildProcess = struct {
49 err_pipe: if (is_windows) void else [2]i32,49 err_pipe: if (is_windows) void else [2]i32,
50 llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,50 llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
5151
52 pub const SpawnError = error {52 pub const SpawnError = error{
53 ProcessFdQuotaExceeded,53 ProcessFdQuotaExceeded,
54 Unexpected,54 Unexpected,
55 NotDir,55 NotDir,
...@@ -88,7 +88,7 @@ pub const ChildProcess = struct {...@@ -88,7 +88,7 @@ pub const ChildProcess = struct {
88 const child = try allocator.create(ChildProcess);88 const child = try allocator.create(ChildProcess);
89 errdefer allocator.destroy(child);89 errdefer allocator.destroy(child);
9090
91 *child = ChildProcess {91 child.* = ChildProcess{
92 .allocator = allocator,92 .allocator = allocator,
93 .argv = argv,93 .argv = argv,
94 .pid = undefined,94 .pid = undefined,
...@@ -99,8 +99,10 @@ pub const ChildProcess = struct {...@@ -99,8 +99,10 @@ pub const ChildProcess = struct {
99 .term = null,99 .term = null,
100 .env_map = null,100 .env_map = null,
101 .cwd = null,101 .cwd = null,
102 .uid = if (is_windows) {} else null,102 .uid = if (is_windows) {} else
103 .gid = if (is_windows) {} else null,103 null,
104 .gid = if (is_windows) {} else
105 null,
104 .stdin = null,106 .stdin = null,
105 .stdout = null,107 .stdout = null,
106 .stderr = null,108 .stderr = null,
...@@ -193,9 +195,7 @@ pub const ChildProcess = struct {...@@ -193,9 +195,7 @@ pub const ChildProcess = struct {
193195
194 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.196 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
195 /// If it succeeds, the caller owns result.stdout and result.stderr memory.197 /// If it succeeds, the caller owns result.stdout and result.stderr memory.
196 pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8,198 pub fn exec(allocator: &mem.Allocator, argv: []const []const u8, cwd: ?[]const u8, env_map: ?&const BufMap, max_output_size: usize) !ExecResult {
197 env_map: ?&const BufMap, max_output_size: usize) !ExecResult
198 {
199 const child = try ChildProcess.init(argv, allocator);199 const child = try ChildProcess.init(argv, allocator);
200 defer child.deinit();200 defer child.deinit();
201201
...@@ -218,7 +218,7 @@ pub const ChildProcess = struct {...@@ -218,7 +218,7 @@ pub const ChildProcess = struct {
218 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);218 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
219 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);219 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
220220
221 return ExecResult {221 return ExecResult{
222 .term = try child.wait(),222 .term = try child.wait(),
223 .stdout = stdout.toOwnedSlice(),223 .stdout = stdout.toOwnedSlice(),
224 .stderr = stderr.toOwnedSlice(),224 .stderr = stderr.toOwnedSlice(),
...@@ -255,9 +255,9 @@ pub const ChildProcess = struct {...@@ -255,9 +255,9 @@ pub const ChildProcess = struct {
255 self.term = (SpawnError!Term)(x: {255 self.term = (SpawnError!Term)(x: {
256 var exit_code: windows.DWORD = undefined;256 var exit_code: windows.DWORD = undefined;
257 if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {257 if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
258 break :x Term { .Unknown = 0 };258 break :x Term{ .Unknown = 0 };
259 } else {259 } else {
260 break :x Term { .Exited = @bitCast(i32, exit_code)};260 break :x Term{ .Exited = @bitCast(i32, exit_code) };
261 }261 }
262 });262 });
263263
...@@ -288,9 +288,18 @@ pub const ChildProcess = struct {...@@ -288,9 +288,18 @@ pub const ChildProcess = struct {
288 }288 }
289289
290 fn cleanupStreams(self: &ChildProcess) void {290 fn cleanupStreams(self: &ChildProcess) void {
291 if (self.stdin) |*stdin| { stdin.close(); self.stdin = null; }291 if (self.stdin) |*stdin| {
292 if (self.stdout) |*stdout| { stdout.close(); self.stdout = null; }292 stdin.close();
293 if (self.stderr) |*stderr| { stderr.close(); self.stderr = null; }293 self.stdin = null;
294 }
295 if (self.stdout) |*stdout| {
296 stdout.close();
297 self.stdout = null;
298 }
299 if (self.stderr) |*stderr| {
300 stderr.close();
301 self.stderr = null;
302 }
294 }303 }
295304
296 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {305 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {
...@@ -317,25 +326,30 @@ pub const ChildProcess = struct {...@@ -317,25 +326,30 @@ pub const ChildProcess = struct {
317326
318 fn statusToTerm(status: i32) Term {327 fn statusToTerm(status: i32) Term {
319 return if (posix.WIFEXITED(status))328 return if (posix.WIFEXITED(status))
320 Term { .Exited = posix.WEXITSTATUS(status) }329 Term{ .Exited = posix.WEXITSTATUS(status) }
321 else if (posix.WIFSIGNALED(status))330 else if (posix.WIFSIGNALED(status))
322 Term { .Signal = posix.WTERMSIG(status) }331 Term{ .Signal = posix.WTERMSIG(status) }
323 else if (posix.WIFSTOPPED(status))332 else if (posix.WIFSTOPPED(status))
324 Term { .Stopped = posix.WSTOPSIG(status) }333 Term{ .Stopped = posix.WSTOPSIG(status) }
325 else334 else
326 Term { .Unknown = status }335 Term{ .Unknown = status };
327 ;
328 }336 }
329337
330 fn spawnPosix(self: &ChildProcess) !void {338 fn spawnPosix(self: &ChildProcess) !void {
331 const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try makePipe() else undefined;339 const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try makePipe() else undefined;
332 errdefer if (self.stdin_behavior == StdIo.Pipe) { destroyPipe(stdin_pipe); };340 errdefer if (self.stdin_behavior == StdIo.Pipe) {
341 destroyPipe(stdin_pipe);
342 };
333343
334 const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try makePipe() else undefined;344 const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try makePipe() else undefined;
335 errdefer if (self.stdout_behavior == StdIo.Pipe) { destroyPipe(stdout_pipe); };345 errdefer if (self.stdout_behavior == StdIo.Pipe) {
346 destroyPipe(stdout_pipe);
347 };
336348
337 const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try makePipe() else undefined;349 const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try makePipe() else undefined;
338 errdefer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };350 errdefer if (self.stderr_behavior == StdIo.Pipe) {
351 destroyPipe(stderr_pipe);
352 };
339353
340 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);354 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
341 const dev_null_fd = if (any_ignore) blk: {355 const dev_null_fd = if (any_ignore) blk: {
...@@ -346,7 +360,9 @@ pub const ChildProcess = struct {...@@ -346,7 +360,9 @@ pub const ChildProcess = struct {
346 } else blk: {360 } else blk: {
347 break :blk undefined;361 break :blk undefined;
348 };362 };
349 defer { if (any_ignore) os.close(dev_null_fd); }363 defer {
364 if (any_ignore) os.close(dev_null_fd);
365 }
350366
351 var env_map_owned: BufMap = undefined;367 var env_map_owned: BufMap = undefined;
352 var we_own_env_map: bool = undefined;368 var we_own_env_map: bool = undefined;
...@@ -358,7 +374,9 @@ pub const ChildProcess = struct {...@@ -358,7 +374,9 @@ pub const ChildProcess = struct {
358 env_map_owned = try os.getEnvMap(self.allocator);374 env_map_owned = try os.getEnvMap(self.allocator);
359 break :x &env_map_owned;375 break :x &env_map_owned;
360 };376 };
361 defer { if (we_own_env_map) env_map_owned.deinit(); }377 defer {
378 if (we_own_env_map) env_map_owned.deinit();
379 }
362380
363 // This pipe is used to communicate errors between the time of fork381 // This pipe is used to communicate errors between the time of fork
364 // and execve from the child process to the parent process.382 // and execve from the child process to the parent process.
...@@ -369,23 +387,21 @@ pub const ChildProcess = struct {...@@ -369,23 +387,21 @@ pub const ChildProcess = struct {
369 const pid_err = posix.getErrno(pid_result);387 const pid_err = posix.getErrno(pid_result);
370 if (pid_err > 0) {388 if (pid_err > 0) {
371 return switch (pid_err) {389 return switch (pid_err) {
372 posix.EAGAIN, posix.ENOMEM, posix.ENOSYS => error.SystemResources,390 posix.EAGAIN,
391 posix.ENOMEM,
392 posix.ENOSYS => error.SystemResources,
373 else => os.unexpectedErrorPosix(pid_err),393 else => os.unexpectedErrorPosix(pid_err),
374 };394 };
375 }395 }
376 if (pid_result == 0) {396 if (pid_result == 0) {
377 // we are the child397 // we are the child
378398
379 setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch399 setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
380 |err| forkChildErrReport(err_pipe[1], err);400 setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
381 setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch401 setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
382 |err| forkChildErrReport(err_pipe[1], err);
383 setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch
384 |err| forkChildErrReport(err_pipe[1], err);
385402
386 if (self.cwd) |cwd| {403 if (self.cwd) |cwd| {
387 os.changeCurDir(self.allocator, cwd) catch404 os.changeCurDir(self.allocator, cwd) catch |err| forkChildErrReport(err_pipe[1], err);
388 |err| forkChildErrReport(err_pipe[1], err);
389 }405 }
390406
391 if (self.gid) |gid| {407 if (self.gid) |gid| {
...@@ -396,8 +412,7 @@ pub const ChildProcess = struct {...@@ -396,8 +412,7 @@ pub const ChildProcess = struct {
396 os.posix_setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);412 os.posix_setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
397 }413 }
398414
399 os.posixExecve(self.argv, env_map, self.allocator) catch415 os.posixExecve(self.argv, env_map, self.allocator) catch |err| forkChildErrReport(err_pipe[1], err);
400 |err| forkChildErrReport(err_pipe[1], err);
401 }416 }
402417
403 // we are the parent418 // we are the parent
...@@ -423,37 +438,41 @@ pub const ChildProcess = struct {...@@ -423,37 +438,41 @@ pub const ChildProcess = struct {
423 self.llnode = LinkedList(&ChildProcess).Node.init(self);438 self.llnode = LinkedList(&ChildProcess).Node.init(self);
424 self.term = null;439 self.term = null;
425440
426 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }441 if (self.stdin_behavior == StdIo.Pipe) {
427 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }442 os.close(stdin_pipe[0]);
428 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }443 }
444 if (self.stdout_behavior == StdIo.Pipe) {
445 os.close(stdout_pipe[1]);
446 }
447 if (self.stderr_behavior == StdIo.Pipe) {
448 os.close(stderr_pipe[1]);
449 }
429 }450 }
430451
431 fn spawnWindows(self: &ChildProcess) !void {452 fn spawnWindows(self: &ChildProcess) !void {
432 const saAttr = windows.SECURITY_ATTRIBUTES {453 const saAttr = windows.SECURITY_ATTRIBUTES{
433 .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),454 .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
434 .bInheritHandle = windows.TRUE,455 .bInheritHandle = windows.TRUE,
435 .lpSecurityDescriptor = null,456 .lpSecurityDescriptor = null,
436 };457 };
437458
438 const any_ignore = (self.stdin_behavior == StdIo.Ignore or459 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
439 self.stdout_behavior == StdIo.Ignore or
440 self.stderr_behavior == StdIo.Ignore);
441460
442 const nul_handle = if (any_ignore) blk: {461 const nul_handle = if (any_ignore) blk: {
443 const nul_file_path = "NUL";462 const nul_file_path = "NUL";
444 var fixed_buffer_mem: [nul_file_path.len + 1]u8 = undefined;463 var fixed_buffer_mem: [nul_file_path.len + 1]u8 = undefined;
445 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);464 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
446 break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,465 break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
447 windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
448 } else blk: {466 } else blk: {
449 break :blk undefined;467 break :blk undefined;
450 };468 };
451 defer { if (any_ignore) os.close(nul_handle); }469 defer {
470 if (any_ignore) os.close(nul_handle);
471 }
452 if (any_ignore) {472 if (any_ignore) {
453 try windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);473 try windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
454 }474 }
455475
456
457 var g_hChildStd_IN_Rd: ?windows.HANDLE = null;476 var g_hChildStd_IN_Rd: ?windows.HANDLE = null;
458 var g_hChildStd_IN_Wr: ?windows.HANDLE = null;477 var g_hChildStd_IN_Wr: ?windows.HANDLE = null;
459 switch (self.stdin_behavior) {478 switch (self.stdin_behavior) {
...@@ -470,7 +489,9 @@ pub const ChildProcess = struct {...@@ -470,7 +489,9 @@ pub const ChildProcess = struct {
470 g_hChildStd_IN_Rd = null;489 g_hChildStd_IN_Rd = null;
471 },490 },
472 }491 }
473 errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr); };492 errdefer if (self.stdin_behavior == StdIo.Pipe) {
493 windowsDestroyPipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr);
494 };
474495
475 var g_hChildStd_OUT_Rd: ?windows.HANDLE = null;496 var g_hChildStd_OUT_Rd: ?windows.HANDLE = null;
476 var g_hChildStd_OUT_Wr: ?windows.HANDLE = null;497 var g_hChildStd_OUT_Wr: ?windows.HANDLE = null;
...@@ -488,7 +509,9 @@ pub const ChildProcess = struct {...@@ -488,7 +509,9 @@ pub const ChildProcess = struct {
488 g_hChildStd_OUT_Wr = null;509 g_hChildStd_OUT_Wr = null;
489 },510 },
490 }511 }
491 errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr); };512 errdefer if (self.stdin_behavior == StdIo.Pipe) {
513 windowsDestroyPipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr);
514 };
492515
493 var g_hChildStd_ERR_Rd: ?windows.HANDLE = null;516 var g_hChildStd_ERR_Rd: ?windows.HANDLE = null;
494 var g_hChildStd_ERR_Wr: ?windows.HANDLE = null;517 var g_hChildStd_ERR_Wr: ?windows.HANDLE = null;
...@@ -506,12 +529,14 @@ pub const ChildProcess = struct {...@@ -506,12 +529,14 @@ pub const ChildProcess = struct {
506 g_hChildStd_ERR_Wr = null;529 g_hChildStd_ERR_Wr = null;
507 },530 },
508 }531 }
509 errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr); };532 errdefer if (self.stdin_behavior == StdIo.Pipe) {
533 windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr);
534 };
510535
511 const cmd_line = try windowsCreateCommandLine(self.allocator, self.argv);536 const cmd_line = try windowsCreateCommandLine(self.allocator, self.argv);
512 defer self.allocator.free(cmd_line);537 defer self.allocator.free(cmd_line);
513538
514 var siStartInfo = windows.STARTUPINFOA {539 var siStartInfo = windows.STARTUPINFOA{
515 .cb = @sizeOf(windows.STARTUPINFOA),540 .cb = @sizeOf(windows.STARTUPINFOA),
516 .hStdError = g_hChildStd_ERR_Wr,541 .hStdError = g_hChildStd_ERR_Wr,
517 .hStdOutput = g_hChildStd_OUT_Wr,542 .hStdOutput = g_hChildStd_OUT_Wr,
...@@ -534,19 +559,11 @@ pub const ChildProcess = struct {...@@ -534,19 +559,11 @@ pub const ChildProcess = struct {
534 };559 };
535 var piProcInfo: windows.PROCESS_INFORMATION = undefined;560 var piProcInfo: windows.PROCESS_INFORMATION = undefined;
536561
537 const cwd_slice = if (self.cwd) |cwd|562 const cwd_slice = if (self.cwd) |cwd| try cstr.addNullByte(self.allocator, cwd) else null;
538 try cstr.addNullByte(self.allocator, cwd)
539 else
540 null
541 ;
542 defer if (cwd_slice) |cwd| self.allocator.free(cwd);563 defer if (cwd_slice) |cwd| self.allocator.free(cwd);
543 const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;564 const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;
544565
545 const maybe_envp_buf = if (self.env_map) |env_map|566 const maybe_envp_buf = if (self.env_map) |env_map| try os.createWindowsEnvBlock(self.allocator, env_map) else null;
546 try os.createWindowsEnvBlock(self.allocator, env_map)
547 else
548 null
549 ;
550 defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);567 defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
551 const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;568 const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;
552569
...@@ -563,11 +580,8 @@ pub const ChildProcess = struct {...@@ -563,11 +580,8 @@ pub const ChildProcess = struct {
563 };580 };
564 defer self.allocator.free(app_name);581 defer self.allocator.free(app_name);
565582
566 windowsCreateProcess(app_name.ptr, cmd_line.ptr, envp_ptr, cwd_ptr,583 windowsCreateProcess(app_name.ptr, cmd_line.ptr, envp_ptr, cwd_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| {
567 &siStartInfo, &piProcInfo) catch |no_path_err|584 if (no_path_err != error.FileNotFound) return no_path_err;
568 {
569 if (no_path_err != error.FileNotFound)
570 return no_path_err;
571585
572 const PATH = try os.getEnvVarOwned(self.allocator, "PATH");586 const PATH = try os.getEnvVarOwned(self.allocator, "PATH");
573 defer self.allocator.free(PATH);587 defer self.allocator.free(PATH);
...@@ -577,9 +591,7 @@ pub const ChildProcess = struct {...@@ -577,9 +591,7 @@ pub const ChildProcess = struct {
577 const joined_path = try os.path.join(self.allocator, search_path, app_name);591 const joined_path = try os.path.join(self.allocator, search_path, app_name);
578 defer self.allocator.free(joined_path);592 defer self.allocator.free(joined_path);
579593
580 if (windowsCreateProcess(joined_path.ptr, cmd_line.ptr, envp_ptr, cwd_ptr,594 if (windowsCreateProcess(joined_path.ptr, cmd_line.ptr, envp_ptr, cwd_ptr, &siStartInfo, &piProcInfo)) |_| {
581 &siStartInfo, &piProcInfo)) |_|
582 {
583 break;595 break;
584 } else |err| if (err == error.FileNotFound) {596 } else |err| if (err == error.FileNotFound) {
585 continue;597 continue;
...@@ -609,9 +621,15 @@ pub const ChildProcess = struct {...@@ -609,9 +621,15 @@ pub const ChildProcess = struct {
609 self.thread_handle = piProcInfo.hThread;621 self.thread_handle = piProcInfo.hThread;
610 self.term = null;622 self.term = null;
611623
612 if (self.stdin_behavior == StdIo.Pipe) { os.close(??g_hChildStd_IN_Rd); }624 if (self.stdin_behavior == StdIo.Pipe) {
613 if (self.stderr_behavior == StdIo.Pipe) { os.close(??g_hChildStd_ERR_Wr); }625 os.close(??g_hChildStd_IN_Rd);
614 if (self.stdout_behavior == StdIo.Pipe) { os.close(??g_hChildStd_OUT_Wr); }626 }
627 if (self.stderr_behavior == StdIo.Pipe) {
628 os.close(??g_hChildStd_ERR_Wr);
629 }
630 if (self.stdout_behavior == StdIo.Pipe) {
631 os.close(??g_hChildStd_OUT_Wr);
632 }
615 }633 }
616634
617 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {635 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {
...@@ -622,18 +640,14 @@ pub const ChildProcess = struct {...@@ -622,18 +640,14 @@ pub const ChildProcess = struct {
622 StdIo.Ignore => try os.posixDup2(dev_null_fd, std_fileno),640 StdIo.Ignore => try os.posixDup2(dev_null_fd, std_fileno),
623 }641 }
624 }642 }
625
626};643};
627644
628fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8,645fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?&u8, lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) !void {
629 lpStartupInfo: &windows.STARTUPINFOA, lpProcessInformation: &windows.PROCESS_INFORMATION) !void646 if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0, @ptrCast(?&c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0) {
630{
631 if (windows.CreateProcessA(app_name, cmd_line, null, null, windows.TRUE, 0,
632 @ptrCast(?&c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation) == 0)
633 {
634 const err = windows.GetLastError();647 const err = windows.GetLastError();
635 return switch (err) {648 return switch (err) {
636 windows.ERROR.FILE_NOT_FOUND, windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,649 windows.ERROR.FILE_NOT_FOUND,
650 windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
637 windows.ERROR.INVALID_PARAMETER => unreachable,651 windows.ERROR.INVALID_PARAMETER => unreachable,
638 windows.ERROR.INVALID_NAME => error.InvalidName,652 windows.ERROR.INVALID_NAME => error.InvalidName,
639 else => os.unexpectedErrorWindows(err),653 else => os.unexpectedErrorWindows(err),
...@@ -641,18 +655,16 @@ fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?...@@ -641,18 +655,16 @@ fn windowsCreateProcess(app_name: &u8, cmd_line: &u8, envp_ptr: ?&u8, cwd_ptr: ?
641 }655 }
642}656}
643657
644
645
646
647/// Caller must dealloc.658/// Caller must dealloc.
648/// Guarantees a null byte at result[result.len].659/// Guarantees a null byte at result[result.len].
649fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8) ![]u8 {660fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8) ![]u8 {
650 var buf = try Buffer.initSize(allocator, 0);661 var buf = try Buffer.initSize(allocator, 0);
651 defer buf.deinit();662 defer buf.deinit();
652663
664 var buf_stream = &io.BufferOutStream.init(&buf).stream;
665
653 for (argv) |arg, arg_i| {666 for (argv) |arg, arg_i| {
654 if (arg_i != 0)667 if (arg_i != 0) try buf.appendByte(' ');
655 try buf.appendByte(' ');
656 if (mem.indexOfAny(u8, arg, " \t\n\"") == null) {668 if (mem.indexOfAny(u8, arg, " \t\n\"") == null) {
657 try buf.append(arg);669 try buf.append(arg);
658 continue;670 continue;
...@@ -663,18 +675,18 @@ fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8)...@@ -663,18 +675,18 @@ fn windowsCreateCommandLine(allocator: &mem.Allocator, argv: []const []const u8)
663 switch (byte) {675 switch (byte) {
664 '\\' => backslash_count += 1,676 '\\' => backslash_count += 1,
665 '"' => {677 '"' => {
666 try buf.appendByteNTimes('\\', backslash_count * 2 + 1);678 try buf_stream.writeByteNTimes('\\', backslash_count * 2 + 1);
667 try buf.appendByte('"');679 try buf.appendByte('"');
668 backslash_count = 0;680 backslash_count = 0;
669 },681 },
670 else => {682 else => {
671 try buf.appendByteNTimes('\\', backslash_count);683 try buf_stream.writeByteNTimes('\\', backslash_count);
672 try buf.appendByte(byte);684 try buf.appendByte(byte);
673 backslash_count = 0;685 backslash_count = 0;
674 },686 },
675 }687 }
676 }688 }
677 try buf.appendByteNTimes('\\', backslash_count * 2);689 try buf_stream.writeByteNTimes('\\', backslash_count * 2);
678 try buf.appendByte('"');690 try buf.appendByte('"');
679 }691 }
680692
...@@ -686,7 +698,6 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {...@@ -686,7 +698,6 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
686 if (wr) |h| os.close(h);698 if (wr) |h| os.close(h);
687}699}
688700
689
690// TODO: workaround for bug where the `const` from `&const` is dropped when the type is701// TODO: workaround for bug where the `const` from `&const` is dropped when the type is
691// a namespace field lookup702// a namespace field lookup
692const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;703const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;
...@@ -715,8 +726,8 @@ fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const S...@@ -715,8 +726,8 @@ fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const S
715 try windowsMakePipe(&rd_h, &wr_h, sattr);726 try windowsMakePipe(&rd_h, &wr_h, sattr);
716 errdefer windowsDestroyPipe(rd_h, wr_h);727 errdefer windowsDestroyPipe(rd_h, wr_h);
717 try windowsSetHandleInfo(wr_h, windows.HANDLE_FLAG_INHERIT, 0);728 try windowsSetHandleInfo(wr_h, windows.HANDLE_FLAG_INHERIT, 0);
718 *rd = rd_h;729 rd.* = rd_h;
719 *wr = wr_h;730 wr.* = wr_h;
720}731}
721732
722fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void {733fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const SECURITY_ATTRIBUTES) !void {
...@@ -725,8 +736,8 @@ fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const...@@ -725,8 +736,8 @@ fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const
725 try windowsMakePipe(&rd_h, &wr_h, sattr);736 try windowsMakePipe(&rd_h, &wr_h, sattr);
726 errdefer windowsDestroyPipe(rd_h, wr_h);737 errdefer windowsDestroyPipe(rd_h, wr_h);
727 try windowsSetHandleInfo(rd_h, windows.HANDLE_FLAG_INHERIT, 0);738 try windowsSetHandleInfo(rd_h, windows.HANDLE_FLAG_INHERIT, 0);
728 *rd = rd_h;739 rd.* = rd_h;
729 *wr = wr_h;740 wr.* = wr_h;
730}741}
731742
732fn makePipe() ![2]i32 {743fn makePipe() ![2]i32 {
...@@ -734,7 +745,8 @@ fn makePipe() ![2]i32 {...@@ -734,7 +745,8 @@ fn makePipe() ![2]i32 {
734 const err = posix.getErrno(posix.pipe(&fds));745 const err = posix.getErrno(posix.pipe(&fds));
735 if (err > 0) {746 if (err > 0) {
736 return switch (err) {747 return switch (err) {
737 posix.EMFILE, posix.ENFILE => error.SystemResources,748 posix.EMFILE,
749 posix.ENFILE => error.SystemResources,
738 else => os.unexpectedErrorPosix(err),750 else => os.unexpectedErrorPosix(err),
739 };751 };
740 }752 }
...@@ -742,8 +754,8 @@ fn makePipe() ![2]i32 {...@@ -742,8 +754,8 @@ fn makePipe() ![2]i32 {
742}754}
743755
744fn destroyPipe(pipe: &const [2]i32) void {756fn destroyPipe(pipe: &const [2]i32) void {
745 os.close((*pipe)[0]);757 os.close((pipe.*)[0]);
746 os.close((*pipe)[1]);758 os.close((pipe.*)[1]);
747}759}
748760
749// Child of fork calls this to report an error to the fork parent.761// Child of fork calls this to report an error to the fork parent.
std/os/darwin.zig+182-100
...@@ -10,33 +10,56 @@ pub const STDIN_FILENO = 0;...@@ -10,33 +10,56 @@ pub const STDIN_FILENO = 0;
10pub const STDOUT_FILENO = 1;10pub const STDOUT_FILENO = 1;
11pub const STDERR_FILENO = 2;11pub const STDERR_FILENO = 2;
1212
13pub const PROT_NONE = 0x00; /// [MC2] no permissions13/// [MC2] no permissions
14pub const PROT_READ = 0x01; /// [MC2] pages can be read14pub const PROT_NONE = 0x00;
15pub const PROT_WRITE = 0x02; /// [MC2] pages can be written15/// [MC2] pages can be read
16pub const PROT_EXEC = 0x04; /// [MC2] pages can be executed16pub const PROT_READ = 0x01;
1717/// [MC2] pages can be written
18pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space18pub const PROT_WRITE = 0x02;
19pub const MAP_FILE = 0x0000; /// map from file (default)19/// [MC2] pages can be executed
20pub const MAP_FIXED = 0x0010; /// interpret addr exactly20pub const PROT_EXEC = 0x04;
21pub const MAP_HASSEMAPHORE = 0x0200; /// region may contain semaphores21
22pub const MAP_PRIVATE = 0x0002; /// changes are private22/// allocated from memory, swap space
23pub const MAP_SHARED = 0x0001; /// share changes23pub const MAP_ANONYMOUS = 0x1000;
24pub const MAP_NOCACHE = 0x0400; /// don't cache pages for this mapping24/// map from file (default)
25pub const MAP_NORESERVE = 0x0040; /// don't reserve needed swap area25pub const MAP_FILE = 0x0000;
26/// interpret addr exactly
27pub const MAP_FIXED = 0x0010;
28/// region may contain semaphores
29pub const MAP_HASSEMAPHORE = 0x0200;
30/// changes are private
31pub const MAP_PRIVATE = 0x0002;
32/// share changes
33pub const MAP_SHARED = 0x0001;
34/// don't cache pages for this mapping
35pub const MAP_NOCACHE = 0x0400;
36/// don't reserve needed swap area
37pub const MAP_NORESERVE = 0x0040;
26pub const MAP_FAILED = @maxValue(usize);38pub const MAP_FAILED = @maxValue(usize);
2739
28pub const WNOHANG = 0x00000001; /// [XSI] no hang in wait/no child to reap40/// [XSI] no hang in wait/no child to reap
29pub const WUNTRACED = 0x00000002; /// [XSI] notify on stop, untraced child41pub const WNOHANG = 0x00000001;
3042/// [XSI] notify on stop, untraced child
31pub const SA_ONSTACK = 0x0001; /// take signal on signal stack43pub const WUNTRACED = 0x00000002;
32pub const SA_RESTART = 0x0002; /// restart system on signal return44
33pub const SA_RESETHAND = 0x0004; /// reset to SIG_DFL when taking signal45/// take signal on signal stack
34pub const SA_NOCLDSTOP = 0x0008; /// do not generate SIGCHLD on child stop46pub const SA_ONSTACK = 0x0001;
35pub const SA_NODEFER = 0x0010; /// don't mask the signal we're delivering47/// restart system on signal return
36pub const SA_NOCLDWAIT = 0x0020; /// don't keep zombies around48pub const SA_RESTART = 0x0002;
37pub const SA_SIGINFO = 0x0040; /// signal handler with SA_SIGINFO args49/// reset to SIG_DFL when taking signal
38pub const SA_USERTRAMP = 0x0100; /// do not bounce off kernel's sigtramp50pub const SA_RESETHAND = 0x0004;
39pub const SA_64REGSET = 0x0200; /// signal handler with SA_SIGINFO args with 64bit regs information51/// do not generate SIGCHLD on child stop
52pub const SA_NOCLDSTOP = 0x0008;
53/// don't mask the signal we're delivering
54pub const SA_NODEFER = 0x0010;
55/// don't keep zombies around
56pub const SA_NOCLDWAIT = 0x0020;
57/// signal handler with SA_SIGINFO args
58pub const SA_SIGINFO = 0x0040;
59/// do not bounce off kernel's sigtramp
60pub const SA_USERTRAMP = 0x0100;
61/// signal handler with SA_SIGINFO args with 64bit regs information
62pub const SA_64REGSET = 0x0200;
4063
41pub const O_LARGEFILE = 0x0000;64pub const O_LARGEFILE = 0x0000;
42pub const O_PATH = 0x0000;65pub const O_PATH = 0x0000;
...@@ -46,20 +69,34 @@ pub const X_OK = 1;...@@ -46,20 +69,34 @@ pub const X_OK = 1;
46pub const W_OK = 2;69pub const W_OK = 2;
47pub const R_OK = 4;70pub const R_OK = 4;
4871
49pub const O_RDONLY = 0x0000; /// open for reading only72/// open for reading only
50pub const O_WRONLY = 0x0001; /// open for writing only73pub const O_RDONLY = 0x0000;
51pub const O_RDWR = 0x0002; /// open for reading and writing74/// open for writing only
52pub const O_NONBLOCK = 0x0004; /// do not block on open or for data to become available75pub const O_WRONLY = 0x0001;
53pub const O_APPEND = 0x0008; /// append on each write76/// open for reading and writing
54pub const O_CREAT = 0x0200; /// create file if it does not exist77pub const O_RDWR = 0x0002;
55pub const O_TRUNC = 0x0400; /// truncate size to 078/// do not block on open or for data to become available
56pub const O_EXCL = 0x0800; /// error if O_CREAT and the file exists79pub const O_NONBLOCK = 0x0004;
57pub const O_SHLOCK = 0x0010; /// atomically obtain a shared lock80/// append on each write
58pub const O_EXLOCK = 0x0020; /// atomically obtain an exclusive lock81pub const O_APPEND = 0x0008;
59pub const O_NOFOLLOW = 0x0100; /// do not follow symlinks82/// create file if it does not exist
60pub const O_SYMLINK = 0x200000; /// allow open of symlinks83pub const O_CREAT = 0x0200;
61pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only84/// truncate size to 0
62pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec85pub const O_TRUNC = 0x0400;
86/// error if O_CREAT and the file exists
87pub const O_EXCL = 0x0800;
88/// atomically obtain a shared lock
89pub const O_SHLOCK = 0x0010;
90/// atomically obtain an exclusive lock
91pub const O_EXLOCK = 0x0020;
92/// do not follow symlinks
93pub const O_NOFOLLOW = 0x0100;
94/// allow open of symlinks
95pub const O_SYMLINK = 0x200000;
96/// descriptor requested for event notifications only
97pub const O_EVTONLY = 0x8000;
98/// mark as close-on-exec
99pub const O_CLOEXEC = 0x1000000;
63100
64pub const O_ACCMODE = 3;101pub const O_ACCMODE = 3;
65pub const O_ALERT = 536870912;102pub const O_ALERT = 536870912;
...@@ -87,52 +124,102 @@ pub const DT_LNK = 10;...@@ -87,52 +124,102 @@ pub const DT_LNK = 10;
87pub const DT_SOCK = 12;124pub const DT_SOCK = 12;
88pub const DT_WHT = 14;125pub const DT_WHT = 14;
89126
90pub const SIG_BLOCK = 1; /// block specified signal set127/// block specified signal set
91pub const SIG_UNBLOCK = 2; /// unblock specified signal set128pub const SIG_BLOCK = 1;
92pub const SIG_SETMASK = 3; /// set specified signal set129/// unblock specified signal set
93130pub const SIG_UNBLOCK = 2;
94pub const SIGHUP = 1; /// hangup131/// set specified signal set
95pub const SIGINT = 2; /// interrupt132pub const SIG_SETMASK = 3;
96pub const SIGQUIT = 3; /// quit133
97pub const SIGILL = 4; /// illegal instruction (not reset when caught)134/// hangup
98pub const SIGTRAP = 5; /// trace trap (not reset when caught)135pub const SIGHUP = 1;
99pub const SIGABRT = 6; /// abort()136/// interrupt
100pub const SIGPOLL = 7; /// pollable event ([XSR] generated, not supported)137pub const SIGINT = 2;
101pub const SIGIOT = SIGABRT; /// compatibility138/// quit
102pub const SIGEMT = 7; /// EMT instruction139pub const SIGQUIT = 3;
103pub const SIGFPE = 8; /// floating point exception140/// illegal instruction (not reset when caught)
104pub const SIGKILL = 9; /// kill (cannot be caught or ignored)141pub const SIGILL = 4;
105pub const SIGBUS = 10; /// bus error142/// trace trap (not reset when caught)
106pub const SIGSEGV = 11; /// segmentation violation143pub const SIGTRAP = 5;
107pub const SIGSYS = 12; /// bad argument to system call144/// abort()
108pub const SIGPIPE = 13; /// write on a pipe with no one to read it145pub const SIGABRT = 6;
109pub const SIGALRM = 14; /// alarm clock146/// pollable event ([XSR] generated, not supported)
110pub const SIGTERM = 15; /// software termination signal from kill147pub const SIGPOLL = 7;
111pub const SIGURG = 16; /// urgent condition on IO channel148/// compatibility
112pub const SIGSTOP = 17; /// sendable stop signal not from tty149pub const SIGIOT = SIGABRT;
113pub const SIGTSTP = 18; /// stop signal from tty150/// EMT instruction
114pub const SIGCONT = 19; /// continue a stopped process151pub const SIGEMT = 7;
115pub const SIGCHLD = 20; /// to parent on child stop or exit152/// floating point exception
116pub const SIGTTIN = 21; /// to readers pgrp upon background tty read153pub const SIGFPE = 8;
117pub const SIGTTOU = 22; /// like TTIN for output if (tp->t_local&LTOSTOP)154/// kill (cannot be caught or ignored)
118pub const SIGIO = 23; /// input/output possible signal155pub const SIGKILL = 9;
119pub const SIGXCPU = 24; /// exceeded CPU time limit156/// bus error
120pub const SIGXFSZ = 25; /// exceeded file size limit157pub const SIGBUS = 10;
121pub const SIGVTALRM = 26; /// virtual time alarm158/// segmentation violation
122pub const SIGPROF = 27; /// profiling time alarm159pub const SIGSEGV = 11;
123pub const SIGWINCH = 28; /// window size changes160/// bad argument to system call
124pub const SIGINFO = 29; /// information request161pub const SIGSYS = 12;
125pub const SIGUSR1 = 30; /// user defined signal 1162/// write on a pipe with no one to read it
126pub const SIGUSR2 = 31; /// user defined signal 2163pub const SIGPIPE = 13;
127164/// alarm clock
128fn wstatus(x: i32) i32 { return x & 0o177; }165pub const SIGALRM = 14;
166/// software termination signal from kill
167pub const SIGTERM = 15;
168/// urgent condition on IO channel
169pub const SIGURG = 16;
170/// sendable stop signal not from tty
171pub const SIGSTOP = 17;
172/// stop signal from tty
173pub const SIGTSTP = 18;
174/// continue a stopped process
175pub const SIGCONT = 19;
176/// to parent on child stop or exit
177pub const SIGCHLD = 20;
178/// to readers pgrp upon background tty read
179pub const SIGTTIN = 21;
180/// like TTIN for output if (tp->t_local&LTOSTOP)
181pub const SIGTTOU = 22;
182/// input/output possible signal
183pub const SIGIO = 23;
184/// exceeded CPU time limit
185pub const SIGXCPU = 24;
186/// exceeded file size limit
187pub const SIGXFSZ = 25;
188/// virtual time alarm
189pub const SIGVTALRM = 26;
190/// profiling time alarm
191pub const SIGPROF = 27;
192/// window size changes
193pub const SIGWINCH = 28;
194/// information request
195pub const SIGINFO = 29;
196/// user defined signal 1
197pub const SIGUSR1 = 30;
198/// user defined signal 2
199pub const SIGUSR2 = 31;
200
201fn wstatus(x: i32) i32 {
202 return x & 0o177;
203}
129const wstopped = 0o177;204const wstopped = 0o177;
130pub fn WEXITSTATUS(x: i32) i32 { return x >> 8; }205pub fn WEXITSTATUS(x: i32) i32 {
131pub fn WTERMSIG(x: i32) i32 { return wstatus(x); }206 return x >> 8;
132pub fn WSTOPSIG(x: i32) i32 { return x >> 8; }207}
133pub fn WIFEXITED(x: i32) bool { return wstatus(x) == 0; }208pub fn WTERMSIG(x: i32) i32 {
134pub fn WIFSTOPPED(x: i32) bool { return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; }209 return wstatus(x);
135pub fn WIFSIGNALED(x: i32) bool { return wstatus(x) != wstopped and wstatus(x) != 0; }210}
211pub fn WSTOPSIG(x: i32) i32 {
212 return x >> 8;
213}
214pub fn WIFEXITED(x: i32) bool {
215 return wstatus(x) == 0;
216}
217pub fn WIFSTOPPED(x: i32) bool {
218 return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13;
219}
220pub fn WIFSIGNALED(x: i32) bool {
221 return wstatus(x) != wstopped and wstatus(x) != 0;
222}
136223
137/// Get the errno from a syscall return value, or 0 for no error.224/// Get the errno from a syscall return value, or 0 for no error.
138pub fn getErrno(r: usize) usize {225pub fn getErrno(r: usize) usize {
...@@ -184,11 +271,8 @@ pub fn write(fd: i32, buf: &const u8, nbyte: usize) usize {...@@ -184,11 +271,8 @@ pub fn write(fd: i32, buf: &const u8, nbyte: usize) usize {
184 return errnoWrap(c.write(fd, @ptrCast(&const c_void, buf), nbyte));271 return errnoWrap(c.write(fd, @ptrCast(&const c_void, buf), nbyte));
185}272}
186273
187pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: u32, fd: i32,274pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
188 offset: isize) usize275 const ptr_result = c.mmap(@ptrCast(&c_void, address), length, @bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset);
189{
190 const ptr_result = c.mmap(@ptrCast(&c_void, address), length,
191 @bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset);
192 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));276 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
193 return errnoWrap(isize_result);277 return errnoWrap(isize_result);
194}278}
...@@ -202,7 +286,7 @@ pub fn unlink(path: &const u8) usize {...@@ -202,7 +286,7 @@ pub fn unlink(path: &const u8) usize {
202}286}
203287
204pub fn getcwd(buf: &u8, size: usize) usize {288pub fn getcwd(buf: &u8, size: usize) usize {
205 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0;289 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
206}290}
207291
208pub fn waitpid(pid: i32, status: &i32, options: u32) usize {292pub fn waitpid(pid: i32, status: &i32, options: u32) usize {
...@@ -223,7 +307,6 @@ pub fn pipe(fds: &[2]i32) usize {...@@ -223,7 +307,6 @@ pub fn pipe(fds: &[2]i32) usize {
223 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));307 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
224}308}
225309
226
227pub fn getdirentries64(fd: i32, buf_ptr: &u8, buf_len: usize, basep: &i64) usize {310pub fn getdirentries64(fd: i32, buf_ptr: &u8, buf_len: usize, basep: &i64) usize {
228 return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep)));311 return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep)));
229}312}
...@@ -269,7 +352,7 @@ pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {...@@ -269,7 +352,7 @@ pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {
269}352}
270353
271pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) usize {354pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) usize {
272 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0;355 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
273}356}
274357
275pub fn setreuid(ruid: u32, euid: u32) usize {358pub fn setreuid(ruid: u32, euid: u32) usize {
...@@ -287,8 +370,8 @@ pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&s...@@ -287,8 +370,8 @@ pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&s
287pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {370pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {
288 assert(sig != SIGKILL);371 assert(sig != SIGKILL);
289 assert(sig != SIGSTOP);372 assert(sig != SIGSTOP);
290 var cact = c.Sigaction {373 var cact = c.Sigaction{
291 .handler = @ptrCast(extern fn(c_int)void, act.handler),374 .handler = @ptrCast(extern fn(c_int) void, act.handler),
292 .sa_flags = @bitCast(c_int, act.flags),375 .sa_flags = @bitCast(c_int, act.flags),
293 .sa_mask = act.mask,376 .sa_mask = act.mask,
294 };377 };
...@@ -298,8 +381,8 @@ pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigacti...@@ -298,8 +381,8 @@ pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigacti
298 return result;381 return result;
299 }382 }
300 if (oact) |old| {383 if (oact) |old| {
301 *old = Sigaction {384 old.* = Sigaction{
302 .handler = @ptrCast(extern fn(i32)void, coact.handler),385 .handler = @ptrCast(extern fn(i32) void, coact.handler),
303 .flags = @bitCast(u32, coact.sa_flags),386 .flags = @bitCast(u32, coact.sa_flags),
304 .mask = coact.sa_mask,387 .mask = coact.sa_mask,
305 };388 };
...@@ -319,23 +402,22 @@ pub const sockaddr = c.sockaddr;...@@ -319,23 +402,22 @@ pub const sockaddr = c.sockaddr;
319402
320/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.403/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
321pub const Sigaction = struct {404pub const Sigaction = struct {
322 handler: extern fn(i32)void,405 handler: extern fn(i32) void,
323 mask: sigset_t,406 mask: sigset_t,
324 flags: u32,407 flags: u32,
325};408};
326409
327pub fn sigaddset(set: &sigset_t, signo: u5) void {410pub fn sigaddset(set: &sigset_t, signo: u5) void {
328 *set |= u32(1) << (signo - 1);411 set.* |= u32(1) << (signo - 1);
329}412}
330413
331/// Takes the return value from a syscall and formats it back in the way414/// Takes the return value from a syscall and formats it back in the way
332/// that the kernel represents it to libc. Errno was a mistake, let's make415/// that the kernel represents it to libc. Errno was a mistake, let's make
333/// it go away forever.416/// it go away forever.
334fn errnoWrap(value: isize) usize {417fn errnoWrap(value: isize) usize {
335 return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value);418 return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
336}419}
337420
338
339pub const timezone = c.timezone;421pub const timezone = c.timezone;
340pub const timeval = c.timeval;422pub const timeval = c.timeval;
341pub const mach_timebase_info_data = c.mach_timebase_info_data;423pub const mach_timebase_info_data = c.mach_timebase_info_data;
std/os/index.zig+41-45
...@@ -137,7 +137,7 @@ pub fn getRandomBytes(buf: []u8) !void {...@@ -137,7 +137,7 @@ pub fn getRandomBytes(buf: []u8) !void {
137 }137 }
138 },138 },
139 Os.zen => {139 Os.zen => {
140 const randomness = []u8 {140 const randomness = []u8{
141 42,141 42,
142 1,142 1,
143 7,143 7,
...@@ -239,7 +239,7 @@ pub fn close(handle: FileHandle) void {...@@ -239,7 +239,7 @@ pub fn close(handle: FileHandle) void {
239/// Calls POSIX read, and keeps trying if it gets interrupted.239/// Calls POSIX read, and keeps trying if it gets interrupted.
240pub fn posixRead(fd: i32, buf: []u8) !void {240pub fn posixRead(fd: i32, buf: []u8) !void {
241 // Linux can return EINVAL when read amount is > 0x7ffff000241 // Linux can return EINVAL when read amount is > 0x7ffff000
242 // See https://github.com/zig-lang/zig/pull/743#issuecomment-363158274242 // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
243 const max_buf_len = 0x7ffff000;243 const max_buf_len = 0x7ffff000;
244244
245 var index: usize = 0;245 var index: usize = 0;
...@@ -265,7 +265,7 @@ pub fn posixRead(fd: i32, buf: []u8) !void {...@@ -265,7 +265,7 @@ pub fn posixRead(fd: i32, buf: []u8) !void {
265 }265 }
266}266}
267267
268pub const PosixWriteError = error {268pub const PosixWriteError = error{
269 WouldBlock,269 WouldBlock,
270 FileClosed,270 FileClosed,
271 DestinationAddressRequired,271 DestinationAddressRequired,
...@@ -281,7 +281,7 @@ pub const PosixWriteError = error {...@@ -281,7 +281,7 @@ pub const PosixWriteError = error {
281/// Calls POSIX write, and keeps trying if it gets interrupted.281/// Calls POSIX write, and keeps trying if it gets interrupted.
282pub fn posixWrite(fd: i32, bytes: []const u8) !void {282pub fn posixWrite(fd: i32, bytes: []const u8) !void {
283 // Linux can return EINVAL when write amount is > 0x7ffff000283 // Linux can return EINVAL when write amount is > 0x7ffff000
284 // See https://github.com/zig-lang/zig/pull/743#issuecomment-363165856284 // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
285 const max_bytes_len = 0x7ffff000;285 const max_bytes_len = 0x7ffff000;
286286
287 var index: usize = 0;287 var index: usize = 0;
...@@ -310,7 +310,7 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void {...@@ -310,7 +310,7 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void {
310 }310 }
311}311}
312312
313pub const PosixOpenError = error {313pub const PosixOpenError = error{
314 OutOfMemory,314 OutOfMemory,
315 AccessDenied,315 AccessDenied,
316 FileTooBig,316 FileTooBig,
...@@ -477,7 +477,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap, allocator:...@@ -477,7 +477,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap, allocator:
477 return posixExecveErrnoToErr(err);477 return posixExecveErrnoToErr(err);
478}478}
479479
480pub const PosixExecveError = error {480pub const PosixExecveError = error{
481 SystemResources,481 SystemResources,
482 AccessDenied,482 AccessDenied,
483 InvalidExe,483 InvalidExe,
...@@ -512,7 +512,7 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError {...@@ -512,7 +512,7 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError {
512 };512 };
513}513}
514514
515pub var linux_aux_raw = []usize {0} ** 38;515pub var linux_aux_raw = []usize{0} ** 38;
516pub var posix_environ_raw: []&u8 = undefined;516pub var posix_environ_raw: []&u8 = undefined;
517517
518/// Caller must free result when done.518/// Caller must free result when done.
...@@ -667,7 +667,7 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con...@@ -667,7 +667,7 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con
667 }667 }
668}668}
669669
670pub const WindowsSymLinkError = error {670pub const WindowsSymLinkError = error{
671 OutOfMemory,671 OutOfMemory,
672 Unexpected,672 Unexpected,
673};673};
...@@ -686,7 +686,7 @@ pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path...@@ -686,7 +686,7 @@ pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path
686 }686 }
687}687}
688688
689pub const PosixSymLinkError = error {689pub const PosixSymLinkError = error{
690 OutOfMemory,690 OutOfMemory,
691 AccessDenied,691 AccessDenied,
692 DiskQuota,692 DiskQuota,
...@@ -895,7 +895,7 @@ pub const AtomicFile = struct {...@@ -895,7 +895,7 @@ pub const AtomicFile = struct {
895 else => return err,895 else => return err,
896 };896 };
897897
898 return AtomicFile {898 return AtomicFile{
899 .allocator = allocator,899 .allocator = allocator,
900 .file = file,900 .file = file,
901 .tmp_path = tmp_path,901 .tmp_path = tmp_path,
...@@ -1087,7 +1087,7 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void {...@@ -1087,7 +1087,7 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void {
1087/// removes it. If it cannot be removed because it is a non-empty directory,1087/// removes it. If it cannot be removed because it is a non-empty directory,
1088/// this function recursively removes its entries and then tries again.1088/// this function recursively removes its entries and then tries again.
1089/// TODO non-recursive implementation1089/// TODO non-recursive implementation
1090const DeleteTreeError = error {1090const DeleteTreeError = error{
1091 OutOfMemory,1091 OutOfMemory,
1092 AccessDenied,1092 AccessDenied,
1093 FileTooBig,1093 FileTooBig,
...@@ -1217,7 +1217,7 @@ pub const Dir = struct {...@@ -1217,7 +1217,7 @@ pub const Dir = struct {
1217 Os.ios => 0,1217 Os.ios => 0,
1218 else => {},1218 else => {},
1219 };1219 };
1220 return Dir {1220 return Dir{
1221 .allocator = allocator,1221 .allocator = allocator,
1222 .fd = fd,1222 .fd = fd,
1223 .darwin_seek = darwin_seek_init,1223 .darwin_seek = darwin_seek_init,
...@@ -1294,7 +1294,7 @@ pub const Dir = struct {...@@ -1294,7 +1294,7 @@ pub const Dir = struct {
1294 posix.DT_WHT => Entry.Kind.Whiteout,1294 posix.DT_WHT => Entry.Kind.Whiteout,
1295 else => Entry.Kind.Unknown,1295 else => Entry.Kind.Unknown,
1296 };1296 };
1297 return Entry {1297 return Entry{
1298 .name = name,1298 .name = name,
1299 .kind = entry_kind,1299 .kind = entry_kind,
1300 };1300 };
...@@ -1355,7 +1355,7 @@ pub const Dir = struct {...@@ -1355,7 +1355,7 @@ pub const Dir = struct {
1355 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,1355 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1356 else => Entry.Kind.Unknown,1356 else => Entry.Kind.Unknown,
1357 };1357 };
1358 return Entry {1358 return Entry{
1359 .name = name,1359 .name = name,
1360 .kind = entry_kind,1360 .kind = entry_kind,
1361 };1361 };
...@@ -1465,7 +1465,7 @@ pub fn posix_setregid(rgid: u32, egid: u32) !void {...@@ -1465,7 +1465,7 @@ pub fn posix_setregid(rgid: u32, egid: u32) !void {
1465 };1465 };
1466}1466}
14671467
1468pub const WindowsGetStdHandleErrs = error {1468pub const WindowsGetStdHandleErrs = error{
1469 NoStdHandles,1469 NoStdHandles,
1470 Unexpected,1470 Unexpected,
1471};1471};
...@@ -1489,7 +1489,7 @@ pub const ArgIteratorPosix = struct {...@@ -1489,7 +1489,7 @@ pub const ArgIteratorPosix = struct {
1489 count: usize,1489 count: usize,
14901490
1491 pub fn init() ArgIteratorPosix {1491 pub fn init() ArgIteratorPosix {
1492 return ArgIteratorPosix {1492 return ArgIteratorPosix{
1493 .index = 0,1493 .index = 0,
1494 .count = raw.len,1494 .count = raw.len,
1495 };1495 };
...@@ -1522,16 +1522,14 @@ pub const ArgIteratorWindows = struct {...@@ -1522,16 +1522,14 @@ pub const ArgIteratorWindows = struct {
1522 quote_count: usize,1522 quote_count: usize,
1523 seen_quote_count: usize,1523 seen_quote_count: usize,
15241524
1525 pub const NextError = error {1525 pub const NextError = error{OutOfMemory};
1526 OutOfMemory,
1527 };
15281526
1529 pub fn init() ArgIteratorWindows {1527 pub fn init() ArgIteratorWindows {
1530 return initWithCmdLine(windows.GetCommandLineA());1528 return initWithCmdLine(windows.GetCommandLineA());
1531 }1529 }
15321530
1533 pub fn initWithCmdLine(cmd_line: &const u8) ArgIteratorWindows {1531 pub fn initWithCmdLine(cmd_line: &const u8) ArgIteratorWindows {
1534 return ArgIteratorWindows {1532 return ArgIteratorWindows{
1535 .index = 0,1533 .index = 0,
1536 .cmd_line = cmd_line,1534 .cmd_line = cmd_line,
1537 .in_quote = false,1535 .in_quote = false,
...@@ -1676,9 +1674,7 @@ pub const ArgIterator = struct {...@@ -1676,9 +1674,7 @@ pub const ArgIterator = struct {
1676 inner: InnerType,1674 inner: InnerType,
16771675
1678 pub fn init() ArgIterator {1676 pub fn init() ArgIterator {
1679 return ArgIterator {1677 return ArgIterator{ .inner = InnerType.init() };
1680 .inner = InnerType.init(),
1681 };
1682 }1678 }
16831679
1684 pub const NextError = ArgIteratorWindows.NextError;1680 pub const NextError = ArgIteratorWindows.NextError;
...@@ -1757,33 +1753,33 @@ pub fn argsFree(allocator: &mem.Allocator, args_alloc: []const []u8) void {...@@ -1757,33 +1753,33 @@ pub fn argsFree(allocator: &mem.Allocator, args_alloc: []const []u8) void {
1757}1753}
17581754
1759test "windows arg parsing" {1755test "windows arg parsing" {
1760 testWindowsCmdLine(c"a b\tc d", [][]const u8 {1756 testWindowsCmdLine(c"a b\tc d", [][]const u8{
1761 "a",1757 "a",
1762 "b",1758 "b",
1763 "c",1759 "c",
1764 "d",1760 "d",
1765 });1761 });
1766 testWindowsCmdLine(c"\"abc\" d e", [][]const u8 {1762 testWindowsCmdLine(c"\"abc\" d e", [][]const u8{
1767 "abc",1763 "abc",
1768 "d",1764 "d",
1769 "e",1765 "e",
1770 });1766 });
1771 testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8 {1767 testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{
1772 "a\\\\\\b",1768 "a\\\\\\b",
1773 "de fg",1769 "de fg",
1774 "h",1770 "h",
1775 });1771 });
1776 testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8 {1772 testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{
1777 "a\\\"b",1773 "a\\\"b",
1778 "c",1774 "c",
1779 "d",1775 "d",
1780 });1776 });
1781 testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8 {1777 testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{
1782 "a\\\\b c",1778 "a\\\\b c",
1783 "d",1779 "d",
1784 "e",1780 "e",
1785 });1781 });
1786 testWindowsCmdLine(c"a b\tc \"d f", [][]const u8 {1782 testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{
1787 "a",1783 "a",
1788 "b",1784 "b",
1789 "c",1785 "c",
...@@ -1791,7 +1787,7 @@ test "windows arg parsing" {...@@ -1791,7 +1787,7 @@ test "windows arg parsing" {
1791 "f",1787 "f",
1792 });1788 });
17931789
1794 testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8 {1790 testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
1795 ".\\..\\zig-cache\\build",1791 ".\\..\\zig-cache\\build",
1796 "bin\\zig.exe",1792 "bin\\zig.exe",
1797 ".\\..",1793 ".\\..",
...@@ -1811,7 +1807,7 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const...@@ -1811,7 +1807,7 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const
18111807
1812// TODO make this a build variable that you can set1808// TODO make this a build variable that you can set
1813const unexpected_error_tracing = false;1809const unexpected_error_tracing = false;
1814const UnexpectedError = error {1810const UnexpectedError = error{
1815 /// The Operating System returned an undocumented error code.1811 /// The Operating System returned an undocumented error code.
1816 Unexpected,1812 Unexpected,
1817};1813};
...@@ -1950,7 +1946,7 @@ pub fn isTty(handle: FileHandle) bool {...@@ -1950,7 +1946,7 @@ pub fn isTty(handle: FileHandle) bool {
1950 }1946 }
1951}1947}
19521948
1953pub const PosixSocketError = error {1949pub const PosixSocketError = error{
1954 /// Permission to create a socket of the specified type and/or1950 /// Permission to create a socket of the specified type and/or
1955 /// pro‐tocol is denied.1951 /// pro‐tocol is denied.
1956 PermissionDenied,1952 PermissionDenied,
...@@ -1992,7 +1988,7 @@ pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {...@@ -1992,7 +1988,7 @@ pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
1992 }1988 }
1993}1989}
19941990
1995pub const PosixBindError = error {1991pub const PosixBindError = error{
1996 /// The address is protected, and the user is not the superuser.1992 /// The address is protected, and the user is not the superuser.
1997 /// For UNIX domain sockets: Search permission is denied on a component 1993 /// For UNIX domain sockets: Search permission is denied on a component
1998 /// of the path prefix.1994 /// of the path prefix.
...@@ -2065,7 +2061,7 @@ pub fn posixBind(fd: i32, addr: &const posix.sockaddr) PosixBindError!void {...@@ -2065,7 +2061,7 @@ pub fn posixBind(fd: i32, addr: &const posix.sockaddr) PosixBindError!void {
2065 }2061 }
2066}2062}
20672063
2068const PosixListenError = error {2064const PosixListenError = error{
2069 /// Another socket is already listening on the same port.2065 /// Another socket is already listening on the same port.
2070 /// For Internet domain sockets, the socket referred to by sockfd had not previously2066 /// For Internet domain sockets, the socket referred to by sockfd had not previously
2071 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it2067 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
...@@ -2098,7 +2094,7 @@ pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {...@@ -2098,7 +2094,7 @@ pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
2098 }2094 }
2099}2095}
21002096
2101pub const PosixAcceptError = error {2097pub const PosixAcceptError = error{
2102 /// The socket is marked nonblocking and no connections are present to be accepted.2098 /// The socket is marked nonblocking and no connections are present to be accepted.
2103 WouldBlock,2099 WouldBlock,
21042100
...@@ -2165,7 +2161,7 @@ pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!...@@ -2165,7 +2161,7 @@ pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!
2165 }2161 }
2166}2162}
21672163
2168pub const LinuxEpollCreateError = error {2164pub const LinuxEpollCreateError = error{
2169 /// Invalid value specified in flags.2165 /// Invalid value specified in flags.
2170 InvalidSyscall,2166 InvalidSyscall,
21712167
...@@ -2198,7 +2194,7 @@ pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {...@@ -2198,7 +2194,7 @@ pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
2198 }2194 }
2199}2195}
22002196
2201pub const LinuxEpollCtlError = error {2197pub const LinuxEpollCtlError = error{
2202 /// epfd or fd is not a valid file descriptor.2198 /// epfd or fd is not a valid file descriptor.
2203 InvalidFileDescriptor,2199 InvalidFileDescriptor,
22042200
...@@ -2271,7 +2267,7 @@ pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usiz...@@ -2271,7 +2267,7 @@ pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usiz
2271 }2267 }
2272}2268}
22732269
2274pub const PosixGetSockNameError = error {2270pub const PosixGetSockNameError = error{
2275 /// Insufficient resources were available in the system to perform the operation.2271 /// Insufficient resources were available in the system to perform the operation.
2276 SystemResources,2272 SystemResources,
22772273
...@@ -2295,7 +2291,7 @@ pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {...@@ -2295,7 +2291,7 @@ pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
2295 }2291 }
2296}2292}
22972293
2298pub const PosixConnectError = error {2294pub const PosixConnectError = error{
2299 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket2295 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
2300 /// file, or search permission is denied for one of the directories in the path prefix.2296 /// file, or search permission is denied for one of the directories in the path prefix.
2301 /// or2297 /// or
...@@ -2485,7 +2481,7 @@ pub const Thread = struct {...@@ -2485,7 +2481,7 @@ pub const Thread = struct {
2485 }2481 }
2486};2482};
24872483
2488pub const SpawnThreadError = error {2484pub const SpawnThreadError = error{
2489 /// A system-imposed limit on the number of threads was encountered.2485 /// A system-imposed limit on the number of threads was encountered.
2490 /// There are a number of limits that may trigger this error:2486 /// There are a number of limits that may trigger this error:
2491 /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),2487 /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
...@@ -2517,7 +2513,7 @@ pub const SpawnThreadError = error {...@@ -2517,7 +2513,7 @@ pub const SpawnThreadError = error {
2517/// caller must call wait on the returned thread2513/// caller must call wait on the returned thread
2518pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread {2514pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread {
2519 // TODO compile-time call graph analysis to determine stack upper bound2515 // TODO compile-time call graph analysis to determine stack upper bound
2520 // https://github.com/zig-lang/zig/issues/1572516 // https://github.com/ziglang/zig/issues/157
2521 const default_stack_size = 8 * 1024 * 1024;2517 const default_stack_size = 8 * 1024 * 1024;
25222518
2523 const Context = @typeOf(context);2519 const Context = @typeOf(context);
...@@ -2533,7 +2529,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread...@@ -2533,7 +2529,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread
2533 if (@sizeOf(Context) == 0) {2529 if (@sizeOf(Context) == 0) {
2534 return startFn({});2530 return startFn({});
2535 } else {2531 } else {
2536 return startFn(*@ptrCast(&Context, @alignCast(@alignOf(Context), arg)));2532 return startFn(@ptrCast(&Context, @alignCast(@alignOf(Context), arg)).*);
2537 }2533 }
2538 }2534 }
2539 };2535 };
...@@ -2563,7 +2559,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread...@@ -2563,7 +2559,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread
2563 if (@sizeOf(Context) == 0) {2559 if (@sizeOf(Context) == 0) {
2564 return startFn({});2560 return startFn({});
2565 } else {2561 } else {
2566 return startFn(*@intToPtr(&const Context, ctx_addr));2562 return startFn(@intToPtr(&const Context, ctx_addr).*);
2567 }2563 }
2568 }2564 }
2569 extern fn posixThreadMain(ctx: ?&c_void) ?&c_void {2565 extern fn posixThreadMain(ctx: ?&c_void) ?&c_void {
...@@ -2571,7 +2567,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread...@@ -2571,7 +2567,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread
2571 _ = startFn({});2567 _ = startFn({});
2572 return null;2568 return null;
2573 } else {2569 } else {
2574 _ = startFn(*@ptrCast(&const Context, @alignCast(@alignOf(Context), ctx)));2570 _ = startFn(@ptrCast(&const Context, @alignCast(@alignOf(Context), ctx)).*);
2575 return null;2571 return null;
2576 }2572 }
2577 }2573 }
...@@ -2591,7 +2587,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread...@@ -2591,7 +2587,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread
2591 stack_end -= stack_end % @alignOf(Context);2587 stack_end -= stack_end % @alignOf(Context);
2592 assert(stack_end >= stack_addr);2588 assert(stack_end >= stack_addr);
2593 const context_ptr = @alignCast(@alignOf(Context), @intToPtr(&Context, stack_end));2589 const context_ptr = @alignCast(@alignOf(Context), @intToPtr(&Context, stack_end));
2594 *context_ptr = context;2590 context_ptr.* = context;
2595 arg = stack_end;2591 arg = stack_end;
2596 }2592 }
25972593
std/os/linux/index.zig+189-190
...@@ -30,96 +30,95 @@ pub const FUTEX_PRIVATE_FLAG = 128;...@@ -30,96 +30,95 @@ pub const FUTEX_PRIVATE_FLAG = 128;
3030
31pub const FUTEX_CLOCK_REALTIME = 256;31pub const FUTEX_CLOCK_REALTIME = 256;
3232
3333pub const PROT_NONE = 0;
34pub const PROT_NONE = 0;34pub const PROT_READ = 1;
35pub const PROT_READ = 1;35pub const PROT_WRITE = 2;
36pub const PROT_WRITE = 2;36pub const PROT_EXEC = 4;
37pub const PROT_EXEC = 4;
38pub const PROT_GROWSDOWN = 0x01000000;37pub const PROT_GROWSDOWN = 0x01000000;
39pub const PROT_GROWSUP = 0x02000000;38pub const PROT_GROWSUP = 0x02000000;
4039
41pub const MAP_FAILED = @maxValue(usize);40pub const MAP_FAILED = @maxValue(usize);
42pub const MAP_SHARED = 0x01;41pub const MAP_SHARED = 0x01;
43pub const MAP_PRIVATE = 0x02;42pub const MAP_PRIVATE = 0x02;
44pub const MAP_TYPE = 0x0f;43pub const MAP_TYPE = 0x0f;
45pub const MAP_FIXED = 0x10;44pub const MAP_FIXED = 0x10;
46pub const MAP_ANONYMOUS = 0x20;45pub const MAP_ANONYMOUS = 0x20;
47pub const MAP_NORESERVE = 0x4000;46pub const MAP_NORESERVE = 0x4000;
48pub const MAP_GROWSDOWN = 0x0100;47pub const MAP_GROWSDOWN = 0x0100;
49pub const MAP_DENYWRITE = 0x0800;48pub const MAP_DENYWRITE = 0x0800;
50pub const MAP_EXECUTABLE = 0x1000;49pub const MAP_EXECUTABLE = 0x1000;
51pub const MAP_LOCKED = 0x2000;50pub const MAP_LOCKED = 0x2000;
52pub const MAP_POPULATE = 0x8000;51pub const MAP_POPULATE = 0x8000;
53pub const MAP_NONBLOCK = 0x10000;52pub const MAP_NONBLOCK = 0x10000;
54pub const MAP_STACK = 0x20000;53pub const MAP_STACK = 0x20000;
55pub const MAP_HUGETLB = 0x40000;54pub const MAP_HUGETLB = 0x40000;
56pub const MAP_FILE = 0;55pub const MAP_FILE = 0;
5756
58pub const F_OK = 0;57pub const F_OK = 0;
59pub const X_OK = 1;58pub const X_OK = 1;
60pub const W_OK = 2;59pub const W_OK = 2;
61pub const R_OK = 4;60pub const R_OK = 4;
6261
63pub const WNOHANG = 1;62pub const WNOHANG = 1;
64pub const WUNTRACED = 2;63pub const WUNTRACED = 2;
65pub const WSTOPPED = 2;64pub const WSTOPPED = 2;
66pub const WEXITED = 4;65pub const WEXITED = 4;
67pub const WCONTINUED = 8;66pub const WCONTINUED = 8;
68pub const WNOWAIT = 0x1000000;67pub const WNOWAIT = 0x1000000;
6968
70pub const SA_NOCLDSTOP = 1;69pub const SA_NOCLDSTOP = 1;
71pub const SA_NOCLDWAIT = 2;70pub const SA_NOCLDWAIT = 2;
72pub const SA_SIGINFO = 4;71pub const SA_SIGINFO = 4;
73pub const SA_ONSTACK = 0x08000000;72pub const SA_ONSTACK = 0x08000000;
74pub const SA_RESTART = 0x10000000;73pub const SA_RESTART = 0x10000000;
75pub const SA_NODEFER = 0x40000000;74pub const SA_NODEFER = 0x40000000;
76pub const SA_RESETHAND = 0x80000000;75pub const SA_RESETHAND = 0x80000000;
77pub const SA_RESTORER = 0x04000000;76pub const SA_RESTORER = 0x04000000;
7877
79pub const SIGHUP = 1;78pub const SIGHUP = 1;
80pub const SIGINT = 2;79pub const SIGINT = 2;
81pub const SIGQUIT = 3;80pub const SIGQUIT = 3;
82pub const SIGILL = 4;81pub const SIGILL = 4;
83pub const SIGTRAP = 5;82pub const SIGTRAP = 5;
84pub const SIGABRT = 6;83pub const SIGABRT = 6;
85pub const SIGIOT = SIGABRT;84pub const SIGIOT = SIGABRT;
86pub const SIGBUS = 7;85pub const SIGBUS = 7;
87pub const SIGFPE = 8;86pub const SIGFPE = 8;
88pub const SIGKILL = 9;87pub const SIGKILL = 9;
89pub const SIGUSR1 = 10;88pub const SIGUSR1 = 10;
90pub const SIGSEGV = 11;89pub const SIGSEGV = 11;
91pub const SIGUSR2 = 12;90pub const SIGUSR2 = 12;
92pub const SIGPIPE = 13;91pub const SIGPIPE = 13;
93pub const SIGALRM = 14;92pub const SIGALRM = 14;
94pub const SIGTERM = 15;93pub const SIGTERM = 15;
95pub const SIGSTKFLT = 16;94pub const SIGSTKFLT = 16;
96pub const SIGCHLD = 17;95pub const SIGCHLD = 17;
97pub const SIGCONT = 18;96pub const SIGCONT = 18;
98pub const SIGSTOP = 19;97pub const SIGSTOP = 19;
99pub const SIGTSTP = 20;98pub const SIGTSTP = 20;
100pub const SIGTTIN = 21;99pub const SIGTTIN = 21;
101pub const SIGTTOU = 22;100pub const SIGTTOU = 22;
102pub const SIGURG = 23;101pub const SIGURG = 23;
103pub const SIGXCPU = 24;102pub const SIGXCPU = 24;
104pub const SIGXFSZ = 25;103pub const SIGXFSZ = 25;
105pub const SIGVTALRM = 26;104pub const SIGVTALRM = 26;
106pub const SIGPROF = 27;105pub const SIGPROF = 27;
107pub const SIGWINCH = 28;106pub const SIGWINCH = 28;
108pub const SIGIO = 29;107pub const SIGIO = 29;
109pub const SIGPOLL = 29;108pub const SIGPOLL = 29;
110pub const SIGPWR = 30;109pub const SIGPWR = 30;
111pub const SIGSYS = 31;110pub const SIGSYS = 31;
112pub const SIGUNUSED = SIGSYS;111pub const SIGUNUSED = SIGSYS;
113112
114pub const O_RDONLY = 0o0;113pub const O_RDONLY = 0o0;
115pub const O_WRONLY = 0o1;114pub const O_WRONLY = 0o1;
116pub const O_RDWR = 0o2;115pub const O_RDWR = 0o2;
117116
118pub const SEEK_SET = 0;117pub const SEEK_SET = 0;
119pub const SEEK_CUR = 1;118pub const SEEK_CUR = 1;
120pub const SEEK_END = 2;119pub const SEEK_END = 2;
121120
122pub const SIG_BLOCK = 0;121pub const SIG_BLOCK = 0;
123pub const SIG_UNBLOCK = 1;122pub const SIG_UNBLOCK = 1;
124pub const SIG_SETMASK = 2;123pub const SIG_SETMASK = 2;
125124
...@@ -408,7 +407,6 @@ pub const DT_LNK = 10;...@@ -408,7 +407,6 @@ pub const DT_LNK = 10;
408pub const DT_SOCK = 12;407pub const DT_SOCK = 12;
409pub const DT_WHT = 14;408pub const DT_WHT = 14;
410409
411
412pub const TCGETS = 0x5401;410pub const TCGETS = 0x5401;
413pub const TCSETS = 0x5402;411pub const TCSETS = 0x5402;
414pub const TCSETSW = 0x5403;412pub const TCSETSW = 0x5403;
...@@ -539,23 +537,23 @@ pub const MS_BIND = 4096;...@@ -539,23 +537,23 @@ pub const MS_BIND = 4096;
539pub const MS_MOVE = 8192;537pub const MS_MOVE = 8192;
540pub const MS_REC = 16384;538pub const MS_REC = 16384;
541pub const MS_SILENT = 32768;539pub const MS_SILENT = 32768;
542pub const MS_POSIXACL = (1<<16);540pub const MS_POSIXACL = (1 << 16);
543pub const MS_UNBINDABLE = (1<<17);541pub const MS_UNBINDABLE = (1 << 17);
544pub const MS_PRIVATE = (1<<18);542pub const MS_PRIVATE = (1 << 18);
545pub const MS_SLAVE = (1<<19);543pub const MS_SLAVE = (1 << 19);
546pub const MS_SHARED = (1<<20);544pub const MS_SHARED = (1 << 20);
547pub const MS_RELATIME = (1<<21);545pub const MS_RELATIME = (1 << 21);
548pub const MS_KERNMOUNT = (1<<22);546pub const MS_KERNMOUNT = (1 << 22);
549pub const MS_I_VERSION = (1<<23);547pub const MS_I_VERSION = (1 << 23);
550pub const MS_STRICTATIME = (1<<24);548pub const MS_STRICTATIME = (1 << 24);
551pub const MS_LAZYTIME = (1<<25);549pub const MS_LAZYTIME = (1 << 25);
552pub const MS_NOREMOTELOCK = (1<<27);550pub const MS_NOREMOTELOCK = (1 << 27);
553pub const MS_NOSEC = (1<<28);551pub const MS_NOSEC = (1 << 28);
554pub const MS_BORN = (1<<29);552pub const MS_BORN = (1 << 29);
555pub const MS_ACTIVE = (1<<30);553pub const MS_ACTIVE = (1 << 30);
556pub const MS_NOUSER = (1<<31);554pub const MS_NOUSER = (1 << 31);
557555
558pub const MS_RMT_MASK = (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME);556pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
559557
560pub const MS_MGC_VAL = 0xc0ed0000;558pub const MS_MGC_VAL = 0xc0ed0000;
561pub const MS_MGC_MSK = 0xffff0000;559pub const MS_MGC_MSK = 0xffff0000;
...@@ -565,7 +563,6 @@ pub const MNT_DETACH = 2;...@@ -565,7 +563,6 @@ pub const MNT_DETACH = 2;
565pub const MNT_EXPIRE = 4;563pub const MNT_EXPIRE = 4;
566pub const UMOUNT_NOFOLLOW = 8;564pub const UMOUNT_NOFOLLOW = 8;
567565
568
569pub const S_IFMT = 0o170000;566pub const S_IFMT = 0o170000;
570567
571pub const S_IFDIR = 0o040000;568pub const S_IFDIR = 0o040000;
...@@ -626,15 +623,30 @@ pub const TFD_CLOEXEC = O_CLOEXEC;...@@ -626,15 +623,30 @@ pub const TFD_CLOEXEC = O_CLOEXEC;
626pub const TFD_TIMER_ABSTIME = 1;623pub const TFD_TIMER_ABSTIME = 1;
627pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);624pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
628625
629fn unsigned(s: i32) u32 { return @bitCast(u32, s); }626fn unsigned(s: i32) u32 {
630fn signed(s: u32) i32 { return @bitCast(i32, s); }627 return @bitCast(u32, s);
631pub fn WEXITSTATUS(s: i32) i32 { return signed((unsigned(s) & 0xff00) >> 8); }628}
632pub fn WTERMSIG(s: i32) i32 { return signed(unsigned(s) & 0x7f); }629fn signed(s: u32) i32 {
633pub fn WSTOPSIG(s: i32) i32 { return WEXITSTATUS(s); }630 return @bitCast(i32, s);
634pub fn WIFEXITED(s: i32) bool { return WTERMSIG(s) == 0; }631}
635pub fn WIFSTOPPED(s: i32) bool { return (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00; }632pub fn WEXITSTATUS(s: i32) i32 {
636pub fn WIFSIGNALED(s: i32) bool { return (unsigned(s)&0xffff)-%1 < 0xff; }633 return signed((unsigned(s) & 0xff00) >> 8);
637634}
635pub fn WTERMSIG(s: i32) i32 {
636 return signed(unsigned(s) & 0x7f);
637}
638pub fn WSTOPSIG(s: i32) i32 {
639 return WEXITSTATUS(s);
640}
641pub fn WIFEXITED(s: i32) bool {
642 return WTERMSIG(s) == 0;
643}
644pub fn WIFSTOPPED(s: i32) bool {
645 return (u16)(((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00;
646}
647pub fn WIFSIGNALED(s: i32) bool {
648 return (unsigned(s) & 0xffff) -% 1 < 0xff;
649}
638650
639pub const winsize = extern struct {651pub const winsize = extern struct {
640 ws_row: u16,652 ws_row: u16,
...@@ -707,8 +719,7 @@ pub fn umount2(special: &const u8, flags: u32) usize {...@@ -707,8 +719,7 @@ pub fn umount2(special: &const u8, flags: u32) usize {
707}719}
708720
709pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {721pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
710 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),722 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd), @bitCast(usize, offset));
711 @bitCast(usize, offset));
712}723}
713724
714pub fn munmap(address: usize, length: usize) usize {725pub fn munmap(address: usize, length: usize) usize {
...@@ -812,7 +823,8 @@ pub fn clock_gettime(clk_id: i32, tp: &timespec) usize {...@@ -812,7 +823,8 @@ pub fn clock_gettime(clk_id: i32, tp: &timespec) usize {
812 if (@ptrToInt(f) != 0) {823 if (@ptrToInt(f) != 0) {
813 const rc = f(clk_id, tp);824 const rc = f(clk_id, tp);
814 switch (rc) {825 switch (rc) {
815 0, @bitCast(usize, isize(-EINVAL)) => return rc,826 0,
827 @bitCast(usize, isize(-EINVAL)) => return rc,
816 else => {},828 else => {},
817 }829 }
818 }830 }
...@@ -823,8 +835,7 @@ var vdso_clock_gettime = init_vdso_clock_gettime;...@@ -823,8 +835,7 @@ var vdso_clock_gettime = init_vdso_clock_gettime;
823extern fn init_vdso_clock_gettime(clk: i32, ts: &timespec) usize {835extern fn init_vdso_clock_gettime(clk: i32, ts: &timespec) usize {
824 const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM);836 const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM);
825 var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr);837 var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr);
826 _ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f,838 _ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f, builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);
827 builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);
828 if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS));839 if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS));
829 return f(clk, ts);840 return f(clk, ts);
830}841}
...@@ -918,18 +929,18 @@ pub fn getpid() i32 {...@@ -918,18 +929,18 @@ pub fn getpid() i32 {
918}929}
919930
920pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize {931pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize {
921 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8);932 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
922}933}
923934
924pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {935pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) usize {
925 assert(sig >= 1);936 assert(sig >= 1);
926 assert(sig != SIGKILL);937 assert(sig != SIGKILL);
927 assert(sig != SIGSTOP);938 assert(sig != SIGSTOP);
928 var ksa = k_sigaction {939 var ksa = k_sigaction{
929 .handler = act.handler,940 .handler = act.handler,
930 .flags = act.flags | SA_RESTORER,941 .flags = act.flags | SA_RESTORER,
931 .mask = undefined,942 .mask = undefined,
932 .restorer = @ptrCast(extern fn()void, restore_rt),943 .restorer = @ptrCast(extern fn() void, restore_rt),
933 };944 };
934 var ksa_old: k_sigaction = undefined;945 var ksa_old: k_sigaction = undefined;
935 @memcpy(@ptrCast(&u8, &ksa.mask), @ptrCast(&const u8, &act.mask), 8);946 @memcpy(@ptrCast(&u8, &ksa.mask), @ptrCast(&const u8, &act.mask), 8);
...@@ -952,22 +963,22 @@ const all_mask = []usize{@maxValue(usize)};...@@ -952,22 +963,22 @@ const all_mask = []usize{@maxValue(usize)};
952const app_mask = []usize{0xfffffffc7fffffff};963const app_mask = []usize{0xfffffffc7fffffff};
953964
954const k_sigaction = extern struct {965const k_sigaction = extern struct {
955 handler: extern fn(i32)void,966 handler: extern fn(i32) void,
956 flags: usize,967 flags: usize,
957 restorer: extern fn()void,968 restorer: extern fn() void,
958 mask: [2]u32,969 mask: [2]u32,
959};970};
960971
961/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.972/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
962pub const Sigaction = struct {973pub const Sigaction = struct {
963 handler: extern fn(i32)void,974 handler: extern fn(i32) void,
964 mask: sigset_t,975 mask: sigset_t,
965 flags: u32,976 flags: u32,
966};977};
967978
968pub const SIG_ERR = @intToPtr(extern fn(i32)void, @maxValue(usize));979pub const SIG_ERR = @intToPtr(extern fn(i32) void, @maxValue(usize));
969pub const SIG_DFL = @intToPtr(extern fn(i32)void, 0);980pub const SIG_DFL = @intToPtr(extern fn(i32) void, 0);
970pub const SIG_IGN = @intToPtr(extern fn(i32)void, 1);981pub const SIG_IGN = @intToPtr(extern fn(i32) void, 1);
971pub const empty_sigset = []usize{0} ** sigset_t.len;982pub const empty_sigset = []usize{0} ** sigset_t.len;
972983
973pub fn raise(sig: i32) usize {984pub fn raise(sig: i32) usize {
...@@ -980,25 +991,25 @@ pub fn raise(sig: i32) usize {...@@ -980,25 +991,25 @@ pub fn raise(sig: i32) usize {
980}991}
981992
982fn blockAllSignals(set: &sigset_t) void {993fn blockAllSignals(set: &sigset_t) void {
983 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG/8);994 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
984}995}
985996
986fn blockAppSignals(set: &sigset_t) void {997fn blockAppSignals(set: &sigset_t) void {
987 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG/8);998 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);
988}999}
9891000
990fn restoreSignals(set: &sigset_t) void {1001fn restoreSignals(set: &sigset_t) void {
991 _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG/8);1002 _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);
992}1003}
9931004
994pub fn sigaddset(set: &sigset_t, sig: u6) void {1005pub fn sigaddset(set: &sigset_t, sig: u6) void {
995 const s = sig - 1;1006 const s = sig - 1;
996 (*set)[usize(s) / usize.bit_count] |= usize(1) << (s & (usize.bit_count - 1));1007 (set.*)[usize(s) / usize.bit_count] |= usize(1) << (s & (usize.bit_count - 1));
997}1008}
9981009
999pub fn sigismember(set: &const sigset_t, sig: u6) bool {1010pub fn sigismember(set: &const sigset_t, sig: u6) bool {
1000 const s = sig - 1;1011 const s = sig - 1;
1001 return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;1012 return ((set.*)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;
1002}1013}
10031014
1004pub const in_port_t = u16;1015pub const in_port_t = u16;
...@@ -1062,9 +1073,7 @@ pub fn recvmsg(fd: i32, msg: &msghdr, flags: u32) usize {...@@ -1062,9 +1073,7 @@ pub fn recvmsg(fd: i32, msg: &msghdr, flags: u32) usize {
1062 return syscall3(SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);1073 return syscall3(SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);
1063}1074}
10641075
1065pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,1076pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32, noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize {
1066 noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) usize
1067{
1068 return syscall6(SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));1077 return syscall6(SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
1069}1078}
10701079
...@@ -1132,25 +1141,16 @@ pub fn fgetxattr(fd: usize, name: &const u8, value: &void, size: usize) usize {...@@ -1132,25 +1141,16 @@ pub fn fgetxattr(fd: usize, name: &const u8, value: &void, size: usize) usize {
1132 return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);1141 return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);
1133}1142}
11341143
1135pub fn setxattr(path: &const u8, name: &const u8, value: &const void,1144pub fn setxattr(path: &const u8, name: &const u8, value: &const void, size: usize, flags: usize) usize {
1136 size: usize, flags: usize) usize {1145 return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
1137
1138 return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value),
1139 size, flags);
1140}1146}
11411147
1142pub fn lsetxattr(path: &const u8, name: &const u8, value: &const void,1148pub fn lsetxattr(path: &const u8, name: &const u8, value: &const void, size: usize, flags: usize) usize {
1143 size: usize, flags: usize) usize {1149 return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
1144
1145 return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value),
1146 size, flags);
1147}1150}
11481151
1149pub fn fsetxattr(fd: usize, name: &const u8, value: &const void,1152pub fn fsetxattr(fd: usize, name: &const u8, value: &const void, size: usize, flags: usize) usize {
1150 size: usize, flags: usize) usize {1153 return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), size, flags);
1151
1152 return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value),
1153 size, flags);
1154}1154}
11551155
1156pub fn removexattr(path: &const u8, name: &const u8) usize {1156pub fn removexattr(path: &const u8, name: &const u8) usize {
...@@ -1199,7 +1199,7 @@ pub fn timerfd_create(clockid: i32, flags: u32) usize {...@@ -1199,7 +1199,7 @@ pub fn timerfd_create(clockid: i32, flags: u32) usize {
11991199
1200pub const itimerspec = extern struct {1200pub const itimerspec = extern struct {
1201 it_interval: timespec,1201 it_interval: timespec,
1202 it_value: timespec1202 it_value: timespec,
1203};1203};
12041204
1205pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) usize {1205pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) usize {
...@@ -1211,30 +1211,30 @@ pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_va...@@ -1211,30 +1211,30 @@ pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_va
1211}1211}
12121212
1213pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;1213pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
1214pub const _LINUX_CAPABILITY_U32S_1 = 1;1214pub const _LINUX_CAPABILITY_U32S_1 = 1;
12151215
1216pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;1216pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
1217pub const _LINUX_CAPABILITY_U32S_2 = 2;1217pub const _LINUX_CAPABILITY_U32S_2 = 2;
12181218
1219pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;1219pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
1220pub const _LINUX_CAPABILITY_U32S_3 = 2;1220pub const _LINUX_CAPABILITY_U32S_3 = 2;
12211221
1222pub const VFS_CAP_REVISION_MASK = 0xFF000000;1222pub const VFS_CAP_REVISION_MASK = 0xFF000000;
1223pub const VFS_CAP_REVISION_SHIFT = 24;1223pub const VFS_CAP_REVISION_SHIFT = 24;
1224pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;1224pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
1225pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;1225pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
12261226
1227pub const VFS_CAP_REVISION_1 = 0x01000000;1227pub const VFS_CAP_REVISION_1 = 0x01000000;
1228pub const VFS_CAP_U32_1 = 1;1228pub const VFS_CAP_U32_1 = 1;
1229pub const XATTR_CAPS_SZ_1 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_1);1229pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
12301230
1231pub const VFS_CAP_REVISION_2 = 0x02000000;1231pub const VFS_CAP_REVISION_2 = 0x02000000;
1232pub const VFS_CAP_U32_2 = 2;1232pub const VFS_CAP_U32_2 = 2;
1233pub const XATTR_CAPS_SZ_2 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_2);1233pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
12341234
1235pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;1235pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
1236pub const VFS_CAP_U32 = VFS_CAP_U32_2;1236pub const VFS_CAP_U32 = VFS_CAP_U32_2;
1237pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;1237pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
12381238
1239pub const vfs_cap_data = extern struct {1239pub const vfs_cap_data = extern struct {
1240 //all of these are mandated as little endian1240 //all of these are mandated as little endian
...@@ -1245,49 +1245,48 @@ pub const vfs_cap_data = extern struct {...@@ -1245,49 +1245,48 @@ pub const vfs_cap_data = extern struct {
1245 };1245 };
12461246
1247 magic_etc: u32,1247 magic_etc: u32,
1248 data: [VFS_CAP_U32]Data,1248 data: [VFS_CAP_U32]Data,
1249};1249};
12501250
12511251pub const CAP_CHOWN = 0;
1252pub const CAP_CHOWN = 0;1252pub const CAP_DAC_OVERRIDE = 1;
1253pub const CAP_DAC_OVERRIDE = 1;1253pub const CAP_DAC_READ_SEARCH = 2;
1254pub const CAP_DAC_READ_SEARCH = 2;1254pub const CAP_FOWNER = 3;
1255pub const CAP_FOWNER = 3;1255pub const CAP_FSETID = 4;
1256pub const CAP_FSETID = 4;1256pub const CAP_KILL = 5;
1257pub const CAP_KILL = 5;1257pub const CAP_SETGID = 6;
1258pub const CAP_SETGID = 6;1258pub const CAP_SETUID = 7;
1259pub const CAP_SETUID = 7;1259pub const CAP_SETPCAP = 8;
1260pub const CAP_SETPCAP = 8;1260pub const CAP_LINUX_IMMUTABLE = 9;
1261pub const CAP_LINUX_IMMUTABLE = 9;1261pub const CAP_NET_BIND_SERVICE = 10;
1262pub const CAP_NET_BIND_SERVICE = 10;1262pub const CAP_NET_BROADCAST = 11;
1263pub const CAP_NET_BROADCAST = 11;1263pub const CAP_NET_ADMIN = 12;
1264pub const CAP_NET_ADMIN = 12;1264pub const CAP_NET_RAW = 13;
1265pub const CAP_NET_RAW = 13;1265pub const CAP_IPC_LOCK = 14;
1266pub const CAP_IPC_LOCK = 14;1266pub const CAP_IPC_OWNER = 15;
1267pub const CAP_IPC_OWNER = 15;1267pub const CAP_SYS_MODULE = 16;
1268pub const CAP_SYS_MODULE = 16;1268pub const CAP_SYS_RAWIO = 17;
1269pub const CAP_SYS_RAWIO = 17;1269pub const CAP_SYS_CHROOT = 18;
1270pub const CAP_SYS_CHROOT = 18;1270pub const CAP_SYS_PTRACE = 19;
1271pub const CAP_SYS_PTRACE = 19;1271pub const CAP_SYS_PACCT = 20;
1272pub const CAP_SYS_PACCT = 20;1272pub const CAP_SYS_ADMIN = 21;
1273pub const CAP_SYS_ADMIN = 21;1273pub const CAP_SYS_BOOT = 22;
1274pub const CAP_SYS_BOOT = 22;1274pub const CAP_SYS_NICE = 23;
1275pub const CAP_SYS_NICE = 23;1275pub const CAP_SYS_RESOURCE = 24;
1276pub const CAP_SYS_RESOURCE = 24;1276pub const CAP_SYS_TIME = 25;
1277pub const CAP_SYS_TIME = 25;1277pub const CAP_SYS_TTY_CONFIG = 26;
1278pub const CAP_SYS_TTY_CONFIG = 26;1278pub const CAP_MKNOD = 27;
1279pub const CAP_MKNOD = 27;1279pub const CAP_LEASE = 28;
1280pub const CAP_LEASE = 28;1280pub const CAP_AUDIT_WRITE = 29;
1281pub const CAP_AUDIT_WRITE = 29;1281pub const CAP_AUDIT_CONTROL = 30;
1282pub const CAP_AUDIT_CONTROL = 30;1282pub const CAP_SETFCAP = 31;
1283pub const CAP_SETFCAP = 31;1283pub const CAP_MAC_OVERRIDE = 32;
1284pub const CAP_MAC_OVERRIDE = 32;1284pub const CAP_MAC_ADMIN = 33;
1285pub const CAP_MAC_ADMIN = 33;1285pub const CAP_SYSLOG = 34;
1286pub const CAP_SYSLOG = 34;1286pub const CAP_WAKE_ALARM = 35;
1287pub const CAP_WAKE_ALARM = 35;1287pub const CAP_BLOCK_SUSPEND = 36;
1288pub const CAP_BLOCK_SUSPEND = 36;1288pub const CAP_AUDIT_READ = 37;
1289pub const CAP_AUDIT_READ = 37;1289pub const CAP_LAST_CAP = CAP_AUDIT_READ;
1290pub const CAP_LAST_CAP = CAP_AUDIT_READ;
12911290
1292pub fn cap_valid(u8: x) bool {1291pub fn cap_valid(u8: x) bool {
1293 return x >= 0 and x <= CAP_LAST_CAP;1292 return x >= 0 and x <= CAP_LAST_CAP;
std/os/test.zig+1-1
...@@ -12,7 +12,7 @@ const AtomicOrder = builtin.AtomicOrder;...@@ -12,7 +12,7 @@ const AtomicOrder = builtin.AtomicOrder;
12test "makePath, put some files in it, deleteTree" {12test "makePath, put some files in it, deleteTree" {
13 if (builtin.os == builtin.Os.windows) {13 if (builtin.os == builtin.Os.windows) {
14 // TODO implement os.Dir for windows14 // TODO implement os.Dir for windows
15 // https://github.com/zig-lang/zig/issues/70915 // https://github.com/ziglang/zig/issues/709
16 return;16 return;
17 }17 }
18 try os.makePath(a, "os_test_tmp/b/c");18 try os.makePath(a, "os_test_tmp/b/c");
std/os/time.zig+1-1
...@@ -135,7 +135,7 @@ pub const Timer = struct {...@@ -135,7 +135,7 @@ pub const Timer = struct {
135 135
136 //At some point we may change our minds on RAW, but for now we're136 //At some point we may change our minds on RAW, but for now we're
137 // sticking with posix standard MONOTONIC. For more information, see: 137 // sticking with posix standard MONOTONIC. For more information, see:
138 // https://github.com/zig-lang/zig/pull/933138 // https://github.com/ziglang/zig/pull/933
139 //139 //
140 //const monotonic_clock_id = switch(builtin.os) {140 //const monotonic_clock_id = switch(builtin.os) {
141 // Os.linux => linux.CLOCK_MONOTONIC_RAW,141 // Os.linux => linux.CLOCK_MONOTONIC_RAW,
std/segmented_list.zig+40-30
...@@ -95,7 +95,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type...@@ -95,7 +95,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
9595
96 /// Deinitialize with `deinit`96 /// Deinitialize with `deinit`
97 pub fn init(allocator: &Allocator) Self {97 pub fn init(allocator: &Allocator) Self {
98 return Self {98 return Self{
99 .allocator = allocator,99 .allocator = allocator,
100 .len = 0,100 .len = 0,
101 .prealloc_segment = undefined,101 .prealloc_segment = undefined,
...@@ -106,7 +106,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type...@@ -106,7 +106,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
106 pub fn deinit(self: &Self) void {106 pub fn deinit(self: &Self) void {
107 self.freeShelves(ShelfIndex(self.dynamic_segments.len), 0);107 self.freeShelves(ShelfIndex(self.dynamic_segments.len), 0);
108 self.allocator.free(self.dynamic_segments);108 self.allocator.free(self.dynamic_segments);
109 *self = undefined;109 self.* = undefined;
110 }110 }
111111
112 pub fn at(self: &Self, i: usize) &T {112 pub fn at(self: &Self, i: usize) &T {
...@@ -120,7 +120,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type...@@ -120,7 +120,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
120120
121 pub fn push(self: &Self, item: &const T) !void {121 pub fn push(self: &Self, item: &const T) !void {
122 const new_item_ptr = try self.addOne();122 const new_item_ptr = try self.addOne();
123 *new_item_ptr = *item;123 new_item_ptr.* = item.*;
124 }124 }
125125
126 pub fn pushMany(self: &Self, items: []const T) !void {126 pub fn pushMany(self: &Self, items: []const T) !void {
...@@ -130,11 +130,10 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type...@@ -130,11 +130,10 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
130 }130 }
131131
132 pub fn pop(self: &Self) ?T {132 pub fn pop(self: &Self) ?T {
133 if (self.len == 0)133 if (self.len == 0) return null;
134 return null;
135134
136 const index = self.len - 1;135 const index = self.len - 1;
137 const result = *self.uncheckedAt(index);136 const result = self.uncheckedAt(index).*;
138 self.len = index;137 self.len = index;
139 return result;138 return result;
140 }139 }
...@@ -247,8 +246,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type...@@ -247,8 +246,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
247 shelf_size: usize,246 shelf_size: usize,
248247
249 pub fn next(it: &Iterator) ?&T {248 pub fn next(it: &Iterator) ?&T {
250 if (it.index >= it.list.len)249 if (it.index >= it.list.len) return null;
251 return null;
252 if (it.index < prealloc_item_count) {250 if (it.index < prealloc_item_count) {
253 const ptr = &it.list.prealloc_segment[it.index];251 const ptr = &it.list.prealloc_segment[it.index];
254 it.index += 1;252 it.index += 1;
...@@ -272,12 +270,10 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type...@@ -272,12 +270,10 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
272 }270 }
273271
274 pub fn prev(it: &Iterator) ?&T {272 pub fn prev(it: &Iterator) ?&T {
275 if (it.index == 0)273 if (it.index == 0) return null;
276 return null;
277274
278 it.index -= 1;275 it.index -= 1;
279 if (it.index < prealloc_item_count)276 if (it.index < prealloc_item_count) return &it.list.prealloc_segment[it.index];
280 return &it.list.prealloc_segment[it.index];
281277
282 if (it.box_index == 0) {278 if (it.box_index == 0) {
283 it.shelf_index -= 1;279 it.shelf_index -= 1;
...@@ -298,21 +294,25 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type...@@ -298,21 +294,25 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
298294
299 return &it.list.dynamic_segments[it.shelf_index][it.box_index];295 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
300 }296 }
297
298 pub fn set(it: &Iterator, index: usize) void {
299 it.index = index;
300 if (index < prealloc_item_count) return;
301 it.shelf_index = shelfIndex(index);
302 it.box_index = boxIndex(index, it.shelf_index);
303 it.shelf_size = shelfSize(it.shelf_index);
304 }
301 };305 };
302306
303 pub fn iterator(self: &Self, start_index: usize) Iterator {307 pub fn iterator(self: &Self, start_index: usize) Iterator {
304 var it = Iterator {308 var it = Iterator{
305 .list = self,309 .list = self,
306 .index = start_index,310 .index = undefined,
307 .shelf_index = undefined,311 .shelf_index = undefined,
308 .box_index = undefined,312 .box_index = undefined,
309 .shelf_size = undefined,313 .shelf_size = undefined,
310 };314 };
311 if (start_index >= prealloc_item_count) {315 it.set(start_index);
312 it.shelf_index = shelfIndex(start_index);
313 it.box_index = boxIndex(start_index, it.shelf_index);
314 it.shelf_size = shelfSize(it.shelf_index);
315 }
316 return it;316 return it;
317 }317 }
318 };318 };
...@@ -335,25 +335,31 @@ fn testSegmentedList(comptime prealloc: usize, allocator: &Allocator) !void {...@@ -335,25 +335,31 @@ fn testSegmentedList(comptime prealloc: usize, allocator: &Allocator) !void {
335 var list = SegmentedList(i32, prealloc).init(allocator);335 var list = SegmentedList(i32, prealloc).init(allocator);
336 defer list.deinit();336 defer list.deinit();
337337
338 {var i: usize = 0; while (i < 100) : (i += 1) {338 {
339 try list.push(i32(i + 1));339 var i: usize = 0;
340 assert(list.len == i + 1);340 while (i < 100) : (i += 1) {
341 }}341 try list.push(i32(i + 1));
342 assert(list.len == i + 1);
343 }
344 }
342345
343 {var i: usize = 0; while (i < 100) : (i += 1) {346 {
344 assert(*list.at(i) == i32(i + 1));347 var i: usize = 0;
345 }}348 while (i < 100) : (i += 1) {
349 assert(list.at(i).* == i32(i + 1));
350 }
351 }
346352
347 {353 {
348 var it = list.iterator(0);354 var it = list.iterator(0);
349 var x: i32 = 0;355 var x: i32 = 0;
350 while (it.next()) |item| {356 while (it.next()) |item| {
351 x += 1;357 x += 1;
352 assert(*item == x);358 assert(item.* == x);
353 }359 }
354 assert(x == 100);360 assert(x == 100);
355 while (it.prev()) |item| : (x -= 1) {361 while (it.prev()) |item| : (x -= 1) {
356 assert(*item == x);362 assert(item.* == x);
357 }363 }
358 assert(x == 0);364 assert(x == 0);
359 }365 }
...@@ -361,14 +367,18 @@ fn testSegmentedList(comptime prealloc: usize, allocator: &Allocator) !void {...@@ -361,14 +367,18 @@ fn testSegmentedList(comptime prealloc: usize, allocator: &Allocator) !void {
361 assert(??list.pop() == 100);367 assert(??list.pop() == 100);
362 assert(list.len == 99);368 assert(list.len == 99);
363369
364 try list.pushMany([]i32 { 1, 2, 3 });370 try list.pushMany([]i32{
371 1,
372 2,
373 3,
374 });
365 assert(list.len == 102);375 assert(list.len == 102);
366 assert(??list.pop() == 3);376 assert(??list.pop() == 3);
367 assert(??list.pop() == 2);377 assert(??list.pop() == 2);
368 assert(??list.pop() == 1);378 assert(??list.pop() == 1);
369 assert(list.len == 99);379 assert(list.len == 99);
370380
371 try list.pushMany([]const i32 {});381 try list.pushMany([]const i32{});
372 assert(list.len == 99);382 assert(list.len == 99);
373383
374 var i: i32 = 99;384 var i: i32 = 99;
std/sort.zig+398-164
...@@ -5,15 +5,18 @@ const math = std.math;...@@ -5,15 +5,18 @@ const math = std.math;
5const builtin = @import("builtin");5const builtin = @import("builtin");
66
7/// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required).7/// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required).
8pub fn insertionSort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) void {8pub fn insertionSort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T) bool) void {
9 {var i: usize = 1; while (i < items.len) : (i += 1) {9 {
10 const x = items[i];10 var i: usize = 1;
11 var j: usize = i;11 while (i < items.len) : (i += 1) {
12 while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) {12 const x = items[i];
13 items[j] = items[j - 1];13 var j: usize = i;
14 while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) {
15 items[j] = items[j - 1];
16 }
17 items[j] = x;
14 }18 }
15 items[j] = x;19 }
16 }}
17}20}
1821
19const Range = struct {22const Range = struct {
...@@ -21,7 +24,10 @@ const Range = struct {...@@ -21,7 +24,10 @@ const Range = struct {
21 end: usize,24 end: usize,
2225
23 fn init(start: usize, end: usize) Range {26 fn init(start: usize, end: usize) Range {
24 return Range { .start = start, .end = end };27 return Range{
28 .start = start,
29 .end = end,
30 };
25 }31 }
2632
27 fn length(self: &const Range) usize {33 fn length(self: &const Range) usize {
...@@ -29,7 +35,6 @@ const Range = struct {...@@ -29,7 +35,6 @@ const Range = struct {
29 }35 }
30};36};
3137
32
33const Iterator = struct {38const Iterator = struct {
34 size: usize,39 size: usize,
35 power_of_two: usize,40 power_of_two: usize,
...@@ -42,7 +47,7 @@ const Iterator = struct {...@@ -42,7 +47,7 @@ const Iterator = struct {
42 fn init(size2: usize, min_level: usize) Iterator {47 fn init(size2: usize, min_level: usize) Iterator {
43 const power_of_two = math.floorPowerOfTwo(usize, size2);48 const power_of_two = math.floorPowerOfTwo(usize, size2);
44 const denominator = power_of_two / min_level;49 const denominator = power_of_two / min_level;
45 return Iterator {50 return Iterator{
46 .numerator = 0,51 .numerator = 0,
47 .decimal = 0,52 .decimal = 0,
48 .size = size2,53 .size = size2,
...@@ -68,7 +73,10 @@ const Iterator = struct {...@@ -68,7 +73,10 @@ const Iterator = struct {
68 self.decimal += 1;73 self.decimal += 1;
69 }74 }
7075
71 return Range {.start = start, .end = self.decimal};76 return Range{
77 .start = start,
78 .end = self.decimal,
79 };
72 }80 }
7381
74 fn finished(self: &Iterator) bool {82 fn finished(self: &Iterator) bool {
...@@ -100,7 +108,7 @@ const Pull = struct {...@@ -100,7 +108,7 @@ const Pull = struct {
100108
101/// Stable in-place sort. O(n) best case, O(n*log(n)) worst case and average case. O(1) memory (no allocator required).109/// Stable in-place sort. O(n) best case, O(n*log(n)) worst case and average case. O(1) memory (no allocator required).
102/// Currently implemented as block sort.110/// Currently implemented as block sort.
103pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) void {111pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T) bool) void {
104 // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c112 // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c
105 var cache: [512]T = undefined;113 var cache: [512]T = undefined;
106114
...@@ -123,7 +131,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -123,7 +131,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
123 // http://pages.ripco.net/~jgamble/nw.html131 // http://pages.ripco.net/~jgamble/nw.html
124 var iterator = Iterator.init(items.len, 4);132 var iterator = Iterator.init(items.len, 4);
125 while (!iterator.finished()) {133 while (!iterator.finished()) {
126 var order = []u8{0, 1, 2, 3, 4, 5, 6, 7};134 var order = []u8{
135 0,
136 1,
137 2,
138 3,
139 4,
140 5,
141 6,
142 7,
143 };
127 const range = iterator.nextRange();144 const range = iterator.nextRange();
128145
129 const sliced_items = items[range.start..];146 const sliced_items = items[range.start..];
...@@ -149,56 +166,56 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -149,56 +166,56 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
149 swap(T, sliced_items, lessThan, &order, 3, 5);166 swap(T, sliced_items, lessThan, &order, 3, 5);
150 swap(T, sliced_items, lessThan, &order, 3, 4);167 swap(T, sliced_items, lessThan, &order, 3, 4);
151 },168 },
152 7 => {169 7 => {
153 swap(T, sliced_items, lessThan, &order, 1, 2);170 swap(T, sliced_items, lessThan, &order, 1, 2);
154 swap(T, sliced_items, lessThan, &order, 3, 4);171 swap(T, sliced_items, lessThan, &order, 3, 4);
155 swap(T, sliced_items, lessThan, &order, 5, 6);172 swap(T, sliced_items, lessThan, &order, 5, 6);
156 swap(T, sliced_items, lessThan, &order, 0, 2);173 swap(T, sliced_items, lessThan, &order, 0, 2);
157 swap(T, sliced_items, lessThan, &order, 3, 5);174 swap(T, sliced_items, lessThan, &order, 3, 5);
158 swap(T, sliced_items, lessThan, &order, 4, 6);175 swap(T, sliced_items, lessThan, &order, 4, 6);
159 swap(T, sliced_items, lessThan, &order, 0, 1);176 swap(T, sliced_items, lessThan, &order, 0, 1);
160 swap(T, sliced_items, lessThan, &order, 4, 5);177 swap(T, sliced_items, lessThan, &order, 4, 5);
161 swap(T, sliced_items, lessThan, &order, 2, 6);178 swap(T, sliced_items, lessThan, &order, 2, 6);
162 swap(T, sliced_items, lessThan, &order, 0, 4);179 swap(T, sliced_items, lessThan, &order, 0, 4);
163 swap(T, sliced_items, lessThan, &order, 1, 5);180 swap(T, sliced_items, lessThan, &order, 1, 5);
164 swap(T, sliced_items, lessThan, &order, 0, 3);181 swap(T, sliced_items, lessThan, &order, 0, 3);
165 swap(T, sliced_items, lessThan, &order, 2, 5);182 swap(T, sliced_items, lessThan, &order, 2, 5);
166 swap(T, sliced_items, lessThan, &order, 1, 3);183 swap(T, sliced_items, lessThan, &order, 1, 3);
167 swap(T, sliced_items, lessThan, &order, 2, 4);184 swap(T, sliced_items, lessThan, &order, 2, 4);
168 swap(T, sliced_items, lessThan, &order, 2, 3);185 swap(T, sliced_items, lessThan, &order, 2, 3);
169 },186 },
170 6 => {187 6 => {
171 swap(T, sliced_items, lessThan, &order, 1, 2);188 swap(T, sliced_items, lessThan, &order, 1, 2);
172 swap(T, sliced_items, lessThan, &order, 4, 5);189 swap(T, sliced_items, lessThan, &order, 4, 5);
173 swap(T, sliced_items, lessThan, &order, 0, 2);190 swap(T, sliced_items, lessThan, &order, 0, 2);
174 swap(T, sliced_items, lessThan, &order, 3, 5);191 swap(T, sliced_items, lessThan, &order, 3, 5);
175 swap(T, sliced_items, lessThan, &order, 0, 1);192 swap(T, sliced_items, lessThan, &order, 0, 1);
176 swap(T, sliced_items, lessThan, &order, 3, 4);193 swap(T, sliced_items, lessThan, &order, 3, 4);
177 swap(T, sliced_items, lessThan, &order, 2, 5);194 swap(T, sliced_items, lessThan, &order, 2, 5);
178 swap(T, sliced_items, lessThan, &order, 0, 3);195 swap(T, sliced_items, lessThan, &order, 0, 3);
179 swap(T, sliced_items, lessThan, &order, 1, 4);196 swap(T, sliced_items, lessThan, &order, 1, 4);
180 swap(T, sliced_items, lessThan, &order, 2, 4);197 swap(T, sliced_items, lessThan, &order, 2, 4);
181 swap(T, sliced_items, lessThan, &order, 1, 3);198 swap(T, sliced_items, lessThan, &order, 1, 3);
182 swap(T, sliced_items, lessThan, &order, 2, 3);199 swap(T, sliced_items, lessThan, &order, 2, 3);
183 },200 },
184 5 => {201 5 => {
185 swap(T, sliced_items, lessThan, &order, 0, 1);202 swap(T, sliced_items, lessThan, &order, 0, 1);
186 swap(T, sliced_items, lessThan, &order, 3, 4);203 swap(T, sliced_items, lessThan, &order, 3, 4);
187 swap(T, sliced_items, lessThan, &order, 2, 4);204 swap(T, sliced_items, lessThan, &order, 2, 4);
188 swap(T, sliced_items, lessThan, &order, 2, 3);205 swap(T, sliced_items, lessThan, &order, 2, 3);
189 swap(T, sliced_items, lessThan, &order, 1, 4);206 swap(T, sliced_items, lessThan, &order, 1, 4);
190 swap(T, sliced_items, lessThan, &order, 0, 3);207 swap(T, sliced_items, lessThan, &order, 0, 3);
191 swap(T, sliced_items, lessThan, &order, 0, 2);208 swap(T, sliced_items, lessThan, &order, 0, 2);
192 swap(T, sliced_items, lessThan, &order, 1, 3);209 swap(T, sliced_items, lessThan, &order, 1, 3);
193 swap(T, sliced_items, lessThan, &order, 1, 2);210 swap(T, sliced_items, lessThan, &order, 1, 2);
194 },211 },
195 4 => {212 4 => {
196 swap(T, sliced_items, lessThan, &order, 0, 1);213 swap(T, sliced_items, lessThan, &order, 0, 1);
197 swap(T, sliced_items, lessThan, &order, 2, 3);214 swap(T, sliced_items, lessThan, &order, 2, 3);
198 swap(T, sliced_items, lessThan, &order, 0, 2);215 swap(T, sliced_items, lessThan, &order, 0, 2);
199 swap(T, sliced_items, lessThan, &order, 1, 3);216 swap(T, sliced_items, lessThan, &order, 1, 3);
200 swap(T, sliced_items, lessThan, &order, 1, 2);217 swap(T, sliced_items, lessThan, &order, 1, 2);
201 },218 },
202 else => {},219 else => {},
203 }220 }
204 }221 }
...@@ -273,7 +290,6 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -273,7 +290,6 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
273 // we merged two levels at the same time, so we're done with this level already290 // we merged two levels at the same time, so we're done with this level already
274 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)291 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)
275 _ = iterator.nextLevel();292 _ = iterator.nextLevel();
276
277 } else {293 } else {
278 iterator.begin();294 iterator.begin();
279 while (!iterator.finished()) {295 while (!iterator.finished()) {
...@@ -303,7 +319,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -303,7 +319,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
303 // 8. redistribute the two internal buffers back into the items319 // 8. redistribute the two internal buffers back into the items
304320
305 var block_size: usize = math.sqrt(iterator.length());321 var block_size: usize = math.sqrt(iterator.length());
306 var buffer_size = iterator.length()/block_size + 1;322 var buffer_size = iterator.length() / block_size + 1;
307323
308 // as an optimization, we really only need to pull out the internal buffers once for each level of merges324 // as an optimization, we really only need to pull out the internal buffers once for each level of merges
309 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level325 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level
...@@ -316,8 +332,18 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -316,8 +332,18 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
316 var start: usize = 0;332 var start: usize = 0;
317 var pull_index: usize = 0;333 var pull_index: usize = 0;
318 var pull = []Pull{334 var pull = []Pull{
319 Pull {.from = 0, .to = 0, .count = 0, .range = Range.init(0, 0),},335 Pull{
320 Pull {.from = 0, .to = 0, .count = 0, .range = Range.init(0, 0),},336 .from = 0,
337 .to = 0,
338 .count = 0,
339 .range = Range.init(0, 0),
340 },
341 Pull{
342 .from = 0,
343 .to = 0,
344 .count = 0,
345 .range = Range.init(0, 0),
346 },
321 };347 };
322348
323 var buffer1 = Range.init(0, 0);349 var buffer1 = Range.init(0, 0);
...@@ -355,7 +381,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -355,7 +381,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
355 // these values will be pulled out to the start of A381 // these values will be pulled out to the start of A
356 last = A.start;382 last = A.start;
357 count = 1;383 count = 1;
358 while (count < find) : ({last = index; count += 1;}) {384 while (count < find) : ({
385 last = index;
386 count += 1;
387 }) {
359 index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), lessThan, find - count);388 index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), lessThan, find - count);
360 if (index == A.end) break;389 if (index == A.end) break;
361 }390 }
...@@ -363,7 +392,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -363,7 +392,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
363392
364 if (count >= buffer_size) {393 if (count >= buffer_size) {
365 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer394 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer
366 pull[pull_index] = Pull {395 pull[pull_index] = Pull{
367 .range = Range.init(A.start, B.end),396 .range = Range.init(A.start, B.end),
368 .count = count,397 .count = count,
369 .from = index,398 .from = index,
...@@ -398,7 +427,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -398,7 +427,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
398 } else if (pull_index == 0 and count > buffer1.length()) {427 } else if (pull_index == 0 and count > buffer1.length()) {
399 // keep track of the largest buffer we were able to find428 // keep track of the largest buffer we were able to find
400 buffer1 = Range.init(A.start, A.start + count);429 buffer1 = Range.init(A.start, A.start + count);
401 pull[pull_index] = Pull {430 pull[pull_index] = Pull{
402 .range = Range.init(A.start, B.end),431 .range = Range.init(A.start, B.end),
403 .count = count,432 .count = count,
404 .from = index,433 .from = index,
...@@ -410,7 +439,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -410,7 +439,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
410 // these values will be pulled out to the end of B439 // these values will be pulled out to the end of B
411 last = B.end - 1;440 last = B.end - 1;
412 count = 1;441 count = 1;
413 while (count < find) : ({last = index - 1; count += 1;}) {442 while (count < find) : ({
443 last = index - 1;
444 count += 1;
445 }) {
414 index = findFirstBackward(T, items, items[last], Range.init(B.start, last), lessThan, find - count);446 index = findFirstBackward(T, items, items[last], Range.init(B.start, last), lessThan, find - count);
415 if (index == B.start) break;447 if (index == B.start) break;
416 }448 }
...@@ -418,7 +450,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -418,7 +450,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
418450
419 if (count >= buffer_size) {451 if (count >= buffer_size) {
420 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe452 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe
421 pull[pull_index] = Pull {453 pull[pull_index] = Pull{
422 .range = Range.init(A.start, B.end),454 .range = Range.init(A.start, B.end),
423 .count = count,455 .count = count,
424 .from = index,456 .from = index,
...@@ -457,7 +489,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -457,7 +489,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
457 } else if (pull_index == 0 and count > buffer1.length()) {489 } else if (pull_index == 0 and count > buffer1.length()) {
458 // keep track of the largest buffer we were able to find490 // keep track of the largest buffer we were able to find
459 buffer1 = Range.init(B.end - count, B.end);491 buffer1 = Range.init(B.end - count, B.end);
460 pull[pull_index] = Pull {492 pull[pull_index] = Pull{
461 .range = Range.init(A.start, B.end),493 .range = Range.init(A.start, B.end),
462 .count = count,494 .count = count,
463 .from = index,495 .from = index,
...@@ -496,7 +528,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -496,7 +528,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
496528
497 // adjust block_size and buffer_size based on the values we were able to pull out529 // adjust block_size and buffer_size based on the values we were able to pull out
498 buffer_size = buffer1.length();530 buffer_size = buffer1.length();
499 block_size = iterator.length()/buffer_size + 1;531 block_size = iterator.length() / buffer_size + 1;
500532
501 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,533 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,
502 // so this was originally here to test the math for adjusting block_size above534 // so this was originally here to test the math for adjusting block_size above
...@@ -547,7 +579,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -547,7 +579,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
547 // swap the first value of each A block with the value in buffer1579 // swap the first value of each A block with the value in buffer1
548 var indexA = buffer1.start;580 var indexA = buffer1.start;
549 index = firstA.end;581 index = firstA.end;
550 while (index < blockA.end) : ({indexA += 1; index += block_size;}) {582 while (index < blockA.end) : ({
583 indexA += 1;
584 index += block_size;
585 }) {
551 mem.swap(T, &items[indexA], &items[index]);586 mem.swap(T, &items[indexA], &items[index]);
552 }587 }
553588
...@@ -626,9 +661,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -626,9 +661,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
626661
627 // if there are no more A blocks remaining, this step is finished!662 // if there are no more A blocks remaining, this step is finished!
628 blockA.start += block_size;663 blockA.start += block_size;
629 if (blockA.length() == 0)664 if (blockA.length() == 0) break;
630 break;
631
632 } else if (blockB.length() < block_size) {665 } else if (blockB.length() < block_size) {
633 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation666 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation
634 // the cache is disabled here since it might contain the contents of the previous A block667 // the cache is disabled here since it might contain the contents of the previous A block
...@@ -709,7 +742,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons...@@ -709,7 +742,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
709}742}
710743
711// merge operation without a buffer744// merge operation without a buffer
712fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void {745fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T, &const T) bool) void {
713 if (A_arg.length() == 0 or B_arg.length() == 0) return;746 if (A_arg.length() == 0 or B_arg.length() == 0) return;
714747
715 // this just repeatedly binary searches into B and rotates A into position.748 // this just repeatedly binary searches into B and rotates A into position.
...@@ -730,8 +763,8 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const...@@ -730,8 +763,8 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const
730 // again, this is NOT a general-purpose solution – it only works well in this case!763 // again, this is NOT a general-purpose solution – it only works well in this case!
731 // kind of like how the O(n^2) insertion sort is used in some places764 // kind of like how the O(n^2) insertion sort is used in some places
732765
733 var A = *A_arg;766 var A = A_arg.*;
734 var B = *B_arg;767 var B = B_arg.*;
735768
736 while (true) {769 while (true) {
737 // find the first place in B where the first item in A needs to be inserted770 // find the first place in B where the first item in A needs to be inserted
...@@ -751,7 +784,7 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const...@@ -751,7 +784,7 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const
751}784}
752785
753// merge operation using an internal buffer786// merge operation using an internal buffer
754fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)bool, buffer: &const Range) void {787fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T, &const T) bool, buffer: &const Range) void {
755 // whenever we find a value to add to the final array, swap it with the value that's already in that spot788 // whenever we find a value to add to the final array, swap it with the value that's already in that spot
756 // when this algorithm is finished, 'buffer' will contain its original contents, but in a different order789 // when this algorithm is finished, 'buffer' will contain its original contents, but in a different order
757 var A_count: usize = 0;790 var A_count: usize = 0;
...@@ -787,9 +820,9 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s...@@ -787,9 +820,9 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s
787820
788// combine a linear search with a binary search to reduce the number of comparisons in situations821// combine a linear search with a binary search to reduce the number of comparisons in situations
789// where have some idea as to how many unique values there are and where the next value might be822// where have some idea as to how many unique values there are and where the next value might be
790fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {823fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool, unique: usize) usize {
791 if (range.length() == 0) return range.start;824 if (range.length() == 0) return range.start;
792 const skip = math.max(range.length()/unique, usize(1));825 const skip = math.max(range.length() / unique, usize(1));
793826
794 var index = range.start + skip;827 var index = range.start + skip;
795 while (lessThan(items[index - 1], value)) : (index += skip) {828 while (lessThan(items[index - 1], value)) : (index += skip) {
...@@ -801,9 +834,9 @@ fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const...@@ -801,9 +834,9 @@ fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const
801 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);834 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);
802}835}
803836
804fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {837fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool, unique: usize) usize {
805 if (range.length() == 0) return range.start;838 if (range.length() == 0) return range.start;
806 const skip = math.max(range.length()/unique, usize(1));839 const skip = math.max(range.length() / unique, usize(1));
807840
808 var index = range.end - skip;841 var index = range.end - skip;
809 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {842 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {
...@@ -815,9 +848,9 @@ fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &cons...@@ -815,9 +848,9 @@ fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &cons
815 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);848 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);
816}849}
817850
818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {851fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool, unique: usize) usize {
819 if (range.length() == 0) return range.start;852 if (range.length() == 0) return range.start;
820 const skip = math.max(range.length()/unique, usize(1));853 const skip = math.max(range.length() / unique, usize(1));
821854
822 var index = range.start + skip;855 var index = range.start + skip;
823 while (!lessThan(value, items[index - 1])) : (index += skip) {856 while (!lessThan(value, items[index - 1])) : (index += skip) {
...@@ -829,9 +862,9 @@ fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const...@@ -829,9 +862,9 @@ fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const
829 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);862 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);
830}863}
831864
832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {865fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool, unique: usize) usize {
833 if (range.length() == 0) return range.start;866 if (range.length() == 0) return range.start;
834 const skip = math.max(range.length()/unique, usize(1));867 const skip = math.max(range.length() / unique, usize(1));
835868
836 var index = range.end - skip;869 var index = range.end - skip;
837 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {870 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {
...@@ -843,12 +876,12 @@ fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const...@@ -843,12 +876,12 @@ fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const
843 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);876 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);
844}877}
845878
846fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool) usize {879fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool) usize {
847 var start = range.start;880 var start = range.start;
848 var end = range.end - 1;881 var end = range.end - 1;
849 if (range.start >= range.end) return range.end;882 if (range.start >= range.end) return range.end;
850 while (start < end) {883 while (start < end) {
851 const mid = start + (end - start)/2;884 const mid = start + (end - start) / 2;
852 if (lessThan(items[mid], value)) {885 if (lessThan(items[mid], value)) {
853 start = mid + 1;886 start = mid + 1;
854 } else {887 } else {
...@@ -861,12 +894,12 @@ fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Rang...@@ -861,12 +894,12 @@ fn binaryFirst(comptime T: type, items: []T, value: &const T, range: &const Rang
861 return start;894 return start;
862}895}
863896
864fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool) usize {897fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T, &const T) bool) usize {
865 var start = range.start;898 var start = range.start;
866 var end = range.end - 1;899 var end = range.end - 1;
867 if (range.start >= range.end) return range.end;900 if (range.start >= range.end) return range.end;
868 while (start < end) {901 while (start < end) {
869 const mid = start + (end - start)/2;902 const mid = start + (end - start) / 2;
870 if (!lessThan(value, items[mid])) {903 if (!lessThan(value, items[mid])) {
871 start = mid + 1;904 start = mid + 1;
872 } else {905 } else {
...@@ -879,7 +912,7 @@ fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range...@@ -879,7 +912,7 @@ fn binaryLast(comptime T: type, items: []T, value: &const T, range: &const Range
879 return start;912 return start;
880}913}
881914
882fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)bool, into: []T) void {915fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, lessThan: fn(&const T, &const T) bool, into: []T) void {
883 var A_index: usize = A.start;916 var A_index: usize = A.start;
884 var B_index: usize = B.start;917 var B_index: usize = B.start;
885 const A_last = A.end;918 const A_last = A.end;
...@@ -909,7 +942,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less...@@ -909,7 +942,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less
909 }942 }
910}943}
911944
912fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T,&const T)bool, cache: []T) void {945fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range, lessThan: fn(&const T, &const T) bool, cache: []T) void {
913 // A fits into the cache, so use that instead of the internal buffer946 // A fits into the cache, so use that instead of the internal buffer
914 var A_index: usize = 0;947 var A_index: usize = 0;
915 var B_index: usize = B.start;948 var B_index: usize = B.start;
...@@ -937,29 +970,27 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,...@@ -937,29 +970,27 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
937 mem.copy(T, items[insert_index..], cache[A_index..A_last]);970 mem.copy(T, items[insert_index..], cache[A_index..A_last]);
938}971}
939972
940fn swap(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool, order: &[8]u8, x: usize, y: usize) void {973fn swap(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T) bool, order: &[8]u8, x: usize, y: usize) void {
941 if (lessThan(items[y], items[x]) or974 if (lessThan(items[y], items[x]) or ((order.*)[x] > (order.*)[y] and !lessThan(items[x], items[y]))) {
942 ((*order)[x] > (*order)[y] and !lessThan(items[x], items[y])))
943 {
944 mem.swap(T, &items[x], &items[y]);975 mem.swap(T, &items[x], &items[y]);
945 mem.swap(u8, &(*order)[x], &(*order)[y]);976 mem.swap(u8, &(order.*)[x], &(order.*)[y]);
946 }977 }
947}978}
948979
949fn i32asc(lhs: &const i32, rhs: &const i32) bool {980fn i32asc(lhs: &const i32, rhs: &const i32) bool {
950 return *lhs < *rhs;981 return lhs.* < rhs.*;
951}982}
952983
953fn i32desc(lhs: &const i32, rhs: &const i32) bool {984fn i32desc(lhs: &const i32, rhs: &const i32) bool {
954 return *rhs < *lhs;985 return rhs.* < lhs.*;
955}986}
956987
957fn u8asc(lhs: &const u8, rhs: &const u8) bool {988fn u8asc(lhs: &const u8, rhs: &const u8) bool {
958 return *lhs < *rhs;989 return lhs.* < rhs.*;
959}990}
960991
961fn u8desc(lhs: &const u8, rhs: &const u8) bool {992fn u8desc(lhs: &const u8, rhs: &const u8) bool {
962 return *rhs < *lhs;993 return rhs.* < lhs.*;
963}994}
964995
965test "stable sort" {996test "stable sort" {
...@@ -967,44 +998,125 @@ test "stable sort" {...@@ -967,44 +998,125 @@ test "stable sort" {
967 comptime testStableSort();998 comptime testStableSort();
968}999}
969fn testStableSort() void {1000fn testStableSort() void {
970 var expected = []IdAndValue {1001 var expected = []IdAndValue{
971 IdAndValue{.id = 0, .value = 0},1002 IdAndValue{
972 IdAndValue{.id = 1, .value = 0},1003 .id = 0,
973 IdAndValue{.id = 2, .value = 0},1004 .value = 0,
974 IdAndValue{.id = 0, .value = 1},1005 },
975 IdAndValue{.id = 1, .value = 1},1006 IdAndValue{
976 IdAndValue{.id = 2, .value = 1},1007 .id = 1,
977 IdAndValue{.id = 0, .value = 2},1008 .value = 0,
978 IdAndValue{.id = 1, .value = 2},1009 },
979 IdAndValue{.id = 2, .value = 2},1010 IdAndValue{
1011 .id = 2,
1012 .value = 0,
1013 },
1014 IdAndValue{
1015 .id = 0,
1016 .value = 1,
1017 },
1018 IdAndValue{
1019 .id = 1,
1020 .value = 1,
1021 },
1022 IdAndValue{
1023 .id = 2,
1024 .value = 1,
1025 },
1026 IdAndValue{
1027 .id = 0,
1028 .value = 2,
1029 },
1030 IdAndValue{
1031 .id = 1,
1032 .value = 2,
1033 },
1034 IdAndValue{
1035 .id = 2,
1036 .value = 2,
1037 },
980 };1038 };
981 var cases = [][9]IdAndValue {1039 var cases = [][9]IdAndValue{
982 []IdAndValue {1040 []IdAndValue{
983 IdAndValue{.id = 0, .value = 0},1041 IdAndValue{
984 IdAndValue{.id = 0, .value = 1},1042 .id = 0,
985 IdAndValue{.id = 0, .value = 2},1043 .value = 0,
986 IdAndValue{.id = 1, .value = 0},1044 },
987 IdAndValue{.id = 1, .value = 1},1045 IdAndValue{
988 IdAndValue{.id = 1, .value = 2},1046 .id = 0,
989 IdAndValue{.id = 2, .value = 0},1047 .value = 1,
990 IdAndValue{.id = 2, .value = 1},1048 },
991 IdAndValue{.id = 2, .value = 2},1049 IdAndValue{
1050 .id = 0,
1051 .value = 2,
1052 },
1053 IdAndValue{
1054 .id = 1,
1055 .value = 0,
1056 },
1057 IdAndValue{
1058 .id = 1,
1059 .value = 1,
1060 },
1061 IdAndValue{
1062 .id = 1,
1063 .value = 2,
1064 },
1065 IdAndValue{
1066 .id = 2,
1067 .value = 0,
1068 },
1069 IdAndValue{
1070 .id = 2,
1071 .value = 1,
1072 },
1073 IdAndValue{
1074 .id = 2,
1075 .value = 2,
1076 },
992 },1077 },
993 []IdAndValue {1078 []IdAndValue{
994 IdAndValue{.id = 0, .value = 2},1079 IdAndValue{
995 IdAndValue{.id = 0, .value = 1},1080 .id = 0,
996 IdAndValue{.id = 0, .value = 0},1081 .value = 2,
997 IdAndValue{.id = 1, .value = 2},1082 },
998 IdAndValue{.id = 1, .value = 1},1083 IdAndValue{
999 IdAndValue{.id = 1, .value = 0},1084 .id = 0,
1000 IdAndValue{.id = 2, .value = 2},1085 .value = 1,
1001 IdAndValue{.id = 2, .value = 1},1086 },
1002 IdAndValue{.id = 2, .value = 0},1087 IdAndValue{
1088 .id = 0,
1089 .value = 0,
1090 },
1091 IdAndValue{
1092 .id = 1,
1093 .value = 2,
1094 },
1095 IdAndValue{
1096 .id = 1,
1097 .value = 1,
1098 },
1099 IdAndValue{
1100 .id = 1,
1101 .value = 0,
1102 },
1103 IdAndValue{
1104 .id = 2,
1105 .value = 2,
1106 },
1107 IdAndValue{
1108 .id = 2,
1109 .value = 1,
1110 },
1111 IdAndValue{
1112 .id = 2,
1113 .value = 0,
1114 },
1003 },1115 },
1004 };1116 };
1005 for (cases) |*case| {1117 for (cases) |*case| {
1006 insertionSort(IdAndValue, (*case)[0..], cmpByValue);1118 insertionSort(IdAndValue, (case.*)[0..], cmpByValue);
1007 for (*case) |item, i| {1119 for (case.*) |item, i| {
1008 assert(item.id == expected[i].id);1120 assert(item.id == expected[i].id);
1009 assert(item.value == expected[i].value);1121 assert(item.value == expected[i].value);
1010 }1122 }
...@@ -1019,13 +1131,31 @@ fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) bool {...@@ -1019,13 +1131,31 @@ fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) bool {
1019}1131}
10201132
1021test "std.sort" {1133test "std.sort" {
1022 const u8cases = [][]const []const u8 {1134 const u8cases = [][]const []const u8{
1023 [][]const u8{"", ""},1135 [][]const u8{
1024 [][]const u8{"a", "a"},1136 "",
1025 [][]const u8{"az", "az"},1137 "",
1026 [][]const u8{"za", "az"},1138 },
1027 [][]const u8{"asdf", "adfs"},1139 [][]const u8{
1028 [][]const u8{"one", "eno"},1140 "a",
1141 "a",
1142 },
1143 [][]const u8{
1144 "az",
1145 "az",
1146 },
1147 [][]const u8{
1148 "za",
1149 "az",
1150 },
1151 [][]const u8{
1152 "asdf",
1153 "adfs",
1154 },
1155 [][]const u8{
1156 "one",
1157 "eno",
1158 },
1029 };1159 };
10301160
1031 for (u8cases) |case| {1161 for (u8cases) |case| {
...@@ -1036,13 +1166,59 @@ test "std.sort" {...@@ -1036,13 +1166,59 @@ test "std.sort" {
1036 assert(mem.eql(u8, slice, case[1]));1166 assert(mem.eql(u8, slice, case[1]));
1037 }1167 }
10381168
1039 const i32cases = [][]const []const i32 {1169 const i32cases = [][]const []const i32{
1040 [][]const i32{[]i32{}, []i32{}},1170 [][]const i32{
1041 [][]const i32{[]i32{1}, []i32{1}},1171 []i32{},
1042 [][]const i32{[]i32{0, 1}, []i32{0, 1}},1172 []i32{},
1043 [][]const i32{[]i32{1, 0}, []i32{0, 1}},1173 },
1044 [][]const i32{[]i32{1, -1, 0}, []i32{-1, 0, 1}},1174 [][]const i32{
1045 [][]const i32{[]i32{2, 1, 3}, []i32{1, 2, 3}},1175 []i32{1},
1176 []i32{1},
1177 },
1178 [][]const i32{
1179 []i32{
1180 0,
1181 1,
1182 },
1183 []i32{
1184 0,
1185 1,
1186 },
1187 },
1188 [][]const i32{
1189 []i32{
1190 1,
1191 0,
1192 },
1193 []i32{
1194 0,
1195 1,
1196 },
1197 },
1198 [][]const i32{
1199 []i32{
1200 1,
1201 -1,
1202 0,
1203 },
1204 []i32{
1205 -1,
1206 0,
1207 1,
1208 },
1209 },
1210 [][]const i32{
1211 []i32{
1212 2,
1213 1,
1214 3,
1215 },
1216 []i32{
1217 1,
1218 2,
1219 3,
1220 },
1221 },
1046 };1222 };
10471223
1048 for (i32cases) |case| {1224 for (i32cases) |case| {
...@@ -1055,13 +1231,59 @@ test "std.sort" {...@@ -1055,13 +1231,59 @@ test "std.sort" {
1055}1231}
10561232
1057test "std.sort descending" {1233test "std.sort descending" {
1058 const rev_cases = [][]const []const i32 {1234 const rev_cases = [][]const []const i32{
1059 [][]const i32{[]i32{}, []i32{}},1235 [][]const i32{
1060 [][]const i32{[]i32{1}, []i32{1}},1236 []i32{},
1061 [][]const i32{[]i32{0, 1}, []i32{1, 0}},1237 []i32{},
1062 [][]const i32{[]i32{1, 0}, []i32{1, 0}},1238 },
1063 [][]const i32{[]i32{1, -1, 0}, []i32{1, 0, -1}},1239 [][]const i32{
1064 [][]const i32{[]i32{2, 1, 3}, []i32{3, 2, 1}},1240 []i32{1},
1241 []i32{1},
1242 },
1243 [][]const i32{
1244 []i32{
1245 0,
1246 1,
1247 },
1248 []i32{
1249 1,
1250 0,
1251 },
1252 },
1253 [][]const i32{
1254 []i32{
1255 1,
1256 0,
1257 },
1258 []i32{
1259 1,
1260 0,
1261 },
1262 },
1263 [][]const i32{
1264 []i32{
1265 1,
1266 -1,
1267 0,
1268 },
1269 []i32{
1270 1,
1271 0,
1272 -1,
1273 },
1274 },
1275 [][]const i32{
1276 []i32{
1277 2,
1278 1,
1279 3,
1280 },
1281 []i32{
1282 3,
1283 2,
1284 1,
1285 },
1286 },
1065 };1287 };
10661288
1067 for (rev_cases) |case| {1289 for (rev_cases) |case| {
...@@ -1074,10 +1296,22 @@ test "std.sort descending" {...@@ -1074,10 +1296,22 @@ test "std.sort descending" {
1074}1296}
10751297
1076test "another sort case" {1298test "another sort case" {
1077 var arr = []i32{ 5, 3, 1, 2, 4 };1299 var arr = []i32{
1300 5,
1301 3,
1302 1,
1303 2,
1304 4,
1305 };
1078 sort(i32, arr[0..], i32asc);1306 sort(i32, arr[0..], i32asc);
10791307
1080 assert(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 }));1308 assert(mem.eql(i32, arr, []i32{
1309 1,
1310 2,
1311 3,
1312 4,
1313 5,
1314 }));
1081}1315}
10821316
1083test "sort fuzz testing" {1317test "sort fuzz testing" {
...@@ -1112,7 +1346,7 @@ fn fuzzTest(rng: &std.rand.Random) void {...@@ -1112,7 +1346,7 @@ fn fuzzTest(rng: &std.rand.Random) void {
1112 }1346 }
1113}1347}
11141348
1115pub fn min(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) T {1349pub fn min(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T) bool) T {
1116 var i: usize = 0;1350 var i: usize = 0;
1117 var smallest = items[0];1351 var smallest = items[0];
1118 for (items[1..]) |item| {1352 for (items[1..]) |item| {
...@@ -1123,7 +1357,7 @@ pub fn min(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const...@@ -1123,7 +1357,7 @@ pub fn min(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const
1123 return smallest;1357 return smallest;
1124}1358}
11251359
1126pub fn max(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T)bool) T {1360pub fn max(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &const T) bool) T {
1127 var i: usize = 0;1361 var i: usize = 0;
1128 var biggest = items[0];1362 var biggest = items[0];
1129 for (items[1..]) |item| {1363 for (items[1..]) |item| {
std/special/bootstrap.zig+4-4
...@@ -27,10 +27,10 @@ extern fn zen_start() noreturn {...@@ -27,10 +27,10 @@ extern fn zen_start() noreturn {
27nakedcc fn _start() noreturn {27nakedcc fn _start() noreturn {
28 switch (builtin.arch) {28 switch (builtin.arch) {
29 builtin.Arch.x86_64 => {29 builtin.Arch.x86_64 => {
30 argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize));30 argc_ptr = asm ("lea (%%rsp), %[argc]" : [argc] "=r" (-> &usize));
31 },31 },
32 builtin.Arch.i386 => {32 builtin.Arch.i386 => {
33 argc_ptr = asm("lea (%%esp), %[argc]": [argc] "=r" (-> &usize));33 argc_ptr = asm ("lea (%%esp), %[argc]" : [argc] "=r" (-> &usize));
34 },34 },
35 else => @compileError("unsupported arch"),35 else => @compileError("unsupported arch"),
36 }36 }
...@@ -46,7 +46,7 @@ extern fn WinMainCRTStartup() noreturn {...@@ -46,7 +46,7 @@ extern fn WinMainCRTStartup() noreturn {
46}46}
4747
48fn posixCallMainAndExit() noreturn {48fn posixCallMainAndExit() noreturn {
49 const argc = *argc_ptr;49 const argc = argc_ptr.*;
50 const argv = @ptrCast(&&u8, &argc_ptr[1]);50 const argv = @ptrCast(&&u8, &argc_ptr[1]);
51 const envp_nullable = @ptrCast(&?&u8, &argv[argc + 1]);51 const envp_nullable = @ptrCast(&?&u8, &argv[argc + 1]);
52 var envp_count: usize = 0;52 var envp_count: usize = 0;
...@@ -56,7 +56,7 @@ fn posixCallMainAndExit() noreturn {...@@ -56,7 +56,7 @@ fn posixCallMainAndExit() noreturn {
56 const auxv = &@ptrCast(&usize, envp.ptr)[envp_count + 1];56 const auxv = &@ptrCast(&usize, envp.ptr)[envp_count + 1];
57 var i: usize = 0;57 var i: usize = 0;
58 while (auxv[i] != 0) : (i += 2) {58 while (auxv[i] != 0) : (i += 2) {
59 if (auxv[i] < std.os.linux_aux_raw.len) std.os.linux_aux_raw[auxv[i]] = auxv[i+1];59 if (auxv[i] < std.os.linux_aux_raw.len) std.os.linux_aux_raw[auxv[i]] = auxv[i + 1];
60 }60 }
61 std.debug.assert(std.os.linux_aux_raw[std.elf.AT_PAGESZ] == std.os.page_size);61 std.debug.assert(std.os.linux_aux_raw[std.elf.AT_PAGESZ] == std.os.page_size);
62 }62 }
std/special/compiler_rt/comparetf2.zig+2-2
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1// TODO https://github.com/zig-lang/zig/issues/3051// TODO https://github.com/ziglang/zig/issues/305
2// and then make the return types of some of these functions the enum instead of c_int2// and then make the return types of some of these functions the enum instead of c_int
3const LE_LESS = c_int(-1);3const LE_LESS = c_int(-1);
4const LE_EQUAL = c_int(0);4const LE_EQUAL = c_int(0);
...@@ -59,7 +59,7 @@ pub extern fn __letf2(a: f128, b: f128) c_int {...@@ -59,7 +59,7 @@ pub extern fn __letf2(a: f128, b: f128) c_int {
59 ;59 ;
60}60}
6161
62// TODO https://github.com/zig-lang/zig/issues/30562// TODO https://github.com/ziglang/zig/issues/305
63// and then make the return types of some of these functions the enum instead of c_int63// and then make the return types of some of these functions the enum instead of c_int
64const GE_LESS = c_int(-1);64const GE_LESS = c_int(-1);
65const GE_EQUAL = c_int(0);65const GE_EQUAL = c_int(0);
std/special/compiler_rt/fixuint.zig+2-4
...@@ -36,12 +36,10 @@ pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t...@@ -36,12 +36,10 @@ pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t
36 const significand: rep_t = (aAbs & significandMask) | implicitBit;36 const significand: rep_t = (aAbs & significandMask) | implicitBit;
3737
38 // If either the value or the exponent is negative, the result is zero.38 // If either the value or the exponent is negative, the result is zero.
39 if (sign == -1 or exponent < 0)39 if (sign == -1 or exponent < 0) return 0;
40 return 0;
4140
42 // If the value is too large for the integer type, saturate.41 // If the value is too large for the integer type, saturate.
43 if (c_uint(exponent) >= fixuint_t.bit_count)42 if (c_uint(exponent) >= fixuint_t.bit_count) return ~fixuint_t(0);
44 return ~fixuint_t(0);
4543
46 // If 0 <= exponent < significandBits, right shift to get the result.44 // If 0 <= exponent < significandBits, right shift to get the result.
47 // Otherwise, shift left.45 // Otherwise, shift left.
std/special/compiler_rt/fixunsdfdi.zig-1
...@@ -9,4 +9,3 @@ pub extern fn __fixunsdfdi(a: f64) u64 {...@@ -9,4 +9,3 @@ pub extern fn __fixunsdfdi(a: f64) u64 {
9test "import fixunsdfdi" {9test "import fixunsdfdi" {
10 _ = @import("fixunsdfdi_test.zig");10 _ = @import("fixunsdfdi_test.zig");
11}11}
12
std/special/compiler_rt/fixunsdfsi.zig-1
...@@ -9,4 +9,3 @@ pub extern fn __fixunsdfsi(a: f64) u32 {...@@ -9,4 +9,3 @@ pub extern fn __fixunsdfsi(a: f64) u32 {
9test "import fixunsdfsi" {9test "import fixunsdfsi" {
10 _ = @import("fixunsdfsi_test.zig");10 _ = @import("fixunsdfsi_test.zig");
11}11}
12
std/special/compiler_rt/fixunssfti.zig-1
...@@ -9,4 +9,3 @@ pub extern fn __fixunssfti(a: f32) u128 {...@@ -9,4 +9,3 @@ pub extern fn __fixunssfti(a: f32) u128 {
9test "import fixunssfti" {9test "import fixunssfti" {
10 _ = @import("fixunssfti_test.zig");10 _ = @import("fixunssfti_test.zig");
11}11}
12
std/special/compiler_rt/fixunstfti.zig-1
...@@ -9,4 +9,3 @@ pub extern fn __fixunstfti(a: f128) u128 {...@@ -9,4 +9,3 @@ pub extern fn __fixunstfti(a: f128) u128 {
9test "import fixunstfti" {9test "import fixunstfti" {
10 _ = @import("fixunstfti_test.zig");10 _ = @import("fixunstfti_test.zig");
11}11}
12
std/special/compiler_rt/index.zig+674-144
...@@ -92,9 +92,10 @@ pub fn setXmm0(comptime T: type, value: T) void {...@@ -92,9 +92,10 @@ pub fn setXmm0(comptime T: type, value: T) void {
92 const aligned_value: T align(16) = value;92 const aligned_value: T align(16) = value;
93 asm volatile (93 asm volatile (
94 \\movaps (%[ptr]), %%xmm094 \\movaps (%[ptr]), %%xmm0
95 :95
96 : [ptr] "r" (&aligned_value)96 :
97 : "xmm0");97 : [ptr] "r" (&aligned_value)
98 : "xmm0");
98}99}
99100
100extern fn __udivdi3(a: u64, b: u64) u64 {101extern fn __udivdi3(a: u64, b: u64) u64 {
...@@ -283,26 +284,27 @@ extern fn __udivmodsi4(a: u32, b: u32, rem: &u32) u32 {...@@ -283,26 +284,27 @@ extern fn __udivmodsi4(a: u32, b: u32, rem: &u32) u32 {
283 @setRuntimeSafety(is_test);284 @setRuntimeSafety(is_test);
284285
285 const d = __udivsi3(a, b);286 const d = __udivsi3(a, b);
286 *rem = u32(i32(a) -% (i32(d) * i32(b)));287 rem.* = u32(i32(a) -% (i32(d) * i32(b)));
287 return d;288 return d;
288}289}
289290
290
291extern fn __udivsi3(n: u32, d: u32) u32 {291extern fn __udivsi3(n: u32, d: u32) u32 {
292 @setRuntimeSafety(is_test);292 @setRuntimeSafety(is_test);
293293
294 const n_uword_bits: c_uint = u32.bit_count;294 const n_uword_bits: c_uint = u32.bit_count;
295 // special cases295 // special cases
296 if (d == 0)296 if (d == 0) return 0; // ?!
297 return 0; // ?!297 if (n == 0) return 0;
298 if (n == 0)
299 return 0;
300 var sr = @bitCast(c_uint, c_int(@clz(d)) - c_int(@clz(n)));298 var sr = @bitCast(c_uint, c_int(@clz(d)) - c_int(@clz(n)));
301 // 0 <= sr <= n_uword_bits - 1 or sr large299 // 0 <= sr <= n_uword_bits - 1 or sr large
302 if (sr > n_uword_bits - 1) // d > r300 if (sr > n_uword_bits - 1) {
301 // d > r
303 return 0;302 return 0;
304 if (sr == n_uword_bits - 1) // d == 1303 }
304 if (sr == n_uword_bits - 1) {
305 // d == 1
305 return n;306 return n;
307 }
306 sr += 1;308 sr += 1;
307 // 1 <= sr <= n_uword_bits - 1309 // 1 <= sr <= n_uword_bits - 1
308 // Not a special case310 // Not a special case
...@@ -341,139 +343,667 @@ fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) void {...@@ -341,139 +343,667 @@ fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) void {
341}343}
342344
343test "test_udivsi3" {345test "test_udivsi3" {
344 const cases = [][3]u32 {346 const cases = [][3]u32{
345 []u32{0x00000000, 0x00000001, 0x00000000},347 []u32{
346 []u32{0x00000000, 0x00000002, 0x00000000},348 0x00000000,
347 []u32{0x00000000, 0x00000003, 0x00000000},349 0x00000001,
348 []u32{0x00000000, 0x00000010, 0x00000000},350 0x00000000,
349 []u32{0x00000000, 0x078644FA, 0x00000000},351 },
350 []u32{0x00000000, 0x0747AE14, 0x00000000},352 []u32{
351 []u32{0x00000000, 0x7FFFFFFF, 0x00000000},353 0x00000000,
352 []u32{0x00000000, 0x80000000, 0x00000000},354 0x00000002,
353 []u32{0x00000000, 0xFFFFFFFD, 0x00000000},355 0x00000000,
354 []u32{0x00000000, 0xFFFFFFFE, 0x00000000},356 },
355 []u32{0x00000000, 0xFFFFFFFF, 0x00000000},357 []u32{
356 []u32{0x00000001, 0x00000001, 0x00000001},358 0x00000000,
357 []u32{0x00000001, 0x00000002, 0x00000000},359 0x00000003,
358 []u32{0x00000001, 0x00000003, 0x00000000},360 0x00000000,
359 []u32{0x00000001, 0x00000010, 0x00000000},361 },
360 []u32{0x00000001, 0x078644FA, 0x00000000},362 []u32{
361 []u32{0x00000001, 0x0747AE14, 0x00000000},363 0x00000000,
362 []u32{0x00000001, 0x7FFFFFFF, 0x00000000},364 0x00000010,
363 []u32{0x00000001, 0x80000000, 0x00000000},365 0x00000000,
364 []u32{0x00000001, 0xFFFFFFFD, 0x00000000},366 },
365 []u32{0x00000001, 0xFFFFFFFE, 0x00000000},367 []u32{
366 []u32{0x00000001, 0xFFFFFFFF, 0x00000000},368 0x00000000,
367 []u32{0x00000002, 0x00000001, 0x00000002},369 0x078644FA,
368 []u32{0x00000002, 0x00000002, 0x00000001},370 0x00000000,
369 []u32{0x00000002, 0x00000003, 0x00000000},371 },
370 []u32{0x00000002, 0x00000010, 0x00000000},372 []u32{
371 []u32{0x00000002, 0x078644FA, 0x00000000},373 0x00000000,
372 []u32{0x00000002, 0x0747AE14, 0x00000000},374 0x0747AE14,
373 []u32{0x00000002, 0x7FFFFFFF, 0x00000000},375 0x00000000,
374 []u32{0x00000002, 0x80000000, 0x00000000},376 },
375 []u32{0x00000002, 0xFFFFFFFD, 0x00000000},377 []u32{
376 []u32{0x00000002, 0xFFFFFFFE, 0x00000000},378 0x00000000,
377 []u32{0x00000002, 0xFFFFFFFF, 0x00000000},379 0x7FFFFFFF,
378 []u32{0x00000003, 0x00000001, 0x00000003},380 0x00000000,
379 []u32{0x00000003, 0x00000002, 0x00000001},381 },
380 []u32{0x00000003, 0x00000003, 0x00000001},382 []u32{
381 []u32{0x00000003, 0x00000010, 0x00000000},383 0x00000000,
382 []u32{0x00000003, 0x078644FA, 0x00000000},384 0x80000000,
383 []u32{0x00000003, 0x0747AE14, 0x00000000},385 0x00000000,
384 []u32{0x00000003, 0x7FFFFFFF, 0x00000000},386 },
385 []u32{0x00000003, 0x80000000, 0x00000000},387 []u32{
386 []u32{0x00000003, 0xFFFFFFFD, 0x00000000},388 0x00000000,
387 []u32{0x00000003, 0xFFFFFFFE, 0x00000000},389 0xFFFFFFFD,
388 []u32{0x00000003, 0xFFFFFFFF, 0x00000000},390 0x00000000,
389 []u32{0x00000010, 0x00000001, 0x00000010},391 },
390 []u32{0x00000010, 0x00000002, 0x00000008},392 []u32{
391 []u32{0x00000010, 0x00000003, 0x00000005},393 0x00000000,
392 []u32{0x00000010, 0x00000010, 0x00000001},394 0xFFFFFFFE,
393 []u32{0x00000010, 0x078644FA, 0x00000000},395 0x00000000,
394 []u32{0x00000010, 0x0747AE14, 0x00000000},396 },
395 []u32{0x00000010, 0x7FFFFFFF, 0x00000000},397 []u32{
396 []u32{0x00000010, 0x80000000, 0x00000000},398 0x00000000,
397 []u32{0x00000010, 0xFFFFFFFD, 0x00000000},399 0xFFFFFFFF,
398 []u32{0x00000010, 0xFFFFFFFE, 0x00000000},400 0x00000000,
399 []u32{0x00000010, 0xFFFFFFFF, 0x00000000},401 },
400 []u32{0x078644FA, 0x00000001, 0x078644FA},402 []u32{
401 []u32{0x078644FA, 0x00000002, 0x03C3227D},403 0x00000001,
402 []u32{0x078644FA, 0x00000003, 0x028216FE},404 0x00000001,
403 []u32{0x078644FA, 0x00000010, 0x0078644F},405 0x00000001,
404 []u32{0x078644FA, 0x078644FA, 0x00000001},406 },
405 []u32{0x078644FA, 0x0747AE14, 0x00000001},407 []u32{
406 []u32{0x078644FA, 0x7FFFFFFF, 0x00000000},408 0x00000001,
407 []u32{0x078644FA, 0x80000000, 0x00000000},409 0x00000002,
408 []u32{0x078644FA, 0xFFFFFFFD, 0x00000000},410 0x00000000,
409 []u32{0x078644FA, 0xFFFFFFFE, 0x00000000},411 },
410 []u32{0x078644FA, 0xFFFFFFFF, 0x00000000},412 []u32{
411 []u32{0x0747AE14, 0x00000001, 0x0747AE14},413 0x00000001,
412 []u32{0x0747AE14, 0x00000002, 0x03A3D70A},414 0x00000003,
413 []u32{0x0747AE14, 0x00000003, 0x026D3A06},415 0x00000000,
414 []u32{0x0747AE14, 0x00000010, 0x00747AE1},416 },
415 []u32{0x0747AE14, 0x078644FA, 0x00000000},417 []u32{
416 []u32{0x0747AE14, 0x0747AE14, 0x00000001},418 0x00000001,
417 []u32{0x0747AE14, 0x7FFFFFFF, 0x00000000},419 0x00000010,
418 []u32{0x0747AE14, 0x80000000, 0x00000000},420 0x00000000,
419 []u32{0x0747AE14, 0xFFFFFFFD, 0x00000000},421 },
420 []u32{0x0747AE14, 0xFFFFFFFE, 0x00000000},422 []u32{
421 []u32{0x0747AE14, 0xFFFFFFFF, 0x00000000},423 0x00000001,
422 []u32{0x7FFFFFFF, 0x00000001, 0x7FFFFFFF},424 0x078644FA,
423 []u32{0x7FFFFFFF, 0x00000002, 0x3FFFFFFF},425 0x00000000,
424 []u32{0x7FFFFFFF, 0x00000003, 0x2AAAAAAA},426 },
425 []u32{0x7FFFFFFF, 0x00000010, 0x07FFFFFF},427 []u32{
426 []u32{0x7FFFFFFF, 0x078644FA, 0x00000011},428 0x00000001,
427 []u32{0x7FFFFFFF, 0x0747AE14, 0x00000011},429 0x0747AE14,
428 []u32{0x7FFFFFFF, 0x7FFFFFFF, 0x00000001},430 0x00000000,
429 []u32{0x7FFFFFFF, 0x80000000, 0x00000000},431 },
430 []u32{0x7FFFFFFF, 0xFFFFFFFD, 0x00000000},432 []u32{
431 []u32{0x7FFFFFFF, 0xFFFFFFFE, 0x00000000},433 0x00000001,
432 []u32{0x7FFFFFFF, 0xFFFFFFFF, 0x00000000},434 0x7FFFFFFF,
433 []u32{0x80000000, 0x00000001, 0x80000000},435 0x00000000,
434 []u32{0x80000000, 0x00000002, 0x40000000},436 },
435 []u32{0x80000000, 0x00000003, 0x2AAAAAAA},437 []u32{
436 []u32{0x80000000, 0x00000010, 0x08000000},438 0x00000001,
437 []u32{0x80000000, 0x078644FA, 0x00000011},439 0x80000000,
438 []u32{0x80000000, 0x0747AE14, 0x00000011},440 0x00000000,
439 []u32{0x80000000, 0x7FFFFFFF, 0x00000001},441 },
440 []u32{0x80000000, 0x80000000, 0x00000001},442 []u32{
441 []u32{0x80000000, 0xFFFFFFFD, 0x00000000},443 0x00000001,
442 []u32{0x80000000, 0xFFFFFFFE, 0x00000000},444 0xFFFFFFFD,
443 []u32{0x80000000, 0xFFFFFFFF, 0x00000000},445 0x00000000,
444 []u32{0xFFFFFFFD, 0x00000001, 0xFFFFFFFD},446 },
445 []u32{0xFFFFFFFD, 0x00000002, 0x7FFFFFFE},447 []u32{
446 []u32{0xFFFFFFFD, 0x00000003, 0x55555554},448 0x00000001,
447 []u32{0xFFFFFFFD, 0x00000010, 0x0FFFFFFF},449 0xFFFFFFFE,
448 []u32{0xFFFFFFFD, 0x078644FA, 0x00000022},450 0x00000000,
449 []u32{0xFFFFFFFD, 0x0747AE14, 0x00000023},451 },
450 []u32{0xFFFFFFFD, 0x7FFFFFFF, 0x00000001},452 []u32{
451 []u32{0xFFFFFFFD, 0x80000000, 0x00000001},453 0x00000001,
452 []u32{0xFFFFFFFD, 0xFFFFFFFD, 0x00000001},454 0xFFFFFFFF,
453 []u32{0xFFFFFFFD, 0xFFFFFFFE, 0x00000000},455 0x00000000,
454 []u32{0xFFFFFFFD, 0xFFFFFFFF, 0x00000000},456 },
455 []u32{0xFFFFFFFE, 0x00000001, 0xFFFFFFFE},457 []u32{
456 []u32{0xFFFFFFFE, 0x00000002, 0x7FFFFFFF},458 0x00000002,
457 []u32{0xFFFFFFFE, 0x00000003, 0x55555554},459 0x00000001,
458 []u32{0xFFFFFFFE, 0x00000010, 0x0FFFFFFF},460 0x00000002,
459 []u32{0xFFFFFFFE, 0x078644FA, 0x00000022},461 },
460 []u32{0xFFFFFFFE, 0x0747AE14, 0x00000023},462 []u32{
461 []u32{0xFFFFFFFE, 0x7FFFFFFF, 0x00000002},463 0x00000002,
462 []u32{0xFFFFFFFE, 0x80000000, 0x00000001},464 0x00000002,
463 []u32{0xFFFFFFFE, 0xFFFFFFFD, 0x00000001},465 0x00000001,
464 []u32{0xFFFFFFFE, 0xFFFFFFFE, 0x00000001},466 },
465 []u32{0xFFFFFFFE, 0xFFFFFFFF, 0x00000000},467 []u32{
466 []u32{0xFFFFFFFF, 0x00000001, 0xFFFFFFFF},468 0x00000002,
467 []u32{0xFFFFFFFF, 0x00000002, 0x7FFFFFFF},469 0x00000003,
468 []u32{0xFFFFFFFF, 0x00000003, 0x55555555},470 0x00000000,
469 []u32{0xFFFFFFFF, 0x00000010, 0x0FFFFFFF},471 },
470 []u32{0xFFFFFFFF, 0x078644FA, 0x00000022},472 []u32{
471 []u32{0xFFFFFFFF, 0x0747AE14, 0x00000023},473 0x00000002,
472 []u32{0xFFFFFFFF, 0x7FFFFFFF, 0x00000002},474 0x00000010,
473 []u32{0xFFFFFFFF, 0x80000000, 0x00000001},475 0x00000000,
474 []u32{0xFFFFFFFF, 0xFFFFFFFD, 0x00000001},476 },
475 []u32{0xFFFFFFFF, 0xFFFFFFFE, 0x00000001},477 []u32{
476 []u32{0xFFFFFFFF, 0xFFFFFFFF, 0x00000001},478 0x00000002,
479 0x078644FA,
480 0x00000000,
481 },
482 []u32{
483 0x00000002,
484 0x0747AE14,
485 0x00000000,
486 },
487 []u32{
488 0x00000002,
489 0x7FFFFFFF,
490 0x00000000,
491 },
492 []u32{
493 0x00000002,
494 0x80000000,
495 0x00000000,
496 },
497 []u32{
498 0x00000002,
499 0xFFFFFFFD,
500 0x00000000,
501 },
502 []u32{
503 0x00000002,
504 0xFFFFFFFE,
505 0x00000000,
506 },
507 []u32{
508 0x00000002,
509 0xFFFFFFFF,
510 0x00000000,
511 },
512 []u32{
513 0x00000003,
514 0x00000001,
515 0x00000003,
516 },
517 []u32{
518 0x00000003,
519 0x00000002,
520 0x00000001,
521 },
522 []u32{
523 0x00000003,
524 0x00000003,
525 0x00000001,
526 },
527 []u32{
528 0x00000003,
529 0x00000010,
530 0x00000000,
531 },
532 []u32{
533 0x00000003,
534 0x078644FA,
535 0x00000000,
536 },
537 []u32{
538 0x00000003,
539 0x0747AE14,
540 0x00000000,
541 },
542 []u32{
543 0x00000003,
544 0x7FFFFFFF,
545 0x00000000,
546 },
547 []u32{
548 0x00000003,
549 0x80000000,
550 0x00000000,
551 },
552 []u32{
553 0x00000003,
554 0xFFFFFFFD,
555 0x00000000,
556 },
557 []u32{
558 0x00000003,
559 0xFFFFFFFE,
560 0x00000000,
561 },
562 []u32{
563 0x00000003,
564 0xFFFFFFFF,
565 0x00000000,
566 },
567 []u32{
568 0x00000010,
569 0x00000001,
570 0x00000010,
571 },
572 []u32{
573 0x00000010,
574 0x00000002,
575 0x00000008,
576 },
577 []u32{
578 0x00000010,
579 0x00000003,
580 0x00000005,
581 },
582 []u32{
583 0x00000010,
584 0x00000010,
585 0x00000001,
586 },
587 []u32{
588 0x00000010,
589 0x078644FA,
590 0x00000000,
591 },
592 []u32{
593 0x00000010,
594 0x0747AE14,
595 0x00000000,
596 },
597 []u32{
598 0x00000010,
599 0x7FFFFFFF,
600 0x00000000,
601 },
602 []u32{
603 0x00000010,
604 0x80000000,
605 0x00000000,
606 },
607 []u32{
608 0x00000010,
609 0xFFFFFFFD,
610 0x00000000,
611 },
612 []u32{
613 0x00000010,
614 0xFFFFFFFE,
615 0x00000000,
616 },
617 []u32{
618 0x00000010,
619 0xFFFFFFFF,
620 0x00000000,
621 },
622 []u32{
623 0x078644FA,
624 0x00000001,
625 0x078644FA,
626 },
627 []u32{
628 0x078644FA,
629 0x00000002,
630 0x03C3227D,
631 },
632 []u32{
633 0x078644FA,
634 0x00000003,
635 0x028216FE,
636 },
637 []u32{
638 0x078644FA,
639 0x00000010,
640 0x0078644F,
641 },
642 []u32{
643 0x078644FA,
644 0x078644FA,
645 0x00000001,
646 },
647 []u32{
648 0x078644FA,
649 0x0747AE14,
650 0x00000001,
651 },
652 []u32{
653 0x078644FA,
654 0x7FFFFFFF,
655 0x00000000,
656 },
657 []u32{
658 0x078644FA,
659 0x80000000,
660 0x00000000,
661 },
662 []u32{
663 0x078644FA,
664 0xFFFFFFFD,
665 0x00000000,
666 },
667 []u32{
668 0x078644FA,
669 0xFFFFFFFE,
670 0x00000000,
671 },
672 []u32{
673 0x078644FA,
674 0xFFFFFFFF,
675 0x00000000,
676 },
677 []u32{
678 0x0747AE14,
679 0x00000001,
680 0x0747AE14,
681 },
682 []u32{
683 0x0747AE14,
684 0x00000002,
685 0x03A3D70A,
686 },
687 []u32{
688 0x0747AE14,
689 0x00000003,
690 0x026D3A06,
691 },
692 []u32{
693 0x0747AE14,
694 0x00000010,
695 0x00747AE1,
696 },
697 []u32{
698 0x0747AE14,
699 0x078644FA,
700 0x00000000,
701 },
702 []u32{
703 0x0747AE14,
704 0x0747AE14,
705 0x00000001,
706 },
707 []u32{
708 0x0747AE14,
709 0x7FFFFFFF,
710 0x00000000,
711 },
712 []u32{
713 0x0747AE14,
714 0x80000000,
715 0x00000000,
716 },
717 []u32{
718 0x0747AE14,
719 0xFFFFFFFD,
720 0x00000000,
721 },
722 []u32{
723 0x0747AE14,
724 0xFFFFFFFE,
725 0x00000000,
726 },
727 []u32{
728 0x0747AE14,
729 0xFFFFFFFF,
730 0x00000000,
731 },
732 []u32{
733 0x7FFFFFFF,
734 0x00000001,
735 0x7FFFFFFF,
736 },
737 []u32{
738 0x7FFFFFFF,
739 0x00000002,
740 0x3FFFFFFF,
741 },
742 []u32{
743 0x7FFFFFFF,
744 0x00000003,
745 0x2AAAAAAA,
746 },
747 []u32{
748 0x7FFFFFFF,
749 0x00000010,
750 0x07FFFFFF,
751 },
752 []u32{
753 0x7FFFFFFF,
754 0x078644FA,
755 0x00000011,
756 },
757 []u32{
758 0x7FFFFFFF,
759 0x0747AE14,
760 0x00000011,
761 },
762 []u32{
763 0x7FFFFFFF,
764 0x7FFFFFFF,
765 0x00000001,
766 },
767 []u32{
768 0x7FFFFFFF,
769 0x80000000,
770 0x00000000,
771 },
772 []u32{
773 0x7FFFFFFF,
774 0xFFFFFFFD,
775 0x00000000,
776 },
777 []u32{
778 0x7FFFFFFF,
779 0xFFFFFFFE,
780 0x00000000,
781 },
782 []u32{
783 0x7FFFFFFF,
784 0xFFFFFFFF,
785 0x00000000,
786 },
787 []u32{
788 0x80000000,
789 0x00000001,
790 0x80000000,
791 },
792 []u32{
793 0x80000000,
794 0x00000002,
795 0x40000000,
796 },
797 []u32{
798 0x80000000,
799 0x00000003,
800 0x2AAAAAAA,
801 },
802 []u32{
803 0x80000000,
804 0x00000010,
805 0x08000000,
806 },
807 []u32{
808 0x80000000,
809 0x078644FA,
810 0x00000011,
811 },
812 []u32{
813 0x80000000,
814 0x0747AE14,
815 0x00000011,
816 },
817 []u32{
818 0x80000000,
819 0x7FFFFFFF,
820 0x00000001,
821 },
822 []u32{
823 0x80000000,
824 0x80000000,
825 0x00000001,
826 },
827 []u32{
828 0x80000000,
829 0xFFFFFFFD,
830 0x00000000,
831 },
832 []u32{
833 0x80000000,
834 0xFFFFFFFE,
835 0x00000000,
836 },
837 []u32{
838 0x80000000,
839 0xFFFFFFFF,
840 0x00000000,
841 },
842 []u32{
843 0xFFFFFFFD,
844 0x00000001,
845 0xFFFFFFFD,
846 },
847 []u32{
848 0xFFFFFFFD,
849 0x00000002,
850 0x7FFFFFFE,
851 },
852 []u32{
853 0xFFFFFFFD,
854 0x00000003,
855 0x55555554,
856 },
857 []u32{
858 0xFFFFFFFD,
859 0x00000010,
860 0x0FFFFFFF,
861 },
862 []u32{
863 0xFFFFFFFD,
864 0x078644FA,
865 0x00000022,
866 },
867 []u32{
868 0xFFFFFFFD,
869 0x0747AE14,
870 0x00000023,
871 },
872 []u32{
873 0xFFFFFFFD,
874 0x7FFFFFFF,
875 0x00000001,
876 },
877 []u32{
878 0xFFFFFFFD,
879 0x80000000,
880 0x00000001,
881 },
882 []u32{
883 0xFFFFFFFD,
884 0xFFFFFFFD,
885 0x00000001,
886 },
887 []u32{
888 0xFFFFFFFD,
889 0xFFFFFFFE,
890 0x00000000,
891 },
892 []u32{
893 0xFFFFFFFD,
894 0xFFFFFFFF,
895 0x00000000,
896 },
897 []u32{
898 0xFFFFFFFE,
899 0x00000001,
900 0xFFFFFFFE,
901 },
902 []u32{
903 0xFFFFFFFE,
904 0x00000002,
905 0x7FFFFFFF,
906 },
907 []u32{
908 0xFFFFFFFE,
909 0x00000003,
910 0x55555554,
911 },
912 []u32{
913 0xFFFFFFFE,
914 0x00000010,
915 0x0FFFFFFF,
916 },
917 []u32{
918 0xFFFFFFFE,
919 0x078644FA,
920 0x00000022,
921 },
922 []u32{
923 0xFFFFFFFE,
924 0x0747AE14,
925 0x00000023,
926 },
927 []u32{
928 0xFFFFFFFE,
929 0x7FFFFFFF,
930 0x00000002,
931 },
932 []u32{
933 0xFFFFFFFE,
934 0x80000000,
935 0x00000001,
936 },
937 []u32{
938 0xFFFFFFFE,
939 0xFFFFFFFD,
940 0x00000001,
941 },
942 []u32{
943 0xFFFFFFFE,
944 0xFFFFFFFE,
945 0x00000001,
946 },
947 []u32{
948 0xFFFFFFFE,
949 0xFFFFFFFF,
950 0x00000000,
951 },
952 []u32{
953 0xFFFFFFFF,
954 0x00000001,
955 0xFFFFFFFF,
956 },
957 []u32{
958 0xFFFFFFFF,
959 0x00000002,
960 0x7FFFFFFF,
961 },
962 []u32{
963 0xFFFFFFFF,
964 0x00000003,
965 0x55555555,
966 },
967 []u32{
968 0xFFFFFFFF,
969 0x00000010,
970 0x0FFFFFFF,
971 },
972 []u32{
973 0xFFFFFFFF,
974 0x078644FA,
975 0x00000022,
976 },
977 []u32{
978 0xFFFFFFFF,
979 0x0747AE14,
980 0x00000023,
981 },
982 []u32{
983 0xFFFFFFFF,
984 0x7FFFFFFF,
985 0x00000002,
986 },
987 []u32{
988 0xFFFFFFFF,
989 0x80000000,
990 0x00000001,
991 },
992 []u32{
993 0xFFFFFFFF,
994 0xFFFFFFFD,
995 0x00000001,
996 },
997 []u32{
998 0xFFFFFFFF,
999 0xFFFFFFFE,
1000 0x00000001,
1001 },
1002 []u32{
1003 0xFFFFFFFF,
1004 0xFFFFFFFF,
1005 0x00000001,
1006 },
477 };1007 };
4781008
479 for (cases) |case| {1009 for (cases) |case| {
std/special/compiler_rt/udivmod.zig+23-20
...@@ -1,7 +1,10 @@...@@ -1,7 +1,10 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const is_test = builtin.is_test;2const is_test = builtin.is_test;
33
4const low = switch (builtin.endian) { builtin.Endian.Big => 1, builtin.Endian.Little => 0 };4const low = switch (builtin.endian) {
5 builtin.Endian.Big => 1,
6 builtin.Endian.Little => 0,
7};
5const high = 1 - low;8const high = 1 - low;
69
7pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?&DoubleInt) DoubleInt {10pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?&DoubleInt) DoubleInt {
...@@ -11,8 +14,8 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -11,8 +14,8 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
11 const SignedDoubleInt = @IntType(true, DoubleInt.bit_count);14 const SignedDoubleInt = @IntType(true, DoubleInt.bit_count);
12 const Log2SingleInt = @import("std").math.Log2Int(SingleInt);15 const Log2SingleInt = @import("std").math.Log2Int(SingleInt);
1316
14 const n = *@ptrCast(&const [2]SingleInt, &a); // TODO issue #42117 const n = @ptrCast(&const [2]SingleInt, &a).*; // TODO issue #421
15 const d = *@ptrCast(&const [2]SingleInt, &b); // TODO issue #42118 const d = @ptrCast(&const [2]SingleInt, &b).*; // TODO issue #421
16 var q: [2]SingleInt = undefined;19 var q: [2]SingleInt = undefined;
17 var r: [2]SingleInt = undefined;20 var r: [2]SingleInt = undefined;
18 var sr: c_uint = undefined;21 var sr: c_uint = undefined;
...@@ -23,7 +26,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -23,7 +26,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
23 // ---26 // ---
24 // 0 X27 // 0 X
25 if (maybe_rem) |rem| {28 if (maybe_rem) |rem| {
26 *rem = n[low] % d[low];29 rem.* = n[low] % d[low];
27 }30 }
28 return n[low] / d[low];31 return n[low] / d[low];
29 }32 }
...@@ -31,7 +34,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -31,7 +34,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
31 // ---34 // ---
32 // K X35 // K X
33 if (maybe_rem) |rem| {36 if (maybe_rem) |rem| {
34 *rem = n[low];37 rem.* = n[low];
35 }38 }
36 return 0;39 return 0;
37 }40 }
...@@ -42,7 +45,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -42,7 +45,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
42 // ---45 // ---
43 // 0 046 // 0 0
44 if (maybe_rem) |rem| {47 if (maybe_rem) |rem| {
45 *rem = n[high] % d[low];48 rem.* = n[high] % d[low];
46 }49 }
47 return n[high] / d[low];50 return n[high] / d[low];
48 }51 }
...@@ -54,7 +57,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -54,7 +57,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
54 if (maybe_rem) |rem| {57 if (maybe_rem) |rem| {
55 r[high] = n[high] % d[high];58 r[high] = n[high] % d[high];
56 r[low] = 0;59 r[low] = 0;
57 *rem = *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]); // TODO issue #42160 rem.* = @ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
58 }61 }
59 return n[high] / d[high];62 return n[high] / d[high];
60 }63 }
...@@ -66,7 +69,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -66,7 +69,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
66 if (maybe_rem) |rem| {69 if (maybe_rem) |rem| {
67 r[low] = n[low];70 r[low] = n[low];
68 r[high] = n[high] & (d[high] - 1);71 r[high] = n[high] & (d[high] - 1);
69 *rem = *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]); // TODO issue #42172 rem.* = @ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
70 }73 }
71 return n[high] >> Log2SingleInt(@ctz(d[high]));74 return n[high] >> Log2SingleInt(@ctz(d[high]));
72 }75 }
...@@ -77,7 +80,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -77,7 +80,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
77 // 0 <= sr <= SingleInt.bit_count - 2 or sr large80 // 0 <= sr <= SingleInt.bit_count - 2 or sr large
78 if (sr > SingleInt.bit_count - 2) {81 if (sr > SingleInt.bit_count - 2) {
79 if (maybe_rem) |rem| {82 if (maybe_rem) |rem| {
80 *rem = a;83 rem.* = a;
81 }84 }
82 return 0;85 return 0;
83 }86 }
...@@ -98,7 +101,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -98,7 +101,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
98 if ((d[low] & (d[low] - 1)) == 0) {101 if ((d[low] & (d[low] - 1)) == 0) {
99 // d is a power of 2102 // d is a power of 2
100 if (maybe_rem) |rem| {103 if (maybe_rem) |rem| {
101 *rem = n[low] & (d[low] - 1);104 rem.* = n[low] & (d[low] - 1);
102 }105 }
103 if (d[low] == 1) {106 if (d[low] == 1) {
104 return a;107 return a;
...@@ -106,7 +109,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -106,7 +109,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
106 sr = @ctz(d[low]);109 sr = @ctz(d[low]);
107 q[high] = n[high] >> Log2SingleInt(sr);110 q[high] = n[high] >> Log2SingleInt(sr);
108 q[low] = (n[high] << Log2SingleInt(SingleInt.bit_count - sr)) | (n[low] >> Log2SingleInt(sr));111 q[low] = (n[high] << Log2SingleInt(SingleInt.bit_count - sr)) | (n[low] >> Log2SingleInt(sr));
109 return *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &q[0]); // TODO issue #421112 return @ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &q[0]).*; // TODO issue #421
110 }113 }
111 // K X114 // K X
112 // ---115 // ---
...@@ -141,7 +144,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -141,7 +144,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
141 // 0 <= sr <= SingleInt.bit_count - 1 or sr large144 // 0 <= sr <= SingleInt.bit_count - 1 or sr large
142 if (sr > SingleInt.bit_count - 1) {145 if (sr > SingleInt.bit_count - 1) {
143 if (maybe_rem) |rem| {146 if (maybe_rem) |rem| {
144 *rem = a;147 rem.* = a;
145 }148 }
146 return 0;149 return 0;
147 }150 }
...@@ -170,25 +173,25 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -170,25 +173,25 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
170 var r_all: DoubleInt = undefined;173 var r_all: DoubleInt = undefined;
171 while (sr > 0) : (sr -= 1) {174 while (sr > 0) : (sr -= 1) {
172 // r:q = ((r:q) << 1) | carry175 // r:q = ((r:q) << 1) | carry
173 r[high] = (r[high] << 1) | (r[low] >> (SingleInt.bit_count - 1));176 r[high] = (r[high] << 1) | (r[low] >> (SingleInt.bit_count - 1));
174 r[low] = (r[low] << 1) | (q[high] >> (SingleInt.bit_count - 1));177 r[low] = (r[low] << 1) | (q[high] >> (SingleInt.bit_count - 1));
175 q[high] = (q[high] << 1) | (q[low] >> (SingleInt.bit_count - 1));178 q[high] = (q[high] << 1) | (q[low] >> (SingleInt.bit_count - 1));
176 q[low] = (q[low] << 1) | carry;179 q[low] = (q[low] << 1) | carry;
177 // carry = 0;180 // carry = 0;
178 // if (r.all >= b)181 // if (r.all >= b)
179 // {182 // {
180 // r.all -= b;183 // r.all -= b;
181 // carry = 1;184 // carry = 1;
182 // }185 // }
183 r_all = *@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]); // TODO issue #421186 r_all = @ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
184 const s: SignedDoubleInt = SignedDoubleInt(b -% r_all -% 1) >> (DoubleInt.bit_count - 1);187 const s: SignedDoubleInt = SignedDoubleInt(b -% r_all -% 1) >> (DoubleInt.bit_count - 1);
185 carry = u32(s & 1);188 carry = u32(s & 1);
186 r_all -= b & @bitCast(DoubleInt, s);189 r_all -= b & @bitCast(DoubleInt, s);
187 r = *@ptrCast(&[2]SingleInt, &r_all); // TODO issue #421190 r = @ptrCast(&[2]SingleInt, &r_all).*; // TODO issue #421
188 }191 }
189 const q_all = ((*@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &q[0])) << 1) | carry; // TODO issue #421192 const q_all = ((@ptrCast(&align(@alignOf(SingleInt)) DoubleInt, &q[0]).*) << 1) | carry; // TODO issue #421
190 if (maybe_rem) |rem| {193 if (maybe_rem) |rem| {
191 *rem = r_all;194 rem.* = r_all;
192 }195 }
193 return q_all;196 return q_all;
194}197}
std/special/compiler_rt/udivmodti4.zig+1-1
...@@ -9,7 +9,7 @@ pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) u128 {...@@ -9,7 +9,7 @@ pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) u128 {
99
10pub extern fn __udivmodti4_windows_x86_64(a: &const u128, b: &const u128, maybe_rem: ?&u128) void {10pub extern fn __udivmodti4_windows_x86_64(a: &const u128, b: &const u128, maybe_rem: ?&u128) void {
11 @setRuntimeSafety(builtin.is_test);11 @setRuntimeSafety(builtin.is_test);
12 compiler_rt.setXmm0(u128, udivmod(u128, *a, *b, maybe_rem));12 compiler_rt.setXmm0(u128, udivmod(u128, a.*, b.*, maybe_rem));
13}13}
1414
15test "import udivmodti4" {15test "import udivmodti4" {
std/special/compiler_rt/umodti3.zig+1-1
...@@ -11,5 +11,5 @@ pub extern fn __umodti3(a: u128, b: u128) u128 {...@@ -11,5 +11,5 @@ pub extern fn __umodti3(a: u128, b: u128) u128 {
1111
12pub extern fn __umodti3_windows_x86_64(a: &const u128, b: &const u128) void {12pub extern fn __umodti3_windows_x86_64(a: &const u128, b: &const u128) void {
13 @setRuntimeSafety(builtin.is_test);13 @setRuntimeSafety(builtin.is_test);
14 compiler_rt.setXmm0(u128, __umodti3(*a, *b));14 compiler_rt.setXmm0(u128, __umodti3(a.*, b.*));
15}15}
std/zig/ast.zig+123-105
...@@ -40,7 +40,7 @@ pub const Tree = struct {...@@ -40,7 +40,7 @@ pub const Tree = struct {
40 };40 };
4141
42 pub fn tokenLocationPtr(self: &Tree, start_index: usize, token: &const Token) Location {42 pub fn tokenLocationPtr(self: &Tree, start_index: usize, token: &const Token) Location {
43 var loc = Location {43 var loc = Location{
44 .line = 0,44 .line = 0,
45 .column = 0,45 .column = 0,
46 .line_start = start_index,46 .line_start = start_index,
...@@ -67,6 +67,28 @@ pub const Tree = struct {...@@ -67,6 +67,28 @@ pub const Tree = struct {
67 pub fn tokenLocation(self: &Tree, start_index: usize, token_index: TokenIndex) Location {67 pub fn tokenLocation(self: &Tree, start_index: usize, token_index: TokenIndex) Location {
68 return self.tokenLocationPtr(start_index, self.tokens.at(token_index));68 return self.tokenLocationPtr(start_index, self.tokens.at(token_index));
69 }69 }
70
71 pub fn dump(self: &Tree) void {
72 self.root_node.base.dump(0);
73 }
74
75 /// Skips over comments
76 pub fn prevToken(self: &Tree, token_index: TokenIndex) TokenIndex {
77 var index = token_index - 1;
78 while (self.tokens.at(index).id == Token.Id.LineComment) {
79 index -= 1;
80 }
81 return index;
82 }
83
84 /// Skips over comments
85 pub fn nextToken(self: &Tree, token_index: TokenIndex) TokenIndex {
86 var index = token_index + 1;
87 while (self.tokens.at(index).id == Token.Id.LineComment) {
88 index += 1;
89 }
90 return index;
91 }
70};92};
7193
72pub const Error = union(enum) {94pub const Error = union(enum) {
...@@ -76,6 +98,7 @@ pub const Error = union(enum) {...@@ -76,6 +98,7 @@ pub const Error = union(enum) {
76 UnattachedDocComment: UnattachedDocComment,98 UnattachedDocComment: UnattachedDocComment,
77 ExpectedEqOrSemi: ExpectedEqOrSemi,99 ExpectedEqOrSemi: ExpectedEqOrSemi,
78 ExpectedSemiOrLBrace: ExpectedSemiOrLBrace,100 ExpectedSemiOrLBrace: ExpectedSemiOrLBrace,
101 ExpectedColonOrRParen: ExpectedColonOrRParen,
79 ExpectedLabelable: ExpectedLabelable,102 ExpectedLabelable: ExpectedLabelable,
80 ExpectedInlinable: ExpectedInlinable,103 ExpectedInlinable: ExpectedInlinable,
81 ExpectedAsmOutputReturnOrType: ExpectedAsmOutputReturnOrType,104 ExpectedAsmOutputReturnOrType: ExpectedAsmOutputReturnOrType,
...@@ -90,14 +113,15 @@ pub const Error = union(enum) {...@@ -90,14 +113,15 @@ pub const Error = union(enum) {
90 ExpectedCommaOrEnd: ExpectedCommaOrEnd,113 ExpectedCommaOrEnd: ExpectedCommaOrEnd,
91114
92 pub fn render(self: &Error, tokens: &Tree.TokenList, stream: var) !void {115 pub fn render(self: &Error, tokens: &Tree.TokenList, stream: var) !void {
93 switch (*self) {116 switch (self.*) {
94 // TODO https://github.com/zig-lang/zig/issues/683117 // TODO https://github.com/ziglang/zig/issues/683
95 @TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),118 @TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
96 @TagType(Error).ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),119 @TagType(Error).ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
97 @TagType(Error).ExpectedAggregateKw => |*x| return x.render(tokens, stream),120 @TagType(Error).ExpectedAggregateKw => |*x| return x.render(tokens, stream),
98 @TagType(Error).UnattachedDocComment => |*x| return x.render(tokens, stream),121 @TagType(Error).UnattachedDocComment => |*x| return x.render(tokens, stream),
99 @TagType(Error).ExpectedEqOrSemi => |*x| return x.render(tokens, stream),122 @TagType(Error).ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
100 @TagType(Error).ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),123 @TagType(Error).ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
124 @TagType(Error).ExpectedColonOrRParen => |*x| return x.render(tokens, stream),
101 @TagType(Error).ExpectedLabelable => |*x| return x.render(tokens, stream),125 @TagType(Error).ExpectedLabelable => |*x| return x.render(tokens, stream),
102 @TagType(Error).ExpectedInlinable => |*x| return x.render(tokens, stream),126 @TagType(Error).ExpectedInlinable => |*x| return x.render(tokens, stream),
103 @TagType(Error).ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),127 @TagType(Error).ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),
...@@ -114,14 +138,15 @@ pub const Error = union(enum) {...@@ -114,14 +138,15 @@ pub const Error = union(enum) {
114 }138 }
115139
116 pub fn loc(self: &Error) TokenIndex {140 pub fn loc(self: &Error) TokenIndex {
117 switch (*self) {141 switch (self.*) {
118 // TODO https://github.com/zig-lang/zig/issues/683142 // TODO https://github.com/ziglang/zig/issues/683
119 @TagType(Error).InvalidToken => |x| return x.token,143 @TagType(Error).InvalidToken => |x| return x.token,
120 @TagType(Error).ExpectedVarDeclOrFn => |x| return x.token,144 @TagType(Error).ExpectedVarDeclOrFn => |x| return x.token,
121 @TagType(Error).ExpectedAggregateKw => |x| return x.token,145 @TagType(Error).ExpectedAggregateKw => |x| return x.token,
122 @TagType(Error).UnattachedDocComment => |x| return x.token,146 @TagType(Error).UnattachedDocComment => |x| return x.token,
123 @TagType(Error).ExpectedEqOrSemi => |x| return x.token,147 @TagType(Error).ExpectedEqOrSemi => |x| return x.token,
124 @TagType(Error).ExpectedSemiOrLBrace => |x| return x.token,148 @TagType(Error).ExpectedSemiOrLBrace => |x| return x.token,
149 @TagType(Error).ExpectedColonOrRParen => |x| return x.token,
125 @TagType(Error).ExpectedLabelable => |x| return x.token,150 @TagType(Error).ExpectedLabelable => |x| return x.token,
126 @TagType(Error).ExpectedInlinable => |x| return x.token,151 @TagType(Error).ExpectedInlinable => |x| return x.token,
127 @TagType(Error).ExpectedAsmOutputReturnOrType => |x| return x.token,152 @TagType(Error).ExpectedAsmOutputReturnOrType => |x| return x.token,
...@@ -139,15 +164,13 @@ pub const Error = union(enum) {...@@ -139,15 +164,13 @@ pub const Error = union(enum) {
139164
140 pub const InvalidToken = SingleTokenError("Invalid token {}");165 pub const InvalidToken = SingleTokenError("Invalid token {}");
141 pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found {}");166 pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found {}");
142 pub const ExpectedAggregateKw = SingleTokenError("Expected " ++167 pub const ExpectedAggregateKw = SingleTokenError("Expected " ++ @tagName(Token.Id.Keyword_struct) ++ ", " ++ @tagName(Token.Id.Keyword_union) ++ ", or " ++ @tagName(Token.Id.Keyword_enum) ++ ", found {}");
143 @tagName(Token.Id.Keyword_struct) ++ ", " ++ @tagName(Token.Id.Keyword_union) ++ ", or " ++
144 @tagName(Token.Id.Keyword_enum) ++ ", found {}");
145 pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found {}");168 pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found {}");
146 pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found {}");169 pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found {}");
170 pub const ExpectedColonOrRParen = SingleTokenError("Expected ':' or ')', found {}");
147 pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found {}");171 pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found {}");
148 pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found {}");172 pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found {}");
149 pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or " ++173 pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or " ++ @tagName(Token.Id.Identifier) ++ ", found {}");
150 @tagName(Token.Id.Identifier) ++ ", found {}");
151 pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found {}");174 pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found {}");
152 pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found {}");175 pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found {}");
153176
...@@ -160,8 +183,7 @@ pub const Error = union(enum) {...@@ -160,8 +183,7 @@ pub const Error = union(enum) {
160 node: &Node,183 node: &Node,
161184
162 pub fn render(self: &ExpectedCall, tokens: &Tree.TokenList, stream: var) !void {185 pub fn render(self: &ExpectedCall, tokens: &Tree.TokenList, stream: var) !void {
163 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}",186 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", @tagName(self.node.id));
164 @tagName(self.node.id));
165 }187 }
166 };188 };
167189
...@@ -169,8 +191,7 @@ pub const Error = union(enum) {...@@ -169,8 +191,7 @@ pub const Error = union(enum) {
169 node: &Node,191 node: &Node,
170192
171 pub fn render(self: &ExpectedCallOrFnProto, tokens: &Tree.TokenList, stream: var) !void {193 pub fn render(self: &ExpectedCallOrFnProto, tokens: &Tree.TokenList, stream: var) !void {
172 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++194 return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++ @tagName(Node.Id.FnProto) ++ ", found {}", @tagName(self.node.id));
173 @tagName(Node.Id.FnProto) ++ ", found {}", @tagName(self.node.id));
174 }195 }
175 };196 };
176197
...@@ -273,7 +294,6 @@ pub const Node = struct {...@@ -273,7 +294,6 @@ pub const Node = struct {
273 Block,294 Block,
274295
275 // Misc296 // Misc
276 LineComment,
277 DocComment,297 DocComment,
278 SwitchCase,298 SwitchCase,
279 SwitchElse,299 SwitchElse,
...@@ -360,7 +380,6 @@ pub const Node = struct {...@@ -360,7 +380,6 @@ pub const Node = struct {
360 Id.SwitchElse,380 Id.SwitchElse,
361 Id.FieldInitializer,381 Id.FieldInitializer,
362 Id.DocComment,382 Id.DocComment,
363 Id.LineComment,
364 Id.TestDecl => return false,383 Id.TestDecl => return false,
365 Id.While => {384 Id.While => {
366 const while_node = @fieldParentPtr(While, "base", n);385 const while_node = @fieldParentPtr(While, "base", n);
...@@ -415,6 +434,20 @@ pub const Node = struct {...@@ -415,6 +434,20 @@ pub const Node = struct {
415 }434 }
416 }435 }
417436
437 pub fn dump(self: &Node, indent: usize) void {
438 {
439 var i: usize = 0;
440 while (i < indent) : (i += 1) {
441 std.debug.warn(" ");
442 }
443 }
444 std.debug.warn("{}\n", @tagName(self.id));
445
446 var child_i: usize = 0;
447 while (self.iterate(child_i)) |child| : (child_i += 1) {
448 child.dump(indent + 2);
449 }
450 }
418451
419 pub const Root = struct {452 pub const Root = struct {
420 base: Node,453 base: Node,
...@@ -426,17 +459,17 @@ pub const Node = struct {...@@ -426,17 +459,17 @@ pub const Node = struct {
426459
427 pub fn iterate(self: &Root, index: usize) ?&Node {460 pub fn iterate(self: &Root, index: usize) ?&Node {
428 if (index < self.decls.len) {461 if (index < self.decls.len) {
429 return self.decls.items[self.decls.len - index - 1];462 return self.decls.at(index).*;
430 }463 }
431 return null;464 return null;
432 }465 }
433466
434 pub fn firstToken(self: &Root) TokenIndex {467 pub fn firstToken(self: &Root) TokenIndex {
435 return if (self.decls.len == 0) self.eof_token else (*self.decls.at(0)).firstToken();468 return if (self.decls.len == 0) self.eof_token else (self.decls.at(0).*).firstToken();
436 }469 }
437470
438 pub fn lastToken(self: &Root) TokenIndex {471 pub fn lastToken(self: &Root) TokenIndex {
439 return if (self.decls.len == 0) self.eof_token else (*self.decls.at(self.decls.len - 1)).lastToken();472 return if (self.decls.len == 0) self.eof_token else (self.decls.at(self.decls.len - 1).*).lastToken();
440 }473 }
441 };474 };
442475
...@@ -493,6 +526,7 @@ pub const Node = struct {...@@ -493,6 +526,7 @@ pub const Node = struct {
493 base: Node,526 base: Node,
494 doc_comments: ?&DocComment,527 doc_comments: ?&DocComment,
495 visib_token: ?TokenIndex,528 visib_token: ?TokenIndex,
529 use_token: TokenIndex,
496 expr: &Node,530 expr: &Node,
497 semicolon_token: TokenIndex,531 semicolon_token: TokenIndex,
498532
...@@ -507,7 +541,7 @@ pub const Node = struct {...@@ -507,7 +541,7 @@ pub const Node = struct {
507541
508 pub fn firstToken(self: &Use) TokenIndex {542 pub fn firstToken(self: &Use) TokenIndex {
509 if (self.visib_token) |visib_token| return visib_token;543 if (self.visib_token) |visib_token| return visib_token;
510 return self.expr.firstToken();544 return self.use_token;
511 }545 }
512546
513 pub fn lastToken(self: &Use) TokenIndex {547 pub fn lastToken(self: &Use) TokenIndex {
...@@ -526,7 +560,7 @@ pub const Node = struct {...@@ -526,7 +560,7 @@ pub const Node = struct {
526 pub fn iterate(self: &ErrorSetDecl, index: usize) ?&Node {560 pub fn iterate(self: &ErrorSetDecl, index: usize) ?&Node {
527 var i = index;561 var i = index;
528562
529 if (i < self.decls.len) return *self.decls.at(i);563 if (i < self.decls.len) return self.decls.at(i).*;
530 i -= self.decls.len;564 i -= self.decls.len;
531565
532 return null;566 return null;
...@@ -543,27 +577,15 @@ pub const Node = struct {...@@ -543,27 +577,15 @@ pub const Node = struct {
543577
544 pub const ContainerDecl = struct {578 pub const ContainerDecl = struct {
545 base: Node,579 base: Node,
546 ltoken: TokenIndex,580 layout_token: ?TokenIndex,
547 layout: Layout,581 kind_token: TokenIndex,
548 kind: Kind,
549 init_arg_expr: InitArg,582 init_arg_expr: InitArg,
550 fields_and_decls: DeclList,583 fields_and_decls: DeclList,
584 lbrace_token: TokenIndex,
551 rbrace_token: TokenIndex,585 rbrace_token: TokenIndex,
552586
553 pub const DeclList = Root.DeclList;587 pub const DeclList = Root.DeclList;
554588
555 const Layout = enum {
556 Auto,
557 Extern,
558 Packed,
559 };
560
561 const Kind = enum {
562 Struct,
563 Enum,
564 Union,
565 };
566
567 const InitArg = union(enum) {589 const InitArg = union(enum) {
568 None,590 None,
569 Enum: ?&Node,591 Enum: ?&Node,
...@@ -579,17 +601,20 @@ pub const Node = struct {...@@ -579,17 +601,20 @@ pub const Node = struct {
579 i -= 1;601 i -= 1;
580 },602 },
581 InitArg.None,603 InitArg.None,
582 InitArg.Enum => { }604 InitArg.Enum => {},
583 }605 }
584606
585 if (i < self.fields_and_decls.len) return *self.fields_and_decls.at(i);607 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*;
586 i -= self.fields_and_decls.len;608 i -= self.fields_and_decls.len;
587609
588 return null;610 return null;
589 }611 }
590612
591 pub fn firstToken(self: &ContainerDecl) TokenIndex {613 pub fn firstToken(self: &ContainerDecl) TokenIndex {
592 return self.ltoken;614 if (self.layout_token) |layout_token| {
615 return layout_token;
616 }
617 return self.kind_token;
593 }618 }
594619
595 pub fn lastToken(self: &ContainerDecl) TokenIndex {620 pub fn lastToken(self: &ContainerDecl) TokenIndex {
...@@ -790,8 +815,16 @@ pub const Node = struct {...@@ -790,8 +815,16 @@ pub const Node = struct {
790 pub fn iterate(self: &FnProto, index: usize) ?&Node {815 pub fn iterate(self: &FnProto, index: usize) ?&Node {
791 var i = index;816 var i = index;
792817
793 if (self.body_node) |body_node| {818 if (self.lib_name) |lib_name| {
794 if (i < 1) return body_node;819 if (i < 1) return lib_name;
820 i -= 1;
821 }
822
823 if (i < self.params.len) return self.params.at(self.params.len - i - 1).*;
824 i -= self.params.len;
825
826 if (self.align_expr) |align_expr| {
827 if (i < 1) return align_expr;
795 i -= 1;828 i -= 1;
796 }829 }
797830
...@@ -807,16 +840,8 @@ pub const Node = struct {...@@ -807,16 +840,8 @@ pub const Node = struct {
807 },840 },
808 }841 }
809842
810 if (self.align_expr) |align_expr| {843 if (self.body_node) |body_node| {
811 if (i < 1) return align_expr;844 if (i < 1) return body_node;
812 i -= 1;
813 }
814
815 if (i < self.params.len) return self.params.items[self.params.len - i - 1];
816 i -= self.params.len;
817
818 if (self.lib_name) |lib_name| {
819 if (i < 1) return lib_name;
820 i -= 1;845 i -= 1;
821 }846 }
822847
...@@ -914,7 +939,7 @@ pub const Node = struct {...@@ -914,7 +939,7 @@ pub const Node = struct {
914 pub fn iterate(self: &Block, index: usize) ?&Node {939 pub fn iterate(self: &Block, index: usize) ?&Node {
915 var i = index;940 var i = index;
916941
917 if (i < self.statements.len) return self.statements.items[i];942 if (i < self.statements.len) return self.statements.at(i).*;
918 i -= self.statements.len;943 i -= self.statements.len;
919944
920 return null;945 return null;
...@@ -1099,7 +1124,8 @@ pub const Node = struct {...@@ -1099,7 +1124,8 @@ pub const Node = struct {
1099 base: Node,1124 base: Node,
1100 switch_token: TokenIndex,1125 switch_token: TokenIndex,
1101 expr: &Node,1126 expr: &Node,
1102 /// these can be SwitchCase nodes or LineComment nodes1127
1128 /// these must be SwitchCase nodes
1103 cases: CaseList,1129 cases: CaseList,
1104 rbrace: TokenIndex,1130 rbrace: TokenIndex,
11051131
...@@ -1111,7 +1137,7 @@ pub const Node = struct {...@@ -1111,7 +1137,7 @@ pub const Node = struct {
1111 if (i < 1) return self.expr;1137 if (i < 1) return self.expr;
1112 i -= 1;1138 i -= 1;
11131139
1114 if (i < self.cases.len) return *self.cases.at(i);1140 if (i < self.cases.len) return self.cases.at(i).*;
1115 i -= self.cases.len;1141 i -= self.cases.len;
11161142
1117 return null;1143 return null;
...@@ -1129,6 +1155,7 @@ pub const Node = struct {...@@ -1129,6 +1155,7 @@ pub const Node = struct {
1129 pub const SwitchCase = struct {1155 pub const SwitchCase = struct {
1130 base: Node,1156 base: Node,
1131 items: ItemList,1157 items: ItemList,
1158 arrow_token: TokenIndex,
1132 payload: ?&Node,1159 payload: ?&Node,
1133 expr: &Node,1160 expr: &Node,
11341161
...@@ -1137,7 +1164,7 @@ pub const Node = struct {...@@ -1137,7 +1164,7 @@ pub const Node = struct {
1137 pub fn iterate(self: &SwitchCase, index: usize) ?&Node {1164 pub fn iterate(self: &SwitchCase, index: usize) ?&Node {
1138 var i = index;1165 var i = index;
11391166
1140 if (i < self.items.len) return *self.items.at(i);1167 if (i < self.items.len) return self.items.at(i).*;
1141 i -= self.items.len;1168 i -= self.items.len;
11421169
1143 if (self.payload) |payload| {1170 if (self.payload) |payload| {
...@@ -1152,7 +1179,7 @@ pub const Node = struct {...@@ -1152,7 +1179,7 @@ pub const Node = struct {
1152 }1179 }
11531180
1154 pub fn firstToken(self: &SwitchCase) TokenIndex {1181 pub fn firstToken(self: &SwitchCase) TokenIndex {
1155 return (*self.items.at(0)).firstToken();1182 return (self.items.at(0).*).firstToken();
1156 }1183 }
11571184
1158 pub fn lastToken(self: &SwitchCase) TokenIndex {1185 pub fn lastToken(self: &SwitchCase) TokenIndex {
...@@ -1464,14 +1491,14 @@ pub const Node = struct {...@@ -1464,14 +1491,14 @@ pub const Node = struct {
1464 op: Op,1491 op: Op,
1465 rhs: &Node,1492 rhs: &Node,
14661493
1467 const Op = union(enum) {1494 pub const Op = union(enum) {
1468 AddrOf: AddrOfInfo,1495 AddrOf: AddrOfInfo,
1469 ArrayType: &Node,1496 ArrayType: &Node,
1470 Await,1497 Await,
1471 BitNot,1498 BitNot,
1472 BoolNot,1499 BoolNot,
1473 Cancel,1500 Cancel,
1474 Deref,1501 PointerType,
1475 MaybeType,1502 MaybeType,
1476 Negation,1503 Negation,
1477 NegationWrap,1504 NegationWrap,
...@@ -1481,12 +1508,20 @@ pub const Node = struct {...@@ -1481,12 +1508,20 @@ pub const Node = struct {
1481 UnwrapMaybe,1508 UnwrapMaybe,
1482 };1509 };
14831510
1484 const AddrOfInfo = struct {1511 pub const AddrOfInfo = struct {
1485 align_expr: ?&Node,1512 align_info: ?Align,
1486 bit_offset_start_token: ?TokenIndex,
1487 bit_offset_end_token: ?TokenIndex,
1488 const_token: ?TokenIndex,1513 const_token: ?TokenIndex,
1489 volatile_token: ?TokenIndex,1514 volatile_token: ?TokenIndex,
1515
1516 pub const Align = struct {
1517 node: &Node,
1518 bit_range: ?BitRange,
1519
1520 pub const BitRange = struct {
1521 start: &Node,
1522 end: &Node,
1523 };
1524 };
1490 };1525 };
14911526
1492 pub fn iterate(self: &PrefixOp, index: usize) ?&Node {1527 pub fn iterate(self: &PrefixOp, index: usize) ?&Node {
...@@ -1513,7 +1548,6 @@ pub const Node = struct {...@@ -1513,7 +1548,6 @@ pub const Node = struct {
1513 Op.BitNot,1548 Op.BitNot,
1514 Op.BoolNot,1549 Op.BoolNot,
1515 Op.Cancel,1550 Op.Cancel,
1516 Op.Deref,
1517 Op.MaybeType,1551 Op.MaybeType,
1518 Op.Negation,1552 Op.Negation,
1519 Op.NegationWrap,1553 Op.NegationWrap,
...@@ -1573,6 +1607,7 @@ pub const Node = struct {...@@ -1573,6 +1607,7 @@ pub const Node = struct {
1573 Slice: Slice,1607 Slice: Slice,
1574 ArrayInitializer: InitList,1608 ArrayInitializer: InitList,
1575 StructInitializer: InitList,1609 StructInitializer: InitList,
1610 Deref,
15761611
1577 pub const InitList = SegmentedList(&Node, 2);1612 pub const InitList = SegmentedList(&Node, 2);
15781613
...@@ -1596,15 +1631,15 @@ pub const Node = struct {...@@ -1596,15 +1631,15 @@ pub const Node = struct {
1596 i -= 1;1631 i -= 1;
15971632
1598 switch (self.op) {1633 switch (self.op) {
1599 Op.Call => |call_info| {1634 @TagType(Op).Call => |*call_info| {
1600 if (i < call_info.params.len) return *call_info.params.at(i);1635 if (i < call_info.params.len) return call_info.params.at(i).*;
1601 i -= call_info.params.len;1636 i -= call_info.params.len;
1602 },1637 },
1603 Op.ArrayAccess => |index_expr| {1638 Op.ArrayAccess => |index_expr| {
1604 if (i < 1) return index_expr;1639 if (i < 1) return index_expr;
1605 i -= 1;1640 i -= 1;
1606 },1641 },
1607 Op.Slice => |range| {1642 @TagType(Op).Slice => |range| {
1608 if (i < 1) return range.start;1643 if (i < 1) return range.start;
1609 i -= 1;1644 i -= 1;
16101645
...@@ -1613,12 +1648,12 @@ pub const Node = struct {...@@ -1613,12 +1648,12 @@ pub const Node = struct {
1613 i -= 1;1648 i -= 1;
1614 }1649 }
1615 },1650 },
1616 Op.ArrayInitializer => |exprs| {1651 Op.ArrayInitializer => |*exprs| {
1617 if (i < exprs.len) return *exprs.at(i);1652 if (i < exprs.len) return exprs.at(i).*;
1618 i -= exprs.len;1653 i -= exprs.len;
1619 },1654 },
1620 Op.StructInitializer => |fields| {1655 Op.StructInitializer => |*fields| {
1621 if (i < fields.len) return *fields.at(i);1656 if (i < fields.len) return fields.at(i).*;
1622 i -= fields.len;1657 i -= fields.len;
1623 },1658 },
1624 }1659 }
...@@ -1811,7 +1846,7 @@ pub const Node = struct {...@@ -1811,7 +1846,7 @@ pub const Node = struct {
1811 pub fn iterate(self: &BuiltinCall, index: usize) ?&Node {1846 pub fn iterate(self: &BuiltinCall, index: usize) ?&Node {
1812 var i = index;1847 var i = index;
18131848
1814 if (i < self.params.len) return *self.params.at(i);1849 if (i < self.params.len) return self.params.at(i).*;
1815 i -= self.params.len;1850 i -= self.params.len;
18161851
1817 return null;1852 return null;
...@@ -1854,11 +1889,11 @@ pub const Node = struct {...@@ -1854,11 +1889,11 @@ pub const Node = struct {
1854 }1889 }
18551890
1856 pub fn firstToken(self: &MultilineStringLiteral) TokenIndex {1891 pub fn firstToken(self: &MultilineStringLiteral) TokenIndex {
1857 return *self.lines.at(0);1892 return self.lines.at(0).*;
1858 }1893 }
18591894
1860 pub fn lastToken(self: &MultilineStringLiteral) TokenIndex {1895 pub fn lastToken(self: &MultilineStringLiteral) TokenIndex {
1861 return *self.lines.at(self.lines.len - 1);1896 return self.lines.at(self.lines.len - 1).*;
1862 }1897 }
1863 };1898 };
18641899
...@@ -1949,13 +1984,15 @@ pub const Node = struct {...@@ -1949,13 +1984,15 @@ pub const Node = struct {
19491984
1950 pub const AsmOutput = struct {1985 pub const AsmOutput = struct {
1951 base: Node,1986 base: Node,
1987 lbracket: TokenIndex,
1952 symbolic_name: &Node,1988 symbolic_name: &Node,
1953 constraint: &Node,1989 constraint: &Node,
1954 kind: Kind,1990 kind: Kind,
1991 rparen: TokenIndex,
19551992
1956 const Kind = union(enum) {1993 const Kind = union(enum) {
1957 Variable: &Identifier,1994 Variable: &Identifier,
1958 Return: &Node1995 Return: &Node,
1959 };1996 };
19601997
1961 pub fn iterate(self: &AsmOutput, index: usize) ?&Node {1998 pub fn iterate(self: &AsmOutput, index: usize) ?&Node {
...@@ -1975,29 +2012,28 @@ pub const Node = struct {...@@ -1975,29 +2012,28 @@ pub const Node = struct {
1975 Kind.Return => |return_type| {2012 Kind.Return => |return_type| {
1976 if (i < 1) return return_type;2013 if (i < 1) return return_type;
1977 i -= 1;2014 i -= 1;
1978 }2015 },
1979 }2016 }
19802017
1981 return null;2018 return null;
1982 }2019 }
19832020
1984 pub fn firstToken(self: &AsmOutput) TokenIndex {2021 pub fn firstToken(self: &AsmOutput) TokenIndex {
1985 return self.symbolic_name.firstToken();2022 return self.lbracket;
1986 }2023 }
19872024
1988 pub fn lastToken(self: &AsmOutput) TokenIndex {2025 pub fn lastToken(self: &AsmOutput) TokenIndex {
1989 return switch (self.kind) {2026 return self.rparen;
1990 Kind.Variable => |variable_name| variable_name.lastToken(),
1991 Kind.Return => |return_type| return_type.lastToken(),
1992 };
1993 }2027 }
1994 };2028 };
19952029
1996 pub const AsmInput = struct {2030 pub const AsmInput = struct {
1997 base: Node,2031 base: Node,
2032 lbracket: TokenIndex,
1998 symbolic_name: &Node,2033 symbolic_name: &Node,
1999 constraint: &Node,2034 constraint: &Node,
2000 expr: &Node,2035 expr: &Node,
2036 rparen: TokenIndex,
20012037
2002 pub fn iterate(self: &AsmInput, index: usize) ?&Node {2038 pub fn iterate(self: &AsmInput, index: usize) ?&Node {
2003 var i = index;2039 var i = index;
...@@ -2015,11 +2051,11 @@ pub const Node = struct {...@@ -2015,11 +2051,11 @@ pub const Node = struct {
2015 }2051 }
20162052
2017 pub fn firstToken(self: &AsmInput) TokenIndex {2053 pub fn firstToken(self: &AsmInput) TokenIndex {
2018 return self.symbolic_name.firstToken();2054 return self.lbracket;
2019 }2055 }
20202056
2021 pub fn lastToken(self: &AsmInput) TokenIndex {2057 pub fn lastToken(self: &AsmInput) TokenIndex {
2022 return self.expr.lastToken();2058 return self.rparen;
2023 }2059 }
2024 };2060 };
20252061
...@@ -2040,13 +2076,13 @@ pub const Node = struct {...@@ -2040,13 +2076,13 @@ pub const Node = struct {
2040 pub fn iterate(self: &Asm, index: usize) ?&Node {2076 pub fn iterate(self: &Asm, index: usize) ?&Node {
2041 var i = index;2077 var i = index;
20422078
2043 if (i < self.outputs.len) return &(*self.outputs.at(index)).base;2079 if (i < self.outputs.len) return &(self.outputs.at(index).*).base;
2044 i -= self.outputs.len;2080 i -= self.outputs.len;
20452081
2046 if (i < self.inputs.len) return &(*self.inputs.at(index)).base;2082 if (i < self.inputs.len) return &(self.inputs.at(index).*).base;
2047 i -= self.inputs.len;2083 i -= self.inputs.len;
20482084
2049 if (i < self.clobbers.len) return *self.clobbers.at(index);2085 if (i < self.clobbers.len) return self.clobbers.at(index).*;
2050 i -= self.clobbers.len;2086 i -= self.clobbers.len;
20512087
2052 return null;2088 return null;
...@@ -2112,23 +2148,6 @@ pub const Node = struct {...@@ -2112,23 +2148,6 @@ pub const Node = struct {
2112 }2148 }
2113 };2149 };
21142150
2115 pub const LineComment = struct {
2116 base: Node,
2117 token: TokenIndex,
2118
2119 pub fn iterate(self: &LineComment, index: usize) ?&Node {
2120 return null;
2121 }
2122
2123 pub fn firstToken(self: &LineComment) TokenIndex {
2124 return self.token;
2125 }
2126
2127 pub fn lastToken(self: &LineComment) TokenIndex {
2128 return self.token;
2129 }
2130 };
2131
2132 pub const DocComment = struct {2151 pub const DocComment = struct {
2133 base: Node,2152 base: Node,
2134 lines: LineList,2153 lines: LineList,
...@@ -2140,11 +2159,11 @@ pub const Node = struct {...@@ -2140,11 +2159,11 @@ pub const Node = struct {
2140 }2159 }
21412160
2142 pub fn firstToken(self: &DocComment) TokenIndex {2161 pub fn firstToken(self: &DocComment) TokenIndex {
2143 return *self.lines.at(0);2162 return self.lines.at(0).*;
2144 }2163 }
21452164
2146 pub fn lastToken(self: &DocComment) TokenIndex {2165 pub fn lastToken(self: &DocComment) TokenIndex {
2147 return *self.lines.at(self.lines.len - 1);2166 return self.lines.at(self.lines.len - 1).*;
2148 }2167 }
2149 };2168 };
21502169
...@@ -2173,4 +2192,3 @@ pub const Node = struct {...@@ -2173,4 +2192,3 @@ pub const Node = struct {
2173 }2192 }
2174 };2193 };
2175};2194};
2176
std/zig/parse.zig+1350-1622
...@@ -7,9 +7,8 @@ const Token = std.zig.Token;...@@ -7,9 +7,8 @@ const Token = std.zig.Token;
7const TokenIndex = ast.TokenIndex;7const TokenIndex = ast.TokenIndex;
8const Error = ast.Error;8const Error = ast.Error;
99
10/// Returns an AST tree, allocated with the parser's allocator.
11/// Result should be freed with tree.deinit() when there are10/// Result should be freed with tree.deinit() when there are
12/// no more references to any AST nodes of the tree.11/// no more references to any of the tokens or nodes.
13pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {12pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
14 var tree_arena = std.heap.ArenaAllocator.init(allocator);13 var tree_arena = std.heap.ArenaAllocator.init(allocator);
15 errdefer tree_arena.deinit();14 errdefer tree_arena.deinit();
...@@ -18,17 +17,15 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -18,17 +17,15 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
18 defer stack.deinit();17 defer stack.deinit();
1918
20 const arena = &tree_arena.allocator;19 const arena = &tree_arena.allocator;
21 const root_node = try createNode(arena, ast.Node.Root,20 const root_node = try arena.construct(ast.Node.Root{
22 ast.Node.Root {21 .base = ast.Node{ .id = ast.Node.Id.Root },
23 .base = undefined,22 .decls = ast.Node.Root.DeclList.init(arena),
24 .decls = ast.Node.Root.DeclList.init(arena),23 .doc_comments = null,
25 .doc_comments = null,24 // initialized when we get the eof token
26 // initialized when we get the eof token25 .eof_token = undefined,
27 .eof_token = undefined,26 });
28 }
29 );
3027
31 var tree = ast.Tree {28 var tree = ast.Tree{
32 .source = source,29 .source = source,
33 .root_node = root_node,30 .root_node = root_node,
34 .arena_allocator = tree_arena,31 .arena_allocator = tree_arena,
...@@ -39,12 +36,18 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -39,12 +36,18 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
39 var tokenizer = Tokenizer.init(tree.source);36 var tokenizer = Tokenizer.init(tree.source);
40 while (true) {37 while (true) {
41 const token_ptr = try tree.tokens.addOne();38 const token_ptr = try tree.tokens.addOne();
42 *token_ptr = tokenizer.next();39 token_ptr.* = tokenizer.next();
43 if (token_ptr.id == Token.Id.Eof)40 if (token_ptr.id == Token.Id.Eof) break;
44 break;
45 }41 }
46 var tok_it = tree.tokens.iterator(0);42 var tok_it = tree.tokens.iterator(0);
4743
44 // skip over line comments at the top of the file
45 while (true) {
46 const next_tok = tok_it.peek() ?? break;
47 if (next_tok.id != Token.Id.LineComment) break;
48 _ = tok_it.next();
49 }
50
48 try stack.append(State.TopLevel);51 try stack.append(State.TopLevel);
4952
50 while (true) {53 while (true) {
...@@ -53,10 +56,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -53,10 +56,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
5356
54 switch (state) {57 switch (state) {
55 State.TopLevel => {58 State.TopLevel => {
56 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
57 try root_node.decls.push(&line_comment.base);
58 }
59
60 const comments = try eatDocComments(arena, &tok_it, &tree);59 const comments = try eatDocComments(arena, &tok_it, &tree);
6160
62 const token = nextToken(&tok_it, &tree);61 const token = nextToken(&tok_it, &tree);
...@@ -66,33 +65,27 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -66,33 +65,27 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
66 Token.Id.Keyword_test => {65 Token.Id.Keyword_test => {
67 stack.append(State.TopLevel) catch unreachable;66 stack.append(State.TopLevel) catch unreachable;
6867
69 const block = try arena.construct(ast.Node.Block {68 const block = try arena.construct(ast.Node.Block{
70 .base = ast.Node {69 .base = ast.Node{ .id = ast.Node.Id.Block },
71 .id = ast.Node.Id.Block,
72 },
73 .label = null,70 .label = null,
74 .lbrace = undefined,71 .lbrace = undefined,
75 .statements = ast.Node.Block.StatementList.init(arena),72 .statements = ast.Node.Block.StatementList.init(arena),
76 .rbrace = undefined,73 .rbrace = undefined,
77 });74 });
78 const test_node = try arena.construct(ast.Node.TestDecl {75 const test_node = try arena.construct(ast.Node.TestDecl{
79 .base = ast.Node {76 .base = ast.Node{ .id = ast.Node.Id.TestDecl },
80 .id = ast.Node.Id.TestDecl,
81 },
82 .doc_comments = comments,77 .doc_comments = comments,
83 .test_token = token_index,78 .test_token = token_index,
84 .name = undefined,79 .name = undefined,
85 .body_node = &block.base,80 .body_node = &block.base,
86 });81 });
87 try root_node.decls.push(&test_node.base);82 try root_node.decls.push(&test_node.base);
88 try stack.append(State { .Block = block });83 try stack.append(State{ .Block = block });
89 try stack.append(State {84 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
90 .ExpectTokenSave = ExpectTokenSave {85 .id = Token.Id.LBrace,
91 .id = Token.Id.LBrace,86 .ptr = &block.lbrace,
92 .ptr = &block.rbrace,87 } });
93 }88 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &test_node.name } });
94 });
95 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
96 continue;89 continue;
97 },90 },
98 Token.Id.Eof => {91 Token.Id.Eof => {
...@@ -102,31 +95,25 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -102,31 +95,25 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
102 },95 },
103 Token.Id.Keyword_pub => {96 Token.Id.Keyword_pub => {
104 stack.append(State.TopLevel) catch unreachable;97 stack.append(State.TopLevel) catch unreachable;
105 try stack.append(State {98 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{
106 .TopLevelExtern = TopLevelDeclCtx {99 .decls = &root_node.decls,
107 .decls = &root_node.decls,100 .visib_token = token_index,
108 .visib_token = token_index,101 .extern_export_inline_token = null,
109 .extern_export_inline_token = null,102 .lib_name = null,
110 .lib_name = null,103 .comments = comments,
111 .comments = comments,104 } });
112 }
113 });
114 continue;105 continue;
115 },106 },
116 Token.Id.Keyword_comptime => {107 Token.Id.Keyword_comptime => {
117 const block = try createNode(arena, ast.Node.Block,108 const block = try arena.construct(ast.Node.Block{
118 ast.Node.Block {109 .base = ast.Node{ .id = ast.Node.Id.Block },
119 .base = undefined,110 .label = null,
120 .label = null,111 .lbrace = undefined,
121 .lbrace = undefined,112 .statements = ast.Node.Block.StatementList.init(arena),
122 .statements = ast.Node.Block.StatementList.init(arena),113 .rbrace = undefined,
123 .rbrace = undefined,114 });
124 }115 const node = try arena.construct(ast.Node.Comptime{
125 );116 .base = ast.Node{ .id = ast.Node.Id.Comptime },
126 const node = try arena.construct(ast.Node.Comptime {
127 .base = ast.Node {
128 .id = ast.Node.Id.Comptime,
129 },
130 .comptime_token = token_index,117 .comptime_token = token_index,
131 .expr = &block.base,118 .expr = &block.base,
132 .doc_comments = comments,119 .doc_comments = comments,
...@@ -134,27 +121,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -134,27 +121,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
134 try root_node.decls.push(&node.base);121 try root_node.decls.push(&node.base);
135122
136 stack.append(State.TopLevel) catch unreachable;123 stack.append(State.TopLevel) catch unreachable;
137 try stack.append(State { .Block = block });124 try stack.append(State{ .Block = block });
138 try stack.append(State {125 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
139 .ExpectTokenSave = ExpectTokenSave {126 .id = Token.Id.LBrace,
140 .id = Token.Id.LBrace,127 .ptr = &block.lbrace,
141 .ptr = &block.rbrace,128 } });
142 }
143 });
144 continue;129 continue;
145 },130 },
146 else => {131 else => {
147 putBackToken(&tok_it, &tree);132 prevToken(&tok_it, &tree);
148 stack.append(State.TopLevel) catch unreachable;133 stack.append(State.TopLevel) catch unreachable;
149 try stack.append(State {134 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{
150 .TopLevelExtern = TopLevelDeclCtx {135 .decls = &root_node.decls,
151 .decls = &root_node.decls,136 .visib_token = null,
152 .visib_token = null,137 .extern_export_inline_token = null,
153 .extern_export_inline_token = null,138 .lib_name = null,
154 .lib_name = null,139 .comments = comments,
155 .comments = comments,140 } });
156 }
157 });
158 continue;141 continue;
159 },142 },
160 }143 }
...@@ -164,41 +147,38 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -164,41 +147,38 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
164 const token_index = token.index;147 const token_index = token.index;
165 const token_ptr = token.ptr;148 const token_ptr = token.ptr;
166 switch (token_ptr.id) {149 switch (token_ptr.id) {
167 Token.Id.Keyword_export, Token.Id.Keyword_inline => {150 Token.Id.Keyword_export,
168 stack.append(State {151 Token.Id.Keyword_inline => {
169 .TopLevelDecl = TopLevelDeclCtx {152 stack.append(State{ .TopLevelDecl = TopLevelDeclCtx{
170 .decls = ctx.decls,153 .decls = ctx.decls,
171 .visib_token = ctx.visib_token,154 .visib_token = ctx.visib_token,
172 .extern_export_inline_token = AnnotatedToken {155 .extern_export_inline_token = AnnotatedToken{
173 .index = token_index,156 .index = token_index,
174 .ptr = token_ptr,157 .ptr = token_ptr,
175 },
176 .lib_name = null,
177 .comments = ctx.comments,
178 },158 },
179 }) catch unreachable;159 .lib_name = null,
160 .comments = ctx.comments,
161 } }) catch unreachable;
180 continue;162 continue;
181 },163 },
182 Token.Id.Keyword_extern => {164 Token.Id.Keyword_extern => {
183 stack.append(State {165 stack.append(State{ .TopLevelLibname = TopLevelDeclCtx{
184 .TopLevelLibname = TopLevelDeclCtx {166 .decls = ctx.decls,
185 .decls = ctx.decls,167 .visib_token = ctx.visib_token,
186 .visib_token = ctx.visib_token,168 .extern_export_inline_token = AnnotatedToken{
187 .extern_export_inline_token = AnnotatedToken {169 .index = token_index,
188 .index = token_index,170 .ptr = token_ptr,
189 .ptr = token_ptr,
190 },
191 .lib_name = null,
192 .comments = ctx.comments,
193 },171 },
194 }) catch unreachable;172 .lib_name = null,
173 .comments = ctx.comments,
174 } }) catch unreachable;
195 continue;175 continue;
196 },176 },
197 else => {177 else => {
198 putBackToken(&tok_it, &tree);178 prevToken(&tok_it, &tree);
199 stack.append(State { .TopLevelDecl = ctx }) catch unreachable;179 stack.append(State{ .TopLevelDecl = ctx }) catch unreachable;
200 continue;180 continue;
201 }181 },
202 }182 }
203 },183 },
204 State.TopLevelLibname => |ctx| {184 State.TopLevelLibname => |ctx| {
...@@ -207,20 +187,18 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -207,20 +187,18 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
207 const lib_name_token_index = lib_name_token.index;187 const lib_name_token_index = lib_name_token.index;
208 const lib_name_token_ptr = lib_name_token.ptr;188 const lib_name_token_ptr = lib_name_token.ptr;
209 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) ?? {189 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) ?? {
210 putBackToken(&tok_it, &tree);190 prevToken(&tok_it, &tree);
211 break :blk null;191 break :blk null;
212 };192 };
213 };193 };
214194
215 stack.append(State {195 stack.append(State{ .TopLevelDecl = TopLevelDeclCtx{
216 .TopLevelDecl = TopLevelDeclCtx {196 .decls = ctx.decls,
217 .decls = ctx.decls,197 .visib_token = ctx.visib_token,
218 .visib_token = ctx.visib_token,198 .extern_export_inline_token = ctx.extern_export_inline_token,
219 .extern_export_inline_token = ctx.extern_export_inline_token,199 .lib_name = lib_name,
220 .lib_name = lib_name,200 .comments = ctx.comments,
221 .comments = ctx.comments,201 } }) catch unreachable;
222 },
223 }) catch unreachable;
224 continue;202 continue;
225 },203 },
226 State.TopLevelDecl => |ctx| {204 State.TopLevelDecl => |ctx| {
...@@ -230,14 +208,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -230,14 +208,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
230 switch (token_ptr.id) {208 switch (token_ptr.id) {
231 Token.Id.Keyword_use => {209 Token.Id.Keyword_use => {
232 if (ctx.extern_export_inline_token) |annotated_token| {210 if (ctx.extern_export_inline_token) |annotated_token| {
233 *(try tree.errors.addOne()) = Error {211 ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = annotated_token.index } };
234 .InvalidToken = Error.InvalidToken { .token = annotated_token.index },
235 };
236 return tree;212 return tree;
237 }213 }
238214
239 const node = try arena.construct(ast.Node.Use {215 const node = try arena.construct(ast.Node.Use{
240 .base = ast.Node {.id = ast.Node.Id.Use },216 .base = ast.Node{ .id = ast.Node.Id.Use },
217 .use_token = token_index,
241 .visib_token = ctx.visib_token,218 .visib_token = ctx.visib_token,
242 .expr = undefined,219 .expr = undefined,
243 .semicolon_token = undefined,220 .semicolon_token = undefined,
...@@ -245,44 +222,39 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -245,44 +222,39 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
245 });222 });
246 try ctx.decls.push(&node.base);223 try ctx.decls.push(&node.base);
247224
248 stack.append(State {225 stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
249 .ExpectTokenSave = ExpectTokenSave {226 .id = Token.Id.Semicolon,
250 .id = Token.Id.Semicolon,227 .ptr = &node.semicolon_token,
251 .ptr = &node.semicolon_token,228 } }) catch unreachable;
252 }229 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
253 }) catch unreachable;
254 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
255 continue;230 continue;
256 },231 },
257 Token.Id.Keyword_var, Token.Id.Keyword_const => {232 Token.Id.Keyword_var,
233 Token.Id.Keyword_const => {
258 if (ctx.extern_export_inline_token) |annotated_token| {234 if (ctx.extern_export_inline_token) |annotated_token| {
259 if (annotated_token.ptr.id == Token.Id.Keyword_inline) {235 if (annotated_token.ptr.id == Token.Id.Keyword_inline) {
260 *(try tree.errors.addOne()) = Error {236 ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = annotated_token.index } };
261 .InvalidToken = Error.InvalidToken { .token = annotated_token.index },
262 };
263 return tree;237 return tree;
264 }238 }
265 }239 }
266240
267 try stack.append(State {241 try stack.append(State{ .VarDecl = VarDeclCtx{
268 .VarDecl = VarDeclCtx {242 .comments = ctx.comments,
269 .comments = ctx.comments,243 .visib_token = ctx.visib_token,
270 .visib_token = ctx.visib_token,244 .lib_name = ctx.lib_name,
271 .lib_name = ctx.lib_name,245 .comptime_token = null,
272 .comptime_token = null,246 .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null,
273 .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null,247 .mut_token = token_index,
274 .mut_token = token_index,248 .list = ctx.decls,
275 .list = ctx.decls249 } });
276 }250 continue;
277 });251 },
278 continue;252 Token.Id.Keyword_fn,
279 },253 Token.Id.Keyword_nakedcc,
280 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,254 Token.Id.Keyword_stdcallcc,
281 Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {255 Token.Id.Keyword_async => {
282 const fn_proto = try arena.construct(ast.Node.FnProto {256 const fn_proto = try arena.construct(ast.Node.FnProto{
283 .base = ast.Node {257 .base = ast.Node{ .id = ast.Node.Id.FnProto },
284 .id = ast.Node.Id.FnProto,
285 },
286 .doc_comments = ctx.comments,258 .doc_comments = ctx.comments,
287 .visib_token = ctx.visib_token,259 .visib_token = ctx.visib_token,
288 .name_token = null,260 .name_token = null,
...@@ -298,38 +270,33 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -298,38 +270,33 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
298 .align_expr = null,270 .align_expr = null,
299 });271 });
300 try ctx.decls.push(&fn_proto.base);272 try ctx.decls.push(&fn_proto.base);
301 stack.append(State { .FnDef = fn_proto }) catch unreachable;273 stack.append(State{ .FnDef = fn_proto }) catch unreachable;
302 try stack.append(State { .FnProto = fn_proto });274 try stack.append(State{ .FnProto = fn_proto });
303275
304 switch (token_ptr.id) {276 switch (token_ptr.id) {
305 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {277 Token.Id.Keyword_nakedcc,
278 Token.Id.Keyword_stdcallcc => {
306 fn_proto.cc_token = token_index;279 fn_proto.cc_token = token_index;
307 try stack.append(State {280 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
308 .ExpectTokenSave = ExpectTokenSave {281 .id = Token.Id.Keyword_fn,
309 .id = Token.Id.Keyword_fn,282 .ptr = &fn_proto.fn_token,
310 .ptr = &fn_proto.fn_token,283 } });
311 }
312 });
313 continue;284 continue;
314 },285 },
315 Token.Id.Keyword_async => {286 Token.Id.Keyword_async => {
316 const async_node = try createNode(arena, ast.Node.AsyncAttribute,287 const async_node = try arena.construct(ast.Node.AsyncAttribute{
317 ast.Node.AsyncAttribute {288 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
318 .base = undefined,289 .async_token = token_index,
319 .async_token = token_index,290 .allocator_type = null,
320 .allocator_type = null,291 .rangle_bracket = null,
321 .rangle_bracket = null,292 });
322 }
323 );
324 fn_proto.async_attr = async_node;293 fn_proto.async_attr = async_node;
325294
326 try stack.append(State {295 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
327 .ExpectTokenSave = ExpectTokenSave {296 .id = Token.Id.Keyword_fn,
328 .id = Token.Id.Keyword_fn,297 .ptr = &fn_proto.fn_token,
329 .ptr = &fn_proto.fn_token,298 } });
330 }299 try stack.append(State{ .AsyncAllocator = async_node });
331 });
332 try stack.append(State { .AsyncAllocator = async_node });
333 continue;300 continue;
334 },301 },
335 Token.Id.Keyword_fn => {302 Token.Id.Keyword_fn => {
...@@ -340,44 +307,37 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -340,44 +307,37 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
340 }307 }
341 },308 },
342 else => {309 else => {
343 *(try tree.errors.addOne()) = Error {310 ((try tree.errors.addOne())).* = Error{ .ExpectedVarDeclOrFn = Error.ExpectedVarDeclOrFn{ .token = token_index } };
344 .ExpectedVarDeclOrFn = Error.ExpectedVarDeclOrFn { .token = token_index },
345 };
346 return tree;311 return tree;
347 },312 },
348 }313 }
349 },314 },
350 State.TopLevelExternOrField => |ctx| {315 State.TopLevelExternOrField => |ctx| {
351 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {316 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {
352 std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);317 const node = try arena.construct(ast.Node.StructField{
353 const node = try arena.construct(ast.Node.StructField {318 .base = ast.Node{ .id = ast.Node.Id.StructField },
354 .base = ast.Node {
355 .id = ast.Node.Id.StructField,
356 },
357 .doc_comments = ctx.comments,319 .doc_comments = ctx.comments,
358 .visib_token = ctx.visib_token,320 .visib_token = ctx.visib_token,
359 .name_token = identifier,321 .name_token = identifier,
360 .type_expr = undefined,322 .type_expr = undefined,
361 });323 });
362 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();324 const node_ptr = try ctx.container_decl.fields_and_decls.addOne();
363 *node_ptr = &node.base;325 node_ptr.* = &node.base;
364326
365 stack.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;327 stack.append(State{ .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
366 try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });328 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.type_expr } });
367 try stack.append(State { .ExpectToken = Token.Id.Colon });329 try stack.append(State{ .ExpectToken = Token.Id.Colon });
368 continue;330 continue;
369 }331 }
370332
371 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;333 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
372 try stack.append(State {334 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{
373 .TopLevelExtern = TopLevelDeclCtx {335 .decls = &ctx.container_decl.fields_and_decls,
374 .decls = &ctx.container_decl.fields_and_decls,336 .visib_token = ctx.visib_token,
375 .visib_token = ctx.visib_token,337 .extern_export_inline_token = null,
376 .extern_export_inline_token = null,338 .lib_name = null,
377 .lib_name = null,339 .comments = ctx.comments,
378 .comments = ctx.comments,340 } });
379 }
380 });
381 continue;341 continue;
382 },342 },
383343
...@@ -386,10 +346,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -386,10 +346,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
386 const eq_tok_index = eq_tok.index;346 const eq_tok_index = eq_tok.index;
387 const eq_tok_ptr = eq_tok.ptr;347 const eq_tok_ptr = eq_tok.ptr;
388 if (eq_tok_ptr.id != Token.Id.Equal) {348 if (eq_tok_ptr.id != Token.Id.Equal) {
389 putBackToken(&tok_it, &tree);349 prevToken(&tok_it, &tree);
390 continue;350 continue;
391 }351 }
392 stack.append(State { .Expression = ctx }) catch unreachable;352 stack.append(State{ .Expression = ctx }) catch unreachable;
393 continue;353 continue;
394 },354 },
395355
...@@ -397,31 +357,31 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -397,31 +357,31 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
397 const token = nextToken(&tok_it, &tree);357 const token = nextToken(&tok_it, &tree);
398 const token_index = token.index;358 const token_index = token.index;
399 const token_ptr = token.ptr;359 const token_ptr = token.ptr;
400 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl,360 const node = try arena.construct(ast.Node.ContainerDecl{
401 ast.Node.ContainerDecl {361 .base = ast.Node{ .id = ast.Node.Id.ContainerDecl },
402 .base = undefined,362 .layout_token = ctx.layout_token,
403 .ltoken = ctx.ltoken,363 .kind_token = switch (token_ptr.id) {
404 .layout = ctx.layout,364 Token.Id.Keyword_struct,
405 .kind = switch (token_ptr.id) {365 Token.Id.Keyword_union,
406 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,366 Token.Id.Keyword_enum => token_index,
407 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,367 else => {
408 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,368 ((try tree.errors.addOne())).* = Error{ .ExpectedAggregateKw = Error.ExpectedAggregateKw{ .token = token_index } };
409 else => {369 return tree;
410 *(try tree.errors.addOne()) = Error {
411 .ExpectedAggregateKw = Error.ExpectedAggregateKw { .token = token_index },
412 };
413 return tree;
414 },
415 },370 },
416 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,371 },
417 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),372 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
418 .rbrace_token = undefined,373 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
419 }374 .lbrace_token = undefined,
420 );375 .rbrace_token = undefined,
376 });
377 ctx.opt_ctx.store(&node.base);
421378
422 stack.append(State { .ContainerDecl = node }) catch unreachable;379 stack.append(State{ .ContainerDecl = node }) catch unreachable;
423 try stack.append(State { .ExpectToken = Token.Id.LBrace });380 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
424 try stack.append(State { .ContainerInitArgStart = node });381 .id = Token.Id.LBrace,
382 .ptr = &node.lbrace_token,
383 } });
384 try stack.append(State{ .ContainerInitArgStart = node });
425 continue;385 continue;
426 },386 },
427387
...@@ -430,8 +390,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -430,8 +390,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
430 continue;390 continue;
431 }391 }
432392
433 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;393 stack.append(State{ .ExpectToken = Token.Id.RParen }) catch unreachable;
434 try stack.append(State { .ContainerInitArg = container_decl });394 try stack.append(State{ .ContainerInitArg = container_decl });
435 continue;395 continue;
436 },396 },
437397
...@@ -441,61 +401,53 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -441,61 +401,53 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
441 const init_arg_token_ptr = init_arg_token.ptr;401 const init_arg_token_ptr = init_arg_token.ptr;
442 switch (init_arg_token_ptr.id) {402 switch (init_arg_token_ptr.id) {
443 Token.Id.Keyword_enum => {403 Token.Id.Keyword_enum => {
444 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg {.Enum = null};404 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Enum = null };
445 const lparen_tok = nextToken(&tok_it, &tree);405 const lparen_tok = nextToken(&tok_it, &tree);
446 const lparen_tok_index = lparen_tok.index;406 const lparen_tok_index = lparen_tok.index;
447 const lparen_tok_ptr = lparen_tok.ptr;407 const lparen_tok_ptr = lparen_tok.ptr;
448 if (lparen_tok_ptr.id == Token.Id.LParen) {408 if (lparen_tok_ptr.id == Token.Id.LParen) {
449 try stack.append(State { .ExpectToken = Token.Id.RParen } );409 try stack.append(State{ .ExpectToken = Token.Id.RParen });
450 try stack.append(State { .Expression = OptionalCtx {410 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &container_decl.init_arg_expr.Enum } });
451 .RequiredNull = &container_decl.init_arg_expr.Enum,
452 } });
453 } else {411 } else {
454 putBackToken(&tok_it, &tree);412 prevToken(&tok_it, &tree);
455 }413 }
456 },414 },
457 else => {415 else => {
458 putBackToken(&tok_it, &tree);416 prevToken(&tok_it, &tree);
459 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg { .Type = undefined };417 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Type = undefined };
460 stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;418 stack.append(State{ .Expression = OptionalCtx{ .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
461 },419 },
462 }420 }
463 continue;421 continue;
464 },422 },
465423
466 State.ContainerDecl => |container_decl| {424 State.ContainerDecl => |container_decl| {
467 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
468 try container_decl.fields_and_decls.push(&line_comment.base);
469 }
470
471 const comments = try eatDocComments(arena, &tok_it, &tree);425 const comments = try eatDocComments(arena, &tok_it, &tree);
472 const token = nextToken(&tok_it, &tree);426 const token = nextToken(&tok_it, &tree);
473 const token_index = token.index;427 const token_index = token.index;
474 const token_ptr = token.ptr;428 const token_ptr = token.ptr;
475 switch (token_ptr.id) {429 switch (token_ptr.id) {
476 Token.Id.Identifier => {430 Token.Id.Identifier => {
477 switch (container_decl.kind) {431 switch (tree.tokens.at(container_decl.kind_token).id) {
478 ast.Node.ContainerDecl.Kind.Struct => {432 Token.Id.Keyword_struct => {
479 const node = try arena.construct(ast.Node.StructField {433 const node = try arena.construct(ast.Node.StructField{
480 .base = ast.Node {434 .base = ast.Node{ .id = ast.Node.Id.StructField },
481 .id = ast.Node.Id.StructField,
482 },
483 .doc_comments = comments,435 .doc_comments = comments,
484 .visib_token = null,436 .visib_token = null,
485 .name_token = token_index,437 .name_token = token_index,
486 .type_expr = undefined,438 .type_expr = undefined,
487 });439 });
488 const node_ptr = try container_decl.fields_and_decls.addOne();440 const node_ptr = try container_decl.fields_and_decls.addOne();
489 *node_ptr = &node.base;441 node_ptr.* = &node.base;
490442
491 try stack.append(State { .FieldListCommaOrEnd = container_decl });443 try stack.append(State{ .FieldListCommaOrEnd = container_decl });
492 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });444 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.type_expr } });
493 try stack.append(State { .ExpectToken = Token.Id.Colon });445 try stack.append(State{ .ExpectToken = Token.Id.Colon });
494 continue;446 continue;
495 },447 },
496 ast.Node.ContainerDecl.Kind.Union => {448 Token.Id.Keyword_union => {
497 const node = try arena.construct(ast.Node.UnionTag {449 const node = try arena.construct(ast.Node.UnionTag{
498 .base = ast.Node {.id = ast.Node.Id.UnionTag },450 .base = ast.Node{ .id = ast.Node.Id.UnionTag },
499 .name_token = token_index,451 .name_token = token_index,
500 .type_expr = null,452 .type_expr = null,
501 .value_expr = null,453 .value_expr = null,
...@@ -503,101 +455,89 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -503,101 +455,89 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
503 });455 });
504 try container_decl.fields_and_decls.push(&node.base);456 try container_decl.fields_and_decls.push(&node.base);
505457
506 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;458 stack.append(State{ .FieldListCommaOrEnd = container_decl }) catch unreachable;
507 try stack.append(State { .FieldInitValue = OptionalCtx { .RequiredNull = &node.value_expr } });459 try stack.append(State{ .FieldInitValue = OptionalCtx{ .RequiredNull = &node.value_expr } });
508 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });460 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &node.type_expr } });
509 try stack.append(State { .IfToken = Token.Id.Colon });461 try stack.append(State{ .IfToken = Token.Id.Colon });
510 continue;462 continue;
511 },463 },
512 ast.Node.ContainerDecl.Kind.Enum => {464 Token.Id.Keyword_enum => {
513 const node = try arena.construct(ast.Node.EnumTag {465 const node = try arena.construct(ast.Node.EnumTag{
514 .base = ast.Node { .id = ast.Node.Id.EnumTag },466 .base = ast.Node{ .id = ast.Node.Id.EnumTag },
515 .name_token = token_index,467 .name_token = token_index,
516 .value = null,468 .value = null,
517 .doc_comments = comments,469 .doc_comments = comments,
518 });470 });
519 try container_decl.fields_and_decls.push(&node.base);471 try container_decl.fields_and_decls.push(&node.base);
520472
521 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;473 stack.append(State{ .FieldListCommaOrEnd = container_decl }) catch unreachable;
522 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });474 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &node.value } });
523 try stack.append(State { .IfToken = Token.Id.Equal });475 try stack.append(State{ .IfToken = Token.Id.Equal });
524 continue;476 continue;
525 },477 },
478 else => unreachable,
526 }479 }
527 },480 },
528 Token.Id.Keyword_pub => {481 Token.Id.Keyword_pub => {
529 switch (container_decl.kind) {482 switch (tree.tokens.at(container_decl.kind_token).id) {
530 ast.Node.ContainerDecl.Kind.Struct => {483 Token.Id.Keyword_struct => {
531 try stack.append(State {484 try stack.append(State{ .TopLevelExternOrField = TopLevelExternOrFieldCtx{
532 .TopLevelExternOrField = TopLevelExternOrFieldCtx {485 .visib_token = token_index,
533 .visib_token = token_index,486 .container_decl = container_decl,
534 .container_decl = container_decl,487 .comments = comments,
535 .comments = comments,488 } });
536 }
537 });
538 continue;489 continue;
539 },490 },
540 else => {491 else => {
541 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;492 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
542 try stack.append(State {493 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{
543 .TopLevelExtern = TopLevelDeclCtx {494 .decls = &container_decl.fields_and_decls,
544 .decls = &container_decl.fields_and_decls,495 .visib_token = token_index,
545 .visib_token = token_index,496 .extern_export_inline_token = null,
546 .extern_export_inline_token = null,497 .lib_name = null,
547 .lib_name = null,498 .comments = comments,
548 .comments = comments,499 } });
549 }
550 });
551 continue;500 continue;
552 }501 },
553 }502 }
554 },503 },
555 Token.Id.Keyword_export => {504 Token.Id.Keyword_export => {
556 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;505 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
557 try stack.append(State {506 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{
558 .TopLevelExtern = TopLevelDeclCtx {507 .decls = &container_decl.fields_and_decls,
559 .decls = &container_decl.fields_and_decls,508 .visib_token = token_index,
560 .visib_token = token_index,509 .extern_export_inline_token = null,
561 .extern_export_inline_token = null,510 .lib_name = null,
562 .lib_name = null,511 .comments = comments,
563 .comments = comments,512 } });
564 }
565 });
566 continue;513 continue;
567 },514 },
568 Token.Id.RBrace => {515 Token.Id.RBrace => {
569 if (comments != null) {516 if (comments != null) {
570 *(try tree.errors.addOne()) = Error {517 ((try tree.errors.addOne())).* = Error{ .UnattachedDocComment = Error.UnattachedDocComment{ .token = token_index } };
571 .UnattachedDocComment = Error.UnattachedDocComment { .token = token_index },
572 };
573 return tree;518 return tree;
574 }519 }
575 container_decl.rbrace_token = token_index;520 container_decl.rbrace_token = token_index;
576 continue;521 continue;
577 },522 },
578 else => {523 else => {
579 putBackToken(&tok_it, &tree);524 prevToken(&tok_it, &tree);
580 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;525 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
581 try stack.append(State {526 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{
582 .TopLevelExtern = TopLevelDeclCtx {527 .decls = &container_decl.fields_and_decls,
583 .decls = &container_decl.fields_and_decls,528 .visib_token = null,
584 .visib_token = null,529 .extern_export_inline_token = null,
585 .extern_export_inline_token = null,530 .lib_name = null,
586 .lib_name = null,531 .comments = comments,
587 .comments = comments,532 } });
588 }
589 });
590 continue;533 continue;
591 }534 },
592 }535 }
593 },536 },
594537
595
596 State.VarDecl => |ctx| {538 State.VarDecl => |ctx| {
597 const var_decl = try arena.construct(ast.Node.VarDecl {539 const var_decl = try arena.construct(ast.Node.VarDecl{
598 .base = ast.Node {540 .base = ast.Node{ .id = ast.Node.Id.VarDecl },
599 .id = ast.Node.Id.VarDecl,
600 },
601 .doc_comments = ctx.comments,541 .doc_comments = ctx.comments,
602 .visib_token = ctx.visib_token,542 .visib_token = ctx.visib_token,
603 .mut_token = ctx.mut_token,543 .mut_token = ctx.mut_token,
...@@ -614,31 +554,29 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -614,31 +554,29 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
614 });554 });
615 try ctx.list.push(&var_decl.base);555 try ctx.list.push(&var_decl.base);
616556
617 try stack.append(State { .VarDeclAlign = var_decl });557 try stack.append(State{ .VarDeclAlign = var_decl });
618 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });558 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &var_decl.type_node } });
619 try stack.append(State { .IfToken = Token.Id.Colon });559 try stack.append(State{ .IfToken = Token.Id.Colon });
620 try stack.append(State {560 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
621 .ExpectTokenSave = ExpectTokenSave {561 .id = Token.Id.Identifier,
622 .id = Token.Id.Identifier,562 .ptr = &var_decl.name_token,
623 .ptr = &var_decl.name_token,563 } });
624 }
625 });
626 continue;564 continue;
627 },565 },
628 State.VarDeclAlign => |var_decl| {566 State.VarDeclAlign => |var_decl| {
629 try stack.append(State { .VarDeclEq = var_decl });567 try stack.append(State{ .VarDeclEq = var_decl });
630568
631 const next_token = nextToken(&tok_it, &tree);569 const next_token = nextToken(&tok_it, &tree);
632 const next_token_index = next_token.index;570 const next_token_index = next_token.index;
633 const next_token_ptr = next_token.ptr;571 const next_token_ptr = next_token.ptr;
634 if (next_token_ptr.id == Token.Id.Keyword_align) {572 if (next_token_ptr.id == Token.Id.Keyword_align) {
635 try stack.append(State { .ExpectToken = Token.Id.RParen });573 try stack.append(State{ .ExpectToken = Token.Id.RParen });
636 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });574 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &var_decl.align_node } });
637 try stack.append(State { .ExpectToken = Token.Id.LParen });575 try stack.append(State{ .ExpectToken = Token.Id.LParen });
638 continue;576 continue;
639 }577 }
640578
641 putBackToken(&tok_it, &tree);579 prevToken(&tok_it, &tree);
642 continue;580 continue;
643 },581 },
644 State.VarDeclEq => |var_decl| {582 State.VarDeclEq => |var_decl| {
...@@ -648,13 +586,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -648,13 +586,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
648 switch (token_ptr.id) {586 switch (token_ptr.id) {
649 Token.Id.Equal => {587 Token.Id.Equal => {
650 var_decl.eq_token = token_index;588 var_decl.eq_token = token_index;
651 stack.append(State {589 stack.append(State{ .VarDeclSemiColon = var_decl }) catch unreachable;
652 .ExpectTokenSave = ExpectTokenSave {590 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &var_decl.init_node } });
653 .id = Token.Id.Semicolon,
654 .ptr = &var_decl.semicolon_token,
655 },
656 }) catch unreachable;
657 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
658 continue;591 continue;
659 },592 },
660 Token.Id.Semicolon => {593 Token.Id.Semicolon => {
...@@ -662,45 +595,63 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -662,45 +595,63 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
662 continue;595 continue;
663 },596 },
664 else => {597 else => {
665 *(try tree.errors.addOne()) = Error {598 ((try tree.errors.addOne())).* = Error{ .ExpectedEqOrSemi = Error.ExpectedEqOrSemi{ .token = token_index } };
666 .ExpectedEqOrSemi = Error.ExpectedEqOrSemi { .token = token_index },
667 };
668 return tree;599 return tree;
669 }600 },
670 }601 }
671 },602 },
672603
604 State.VarDeclSemiColon => |var_decl| {
605 const semicolon_token = nextToken(&tok_it, &tree);
606
607 if (semicolon_token.ptr.id != Token.Id.Semicolon) {
608 ((try tree.errors.addOne())).* = Error{ .ExpectedToken = Error.ExpectedToken{
609 .token = semicolon_token.index,
610 .expected_id = Token.Id.Semicolon,
611 } };
612 return tree;
613 }
614
615 var_decl.semicolon_token = semicolon_token.index;
616
617 if (eatToken(&tok_it, &tree, Token.Id.DocComment)) |doc_comment_token| {
618 const loc = tree.tokenLocation(semicolon_token.ptr.end, doc_comment_token);
619 if (loc.line == 0) {
620 try pushDocComment(arena, doc_comment_token, &var_decl.doc_comments);
621 } else {
622 prevToken(&tok_it, &tree);
623 }
624 }
625 },
673626
674 State.FnDef => |fn_proto| {627 State.FnDef => |fn_proto| {
675 const token = nextToken(&tok_it, &tree);628 const token = nextToken(&tok_it, &tree);
676 const token_index = token.index;629 const token_index = token.index;
677 const token_ptr = token.ptr;630 const token_ptr = token.ptr;
678 switch(token_ptr.id) {631 switch (token_ptr.id) {
679 Token.Id.LBrace => {632 Token.Id.LBrace => {
680 const block = try arena.construct(ast.Node.Block {633 const block = try arena.construct(ast.Node.Block{
681 .base = ast.Node { .id = ast.Node.Id.Block },634 .base = ast.Node{ .id = ast.Node.Id.Block },
682 .label = null,635 .label = null,
683 .lbrace = token_index,636 .lbrace = token_index,
684 .statements = ast.Node.Block.StatementList.init(arena),637 .statements = ast.Node.Block.StatementList.init(arena),
685 .rbrace = undefined,638 .rbrace = undefined,
686 });639 });
687 fn_proto.body_node = &block.base;640 fn_proto.body_node = &block.base;
688 stack.append(State { .Block = block }) catch unreachable;641 stack.append(State{ .Block = block }) catch unreachable;
689 continue;642 continue;
690 },643 },
691 Token.Id.Semicolon => continue,644 Token.Id.Semicolon => continue,
692 else => {645 else => {
693 *(try tree.errors.addOne()) = Error {646 ((try tree.errors.addOne())).* = Error{ .ExpectedSemiOrLBrace = Error.ExpectedSemiOrLBrace{ .token = token_index } };
694 .ExpectedSemiOrLBrace = Error.ExpectedSemiOrLBrace { .token = token_index },
695 };
696 return tree;647 return tree;
697 },648 },
698 }649 }
699 },650 },
700 State.FnProto => |fn_proto| {651 State.FnProto => |fn_proto| {
701 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;652 stack.append(State{ .FnProtoAlign = fn_proto }) catch unreachable;
702 try stack.append(State { .ParamDecl = fn_proto });653 try stack.append(State{ .ParamDecl = fn_proto });
703 try stack.append(State { .ExpectToken = Token.Id.LParen });654 try stack.append(State{ .ExpectToken = Token.Id.LParen });
704655
705 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |name_token| {656 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |name_token| {
706 fn_proto.name_token = name_token;657 fn_proto.name_token = name_token;
...@@ -708,12 +659,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -708,12 +659,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
708 continue;659 continue;
709 },660 },
710 State.FnProtoAlign => |fn_proto| {661 State.FnProtoAlign => |fn_proto| {
711 stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;662 stack.append(State{ .FnProtoReturnType = fn_proto }) catch unreachable;
712663
713 if (eatToken(&tok_it, &tree, Token.Id.Keyword_align)) |align_token| {664 if (eatToken(&tok_it, &tree, Token.Id.Keyword_align)) |align_token| {
714 try stack.append(State { .ExpectToken = Token.Id.RParen });665 try stack.append(State{ .ExpectToken = Token.Id.RParen });
715 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });666 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &fn_proto.align_expr } });
716 try stack.append(State { .ExpectToken = Token.Id.LParen });667 try stack.append(State{ .ExpectToken = Token.Id.LParen });
717 }668 }
718 continue;669 continue;
719 },670 },
...@@ -723,42 +674,37 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -723,42 +674,37 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
723 const token_ptr = token.ptr;674 const token_ptr = token.ptr;
724 switch (token_ptr.id) {675 switch (token_ptr.id) {
725 Token.Id.Bang => {676 Token.Id.Bang => {
726 fn_proto.return_type = ast.Node.FnProto.ReturnType { .InferErrorSet = undefined };677 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .InferErrorSet = undefined };
727 stack.append(State {678 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &fn_proto.return_type.InferErrorSet } }) catch unreachable;
728 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
729 }) catch unreachable;
730 continue;679 continue;
731 },680 },
732 else => {681 else => {
733 // TODO: this is a special case. Remove this when #760 is fixed682 // TODO: this is a special case. Remove this when #760 is fixed
734 if (token_ptr.id == Token.Id.Keyword_error) {683 if (token_ptr.id == Token.Id.Keyword_error) {
735 if ((??tok_it.peek()).id == Token.Id.LBrace) {684 if ((??tok_it.peek()).id == Token.Id.LBrace) {
736 const error_type_node = try arena.construct(ast.Node.ErrorType {685 const error_type_node = try arena.construct(ast.Node.ErrorType{
737 .base = ast.Node { .id = ast.Node.Id.ErrorType },686 .base = ast.Node{ .id = ast.Node.Id.ErrorType },
738 .token = token_index,687 .token = token_index,
739 });688 });
740 fn_proto.return_type = ast.Node.FnProto.ReturnType {689 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = &error_type_node.base };
741 .Explicit = &error_type_node.base,
742 };
743 continue;690 continue;
744 }691 }
745 }692 }
746693
747 putBackToken(&tok_it, &tree);694 prevToken(&tok_it, &tree);
748 fn_proto.return_type = ast.Node.FnProto.ReturnType { .Explicit = undefined };695 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = undefined };
749 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;696 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &fn_proto.return_type.Explicit } }) catch unreachable;
750 continue;697 continue;
751 },698 },
752 }699 }
753 },700 },
754701
755
756 State.ParamDecl => |fn_proto| {702 State.ParamDecl => |fn_proto| {
757 if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| {703 if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| {
758 continue;704 continue;
759 }705 }
760 const param_decl = try arena.construct(ast.Node.ParamDecl {706 const param_decl = try arena.construct(ast.Node.ParamDecl{
761 .base = ast.Node {.id = ast.Node.Id.ParamDecl },707 .base = ast.Node{ .id = ast.Node.Id.ParamDecl },
762 .comptime_token = null,708 .comptime_token = null,
763 .noalias_token = null,709 .noalias_token = null,
764 .name_token = null,710 .name_token = null,
...@@ -767,14 +713,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -767,14 +713,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
767 });713 });
768 try fn_proto.params.push(&param_decl.base);714 try fn_proto.params.push(&param_decl.base);
769715
770 stack.append(State {716 stack.append(State{ .ParamDeclEnd = ParamDeclEndCtx{
771 .ParamDeclEnd = ParamDeclEndCtx {717 .param_decl = param_decl,
772 .param_decl = param_decl,718 .fn_proto = fn_proto,
773 .fn_proto = fn_proto,719 } }) catch unreachable;
774 }720 try stack.append(State{ .ParamDeclName = param_decl });
775 }) catch unreachable;721 try stack.append(State{ .ParamDeclAliasOrComptime = param_decl });
776 try stack.append(State { .ParamDeclName = param_decl });
777 try stack.append(State { .ParamDeclAliasOrComptime = param_decl });
778 continue;722 continue;
779 },723 },
780 State.ParamDeclAliasOrComptime => |param_decl| {724 State.ParamDeclAliasOrComptime => |param_decl| {
...@@ -792,7 +736,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -792,7 +736,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
792 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {736 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
793 param_decl.name_token = ident_token;737 param_decl.name_token = ident_token;
794 } else {738 } else {
795 putBackToken(&tok_it, &tree);739 prevToken(&tok_it, &tree);
796 }740 }
797 }741 }
798 continue;742 continue;
...@@ -800,21 +744,19 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -800,21 +744,19 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
800 State.ParamDeclEnd => |ctx| {744 State.ParamDeclEnd => |ctx| {
801 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {745 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
802 ctx.param_decl.var_args_token = ellipsis3;746 ctx.param_decl.var_args_token = ellipsis3;
803 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;747 stack.append(State{ .ExpectToken = Token.Id.RParen }) catch unreachable;
804 continue;748 continue;
805 }749 }
806750
807 try stack.append(State { .ParamDeclComma = ctx.fn_proto });751 try stack.append(State{ .ParamDeclComma = ctx.fn_proto });
808 try stack.append(State {752 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &ctx.param_decl.type_node } });
809 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
810 });
811 continue;753 continue;
812 },754 },
813 State.ParamDeclComma => |fn_proto| {755 State.ParamDeclComma => |fn_proto| {
814 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) {756 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) {
815 ExpectCommaOrEndResult.end_token => |t| {757 ExpectCommaOrEndResult.end_token => |t| {
816 if (t == null) {758 if (t == null) {
817 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;759 stack.append(State{ .ParamDecl = fn_proto }) catch unreachable;
818 }760 }
819 continue;761 continue;
820 },762 },
...@@ -827,12 +769,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -827,12 +769,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
827769
828 State.MaybeLabeledExpression => |ctx| {770 State.MaybeLabeledExpression => |ctx| {
829 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {771 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
830 stack.append(State {772 stack.append(State{ .LabeledExpression = LabelCtx{
831 .LabeledExpression = LabelCtx {773 .label = ctx.label,
832 .label = ctx.label,774 .opt_ctx = ctx.opt_ctx,
833 .opt_ctx = ctx.opt_ctx,775 } }) catch unreachable;
834 }
835 }) catch unreachable;
836 continue;776 continue;
837 }777 }
838778
...@@ -845,74 +785,63 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -845,74 +785,63 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
845 const token_ptr = token.ptr;785 const token_ptr = token.ptr;
846 switch (token_ptr.id) {786 switch (token_ptr.id) {
847 Token.Id.LBrace => {787 Token.Id.LBrace => {
848 const block = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block,788 const block = try arena.construct(ast.Node.Block{
849 ast.Node.Block {789 .base = ast.Node{ .id = ast.Node.Id.Block },
850 .base = undefined,790 .label = ctx.label,
851 .label = ctx.label,791 .lbrace = token_index,
852 .lbrace = token_index,792 .statements = ast.Node.Block.StatementList.init(arena),
853 .statements = ast.Node.Block.StatementList.init(arena),793 .rbrace = undefined,
854 .rbrace = undefined,794 });
855 }795 ctx.opt_ctx.store(&block.base);
856 );796 stack.append(State{ .Block = block }) catch unreachable;
857 stack.append(State { .Block = block }) catch unreachable;
858 continue;797 continue;
859 },798 },
860 Token.Id.Keyword_while => {799 Token.Id.Keyword_while => {
861 stack.append(State {800 stack.append(State{ .While = LoopCtx{
862 .While = LoopCtx {801 .label = ctx.label,
863 .label = ctx.label,802 .inline_token = null,
864 .inline_token = null,803 .loop_token = token_index,
865 .loop_token = token_index,804 .opt_ctx = ctx.opt_ctx.toRequired(),
866 .opt_ctx = ctx.opt_ctx.toRequired(),805 } }) catch unreachable;
867 }
868 }) catch unreachable;
869 continue;806 continue;
870 },807 },
871 Token.Id.Keyword_for => {808 Token.Id.Keyword_for => {
872 stack.append(State {809 stack.append(State{ .For = LoopCtx{
873 .For = LoopCtx {810 .label = ctx.label,
874 .label = ctx.label,811 .inline_token = null,
875 .inline_token = null,812 .loop_token = token_index,
876 .loop_token = token_index,813 .opt_ctx = ctx.opt_ctx.toRequired(),
877 .opt_ctx = ctx.opt_ctx.toRequired(),814 } }) catch unreachable;
878 }
879 }) catch unreachable;
880 continue;815 continue;
881 },816 },
882 Token.Id.Keyword_suspend => {817 Token.Id.Keyword_suspend => {
883 const node = try arena.construct(ast.Node.Suspend {818 const node = try arena.construct(ast.Node.Suspend{
884 .base = ast.Node {819 .base = ast.Node{ .id = ast.Node.Id.Suspend },
885 .id = ast.Node.Id.Suspend,
886 },
887 .label = ctx.label,820 .label = ctx.label,
888 .suspend_token = token_index,821 .suspend_token = token_index,
889 .payload = null,822 .payload = null,
890 .body = null,823 .body = null,
891 });824 });
892 ctx.opt_ctx.store(&node.base);825 ctx.opt_ctx.store(&node.base);
893 stack.append(State { .SuspendBody = node }) catch unreachable;826 stack.append(State{ .SuspendBody = node }) catch unreachable;
894 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });827 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
895 continue;828 continue;
896 },829 },
897 Token.Id.Keyword_inline => {830 Token.Id.Keyword_inline => {
898 stack.append(State {831 stack.append(State{ .Inline = InlineCtx{
899 .Inline = InlineCtx {832 .label = ctx.label,
900 .label = ctx.label,833 .inline_token = token_index,
901 .inline_token = token_index,834 .opt_ctx = ctx.opt_ctx.toRequired(),
902 .opt_ctx = ctx.opt_ctx.toRequired(),835 } }) catch unreachable;
903 }
904 }) catch unreachable;
905 continue;836 continue;
906 },837 },
907 else => {838 else => {
908 if (ctx.opt_ctx != OptionalCtx.Optional) {839 if (ctx.opt_ctx != OptionalCtx.Optional) {
909 *(try tree.errors.addOne()) = Error {840 ((try tree.errors.addOne())).* = Error{ .ExpectedLabelable = Error.ExpectedLabelable{ .token = token_index } };
910 .ExpectedLabelable = Error.ExpectedLabelable { .token = token_index },
911 };
912 return tree;841 return tree;
913 }842 }
914843
915 putBackToken(&tok_it, &tree);844 prevToken(&tok_it, &tree);
916 continue;845 continue;
917 },846 },
918 }847 }
...@@ -923,112 +852,101 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -923,112 +852,101 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
923 const token_ptr = token.ptr;852 const token_ptr = token.ptr;
924 switch (token_ptr.id) {853 switch (token_ptr.id) {
925 Token.Id.Keyword_while => {854 Token.Id.Keyword_while => {
926 stack.append(State {855 stack.append(State{ .While = LoopCtx{
927 .While = LoopCtx {856 .inline_token = ctx.inline_token,
928 .inline_token = ctx.inline_token,857 .label = ctx.label,
929 .label = ctx.label,858 .loop_token = token_index,
930 .loop_token = token_index,859 .opt_ctx = ctx.opt_ctx.toRequired(),
931 .opt_ctx = ctx.opt_ctx.toRequired(),860 } }) catch unreachable;
932 }
933 }) catch unreachable;
934 continue;861 continue;
935 },862 },
936 Token.Id.Keyword_for => {863 Token.Id.Keyword_for => {
937 stack.append(State {864 stack.append(State{ .For = LoopCtx{
938 .For = LoopCtx {865 .inline_token = ctx.inline_token,
939 .inline_token = ctx.inline_token,866 .label = ctx.label,
940 .label = ctx.label,867 .loop_token = token_index,
941 .loop_token = token_index,868 .opt_ctx = ctx.opt_ctx.toRequired(),
942 .opt_ctx = ctx.opt_ctx.toRequired(),869 } }) catch unreachable;
943 }
944 }) catch unreachable;
945 continue;870 continue;
946 },871 },
947 else => {872 else => {
948 if (ctx.opt_ctx != OptionalCtx.Optional) {873 if (ctx.opt_ctx != OptionalCtx.Optional) {
949 *(try tree.errors.addOne()) = Error {874 ((try tree.errors.addOne())).* = Error{ .ExpectedInlinable = Error.ExpectedInlinable{ .token = token_index } };
950 .ExpectedInlinable = Error.ExpectedInlinable { .token = token_index },
951 };
952 return tree;875 return tree;
953 }876 }
954877
955 putBackToken(&tok_it, &tree);878 prevToken(&tok_it, &tree);
956 continue;879 continue;
957 },880 },
958 }881 }
959 },882 },
960 State.While => |ctx| {883 State.While => |ctx| {
961 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.While,884 const node = try arena.construct(ast.Node.While{
962 ast.Node.While {885 .base = ast.Node{ .id = ast.Node.Id.While },
963 .base = undefined,886 .label = ctx.label,
964 .label = ctx.label,887 .inline_token = ctx.inline_token,
965 .inline_token = ctx.inline_token,888 .while_token = ctx.loop_token,
966 .while_token = ctx.loop_token,889 .condition = undefined,
967 .condition = undefined,890 .payload = null,
968 .payload = null,891 .continue_expr = null,
969 .continue_expr = null,892 .body = undefined,
970 .body = undefined,893 .@"else" = null,
971 .@"else" = null,894 });
972 }895 ctx.opt_ctx.store(&node.base);
973 );896 stack.append(State{ .Else = &node.@"else" }) catch unreachable;
974 stack.append(State { .Else = &node.@"else" }) catch unreachable;897 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
975 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });898 try stack.append(State{ .WhileContinueExpr = &node.continue_expr });
976 try stack.append(State { .WhileContinueExpr = &node.continue_expr });899 try stack.append(State{ .IfToken = Token.Id.Colon });
977 try stack.append(State { .IfToken = Token.Id.Colon });900 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });
978 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });901 try stack.append(State{ .ExpectToken = Token.Id.RParen });
979 try stack.append(State { .ExpectToken = Token.Id.RParen });902 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.condition } });
980 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });903 try stack.append(State{ .ExpectToken = Token.Id.LParen });
981 try stack.append(State { .ExpectToken = Token.Id.LParen });
982 continue;904 continue;
983 },905 },
984 State.WhileContinueExpr => |dest| {906 State.WhileContinueExpr => |dest| {
985 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;907 stack.append(State{ .ExpectToken = Token.Id.RParen }) catch unreachable;
986 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });908 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = dest } });
987 try stack.append(State { .ExpectToken = Token.Id.LParen });909 try stack.append(State{ .ExpectToken = Token.Id.LParen });
988 continue;910 continue;
989 },911 },
990 State.For => |ctx| {912 State.For => |ctx| {
991 const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.For,913 const node = try arena.construct(ast.Node.For{
992 ast.Node.For {914 .base = ast.Node{ .id = ast.Node.Id.For },
993 .base = undefined,915 .label = ctx.label,
994 .label = ctx.label,916 .inline_token = ctx.inline_token,
995 .inline_token = ctx.inline_token,917 .for_token = ctx.loop_token,
996 .for_token = ctx.loop_token,918 .array_expr = undefined,
997 .array_expr = undefined,919 .payload = null,
998 .payload = null,920 .body = undefined,
999 .body = undefined,921 .@"else" = null,
1000 .@"else" = null,922 });
1001 }923 ctx.opt_ctx.store(&node.base);
1002 );924 stack.append(State{ .Else = &node.@"else" }) catch unreachable;
1003 stack.append(State { .Else = &node.@"else" }) catch unreachable;925 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
1004 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });926 try stack.append(State{ .PointerIndexPayload = OptionalCtx{ .Optional = &node.payload } });
1005 try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });927 try stack.append(State{ .ExpectToken = Token.Id.RParen });
1006 try stack.append(State { .ExpectToken = Token.Id.RParen });928 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.array_expr } });
1007 try stack.append(State { .Expression = OptionalCtx { .Required = &node.array_expr } });929 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1008 try stack.append(State { .ExpectToken = Token.Id.LParen });
1009 continue;930 continue;
1010 },931 },
1011 State.Else => |dest| {932 State.Else => |dest| {
1012 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {933 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {
1013 const node = try createNode(arena, ast.Node.Else,934 const node = try arena.construct(ast.Node.Else{
1014 ast.Node.Else {935 .base = ast.Node{ .id = ast.Node.Id.Else },
1015 .base = undefined,936 .else_token = else_token,
1016 .else_token = else_token,937 .payload = null,
1017 .payload = null,938 .body = undefined,
1018 .body = undefined,939 });
1019 }940 dest.* = node;
1020 );
1021 *dest = node;
1022941
1023 stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;942 stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }) catch unreachable;
1024 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });943 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
1025 continue;944 continue;
1026 } else {945 } else {
1027 continue;946 continue;
1028 }947 }
1029 },948 },
1030949
1031
1032 State.Block => |block| {950 State.Block => |block| {
1033 const token = nextToken(&tok_it, &tree);951 const token = nextToken(&tok_it, &tree);
1034 const token_index = token.index;952 const token_index = token.index;
...@@ -1039,17 +957,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1039,17 +957,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1039 continue;957 continue;
1040 },958 },
1041 else => {959 else => {
1042 putBackToken(&tok_it, &tree);960 prevToken(&tok_it, &tree);
1043 stack.append(State { .Block = block }) catch unreachable;961 stack.append(State{ .Block = block }) catch unreachable;
1044
1045 var any_comments = false;
1046 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1047 try block.statements.push(&line_comment.base);
1048 any_comments = true;
1049 }
1050 if (any_comments) continue;
1051962
1052 try stack.append(State { .Statement = block });963 try stack.append(State{ .Statement = block });
1053 continue;964 continue;
1054 },965 },
1055 }966 }
...@@ -1060,33 +971,29 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1060,33 +971,29 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1060 const token_ptr = token.ptr;971 const token_ptr = token.ptr;
1061 switch (token_ptr.id) {972 switch (token_ptr.id) {
1062 Token.Id.Keyword_comptime => {973 Token.Id.Keyword_comptime => {
1063 stack.append(State {974 stack.append(State{ .ComptimeStatement = ComptimeStatementCtx{
1064 .ComptimeStatement = ComptimeStatementCtx {975 .comptime_token = token_index,
1065 .comptime_token = token_index,976 .block = block,
1066 .block = block,977 } }) catch unreachable;
1067 }
1068 }) catch unreachable;
1069 continue;
1070 },
1071 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1072 stack.append(State {
1073 .VarDecl = VarDeclCtx {
1074 .comments = null,
1075 .visib_token = null,
1076 .comptime_token = null,
1077 .extern_export_token = null,
1078 .lib_name = null,
1079 .mut_token = token_index,
1080 .list = &block.statements,
1081 }
1082 }) catch unreachable;
1083 continue;978 continue;
1084 },979 },
1085 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {980 Token.Id.Keyword_var,
1086 const node = try arena.construct(ast.Node.Defer {981 Token.Id.Keyword_const => {
1087 .base = ast.Node {982 stack.append(State{ .VarDecl = VarDeclCtx{
1088 .id = ast.Node.Id.Defer,983 .comments = null,
1089 },984 .visib_token = null,
985 .comptime_token = null,
986 .extern_export_token = null,
987 .lib_name = null,
988 .mut_token = token_index,
989 .list = &block.statements,
990 } }) catch unreachable;
991 continue;
992 },
993 Token.Id.Keyword_defer,
994 Token.Id.Keyword_errdefer => {
995 const node = try arena.construct(ast.Node.Defer{
996 .base = ast.Node{ .id = ast.Node.Id.Defer },
1090 .defer_token = token_index,997 .defer_token = token_index,
1091 .kind = switch (token_ptr.id) {998 .kind = switch (token_ptr.id) {
1092 Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,999 Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,
...@@ -1096,15 +1003,15 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1096,15 +1003,15 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1096 .expr = undefined,1003 .expr = undefined,
1097 });1004 });
1098 const node_ptr = try block.statements.addOne();1005 const node_ptr = try block.statements.addOne();
1099 *node_ptr = &node.base;1006 node_ptr.* = &node.base;
11001007
1101 stack.append(State { .Semicolon = node_ptr }) catch unreachable;1008 stack.append(State{ .Semicolon = node_ptr }) catch unreachable;
1102 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });1009 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1103 continue;1010 continue;
1104 },1011 },
1105 Token.Id.LBrace => {1012 Token.Id.LBrace => {
1106 const inner_block = try arena.construct(ast.Node.Block {1013 const inner_block = try arena.construct(ast.Node.Block{
1107 .base = ast.Node { .id = ast.Node.Id.Block },1014 .base = ast.Node{ .id = ast.Node.Id.Block },
1108 .label = null,1015 .label = null,
1109 .lbrace = token_index,1016 .lbrace = token_index,
1110 .statements = ast.Node.Block.StatementList.init(arena),1017 .statements = ast.Node.Block.StatementList.init(arena),
...@@ -1112,16 +1019,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1112,16 +1019,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1112 });1019 });
1113 try block.statements.push(&inner_block.base);1020 try block.statements.push(&inner_block.base);
11141021
1115 stack.append(State { .Block = inner_block }) catch unreachable;1022 stack.append(State{ .Block = inner_block }) catch unreachable;
1116 continue;1023 continue;
1117 },1024 },
1118 else => {1025 else => {
1119 putBackToken(&tok_it, &tree);1026 prevToken(&tok_it, &tree);
1120 const statement = try block.statements.addOne();1027 const statement = try block.statements.addOne();
1121 try stack.append(State { .Semicolon = statement });1028 try stack.append(State{ .Semicolon = statement });
1122 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });1029 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1123 continue;1030 continue;
1124 }1031 },
1125 }1032 }
1126 },1033 },
1127 State.ComptimeStatement => |ctx| {1034 State.ComptimeStatement => |ctx| {
...@@ -1129,34 +1036,33 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1129,34 +1036,33 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1129 const token_index = token.index;1036 const token_index = token.index;
1130 const token_ptr = token.ptr;1037 const token_ptr = token.ptr;
1131 switch (token_ptr.id) {1038 switch (token_ptr.id) {
1132 Token.Id.Keyword_var, Token.Id.Keyword_const => {1039 Token.Id.Keyword_var,
1133 stack.append(State {1040 Token.Id.Keyword_const => {
1134 .VarDecl = VarDeclCtx {1041 stack.append(State{ .VarDecl = VarDeclCtx{
1135 .comments = null,1042 .comments = null,
1136 .visib_token = null,1043 .visib_token = null,
1137 .comptime_token = ctx.comptime_token,1044 .comptime_token = ctx.comptime_token,
1138 .extern_export_token = null,1045 .extern_export_token = null,
1139 .lib_name = null,1046 .lib_name = null,
1140 .mut_token = token_index,1047 .mut_token = token_index,
1141 .list = &ctx.block.statements,1048 .list = &ctx.block.statements,
1142 }1049 } }) catch unreachable;
1143 }) catch unreachable;
1144 continue;1050 continue;
1145 },1051 },
1146 else => {1052 else => {
1147 putBackToken(&tok_it, &tree);1053 prevToken(&tok_it, &tree);
1148 putBackToken(&tok_it, &tree);1054 prevToken(&tok_it, &tree);
1149 const statement = try ctx.block.statements.addOne();1055 const statement = try ctx.block.statements.addOne();
1150 try stack.append(State { .Semicolon = statement });1056 try stack.append(State{ .Semicolon = statement });
1151 try stack.append(State { .Expression = OptionalCtx { .Required = statement } });1057 try stack.append(State{ .Expression = OptionalCtx{ .Required = statement } });
1152 continue;1058 continue;
1153 }1059 },
1154 }1060 }
1155 },1061 },
1156 State.Semicolon => |node_ptr| {1062 State.Semicolon => |node_ptr| {
1157 const node = *node_ptr;1063 const node = node_ptr.*;
1158 if (node.requireSemiColon()) {1064 if (node.requireSemiColon()) {
1159 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;1065 stack.append(State{ .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1160 continue;1066 continue;
1161 }1067 }
1162 continue;1068 continue;
...@@ -1167,28 +1073,31 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1167,28 +1073,31 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1167 const lbracket_index = lbracket.index;1073 const lbracket_index = lbracket.index;
1168 const lbracket_ptr = lbracket.ptr;1074 const lbracket_ptr = lbracket.ptr;
1169 if (lbracket_ptr.id != Token.Id.LBracket) {1075 if (lbracket_ptr.id != Token.Id.LBracket) {
1170 putBackToken(&tok_it, &tree);1076 prevToken(&tok_it, &tree);
1171 continue;1077 continue;
1172 }1078 }
11731079
1174 const node = try createNode(arena, ast.Node.AsmOutput,1080 const node = try arena.construct(ast.Node.AsmOutput{
1175 ast.Node.AsmOutput {1081 .base = ast.Node{ .id = ast.Node.Id.AsmOutput },
1176 .base = undefined,1082 .lbracket = lbracket_index,
1177 .symbolic_name = undefined,1083 .symbolic_name = undefined,
1178 .constraint = undefined,1084 .constraint = undefined,
1179 .kind = undefined,1085 .kind = undefined,
1180 }1086 .rparen = undefined,
1181 );1087 });
1182 try items.push(node);1088 try items.push(node);
11831089
1184 stack.append(State { .AsmOutputItems = items }) catch unreachable;1090 stack.append(State{ .AsmOutputItems = items }) catch unreachable;
1185 try stack.append(State { .IfToken = Token.Id.Comma });1091 try stack.append(State{ .IfToken = Token.Id.Comma });
1186 try stack.append(State { .ExpectToken = Token.Id.RParen });1092 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1187 try stack.append(State { .AsmOutputReturnOrType = node });1093 .id = Token.Id.RParen,
1188 try stack.append(State { .ExpectToken = Token.Id.LParen });1094 .ptr = &node.rparen,
1189 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });1095 } });
1190 try stack.append(State { .ExpectToken = Token.Id.RBracket });1096 try stack.append(State{ .AsmOutputReturnOrType = node });
1191 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });1097 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1098 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });
1099 try stack.append(State{ .ExpectToken = Token.Id.RBracket });
1100 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.symbolic_name } });
1192 continue;1101 continue;
1193 },1102 },
1194 State.AsmOutputReturnOrType => |node| {1103 State.AsmOutputReturnOrType => |node| {
...@@ -1197,20 +1106,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1197,20 +1106,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1197 const token_ptr = token.ptr;1106 const token_ptr = token.ptr;
1198 switch (token_ptr.id) {1107 switch (token_ptr.id) {
1199 Token.Id.Identifier => {1108 Token.Id.Identifier => {
1200 node.kind = ast.Node.AsmOutput.Kind { .Variable = try createLiteral(arena, ast.Node.Identifier, token_index) };1109 node.kind = ast.Node.AsmOutput.Kind{ .Variable = try createLiteral(arena, ast.Node.Identifier, token_index) };
1201 continue;1110 continue;
1202 },1111 },
1203 Token.Id.Arrow => {1112 Token.Id.Arrow => {
1204 node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };1113 node.kind = ast.Node.AsmOutput.Kind{ .Return = undefined };
1205 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });1114 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.kind.Return } });
1206 continue;1115 continue;
1207 },1116 },
1208 else => {1117 else => {
1209 *(try tree.errors.addOne()) = Error {1118 ((try tree.errors.addOne())).* = Error{ .ExpectedAsmOutputReturnOrType = Error.ExpectedAsmOutputReturnOrType{ .token = token_index } };
1210 .ExpectedAsmOutputReturnOrType = Error.ExpectedAsmOutputReturnOrType {
1211 .token = token_index,
1212 },
1213 };
1214 return tree;1119 return tree;
1215 },1120 },
1216 }1121 }
...@@ -1220,55 +1125,57 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1220,55 +1125,57 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1220 const lbracket_index = lbracket.index;1125 const lbracket_index = lbracket.index;
1221 const lbracket_ptr = lbracket.ptr;1126 const lbracket_ptr = lbracket.ptr;
1222 if (lbracket_ptr.id != Token.Id.LBracket) {1127 if (lbracket_ptr.id != Token.Id.LBracket) {
1223 putBackToken(&tok_it, &tree);1128 prevToken(&tok_it, &tree);
1224 continue;1129 continue;
1225 }1130 }
12261131
1227 const node = try createNode(arena, ast.Node.AsmInput,1132 const node = try arena.construct(ast.Node.AsmInput{
1228 ast.Node.AsmInput {1133 .base = ast.Node{ .id = ast.Node.Id.AsmInput },
1229 .base = undefined,1134 .lbracket = lbracket_index,
1230 .symbolic_name = undefined,1135 .symbolic_name = undefined,
1231 .constraint = undefined,1136 .constraint = undefined,
1232 .expr = undefined,1137 .expr = undefined,
1233 }1138 .rparen = undefined,
1234 );1139 });
1235 try items.push(node);1140 try items.push(node);
12361141
1237 stack.append(State { .AsmInputItems = items }) catch unreachable;1142 stack.append(State{ .AsmInputItems = items }) catch unreachable;
1238 try stack.append(State { .IfToken = Token.Id.Comma });1143 try stack.append(State{ .IfToken = Token.Id.Comma });
1239 try stack.append(State { .ExpectToken = Token.Id.RParen });1144 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1240 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });1145 .id = Token.Id.RParen,
1241 try stack.append(State { .ExpectToken = Token.Id.LParen });1146 .ptr = &node.rparen,
1242 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });1147 } });
1243 try stack.append(State { .ExpectToken = Token.Id.RBracket });1148 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
1244 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });1149 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1150 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });
1151 try stack.append(State{ .ExpectToken = Token.Id.RBracket });
1152 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.symbolic_name } });
1245 continue;1153 continue;
1246 },1154 },
1247 State.AsmClobberItems => |items| {1155 State.AsmClobberItems => |items| {
1248 stack.append(State { .AsmClobberItems = items }) catch unreachable;1156 stack.append(State{ .AsmClobberItems = items }) catch unreachable;
1249 try stack.append(State { .IfToken = Token.Id.Comma });1157 try stack.append(State{ .IfToken = Token.Id.Comma });
1250 try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });1158 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = try items.addOne() } });
1251 continue;1159 continue;
1252 },1160 },
12531161
1254
1255 State.ExprListItemOrEnd => |list_state| {1162 State.ExprListItemOrEnd => |list_state| {
1256 if (eatToken(&tok_it, &tree, list_state.end)) |token_index| {1163 if (eatToken(&tok_it, &tree, list_state.end)) |token_index| {
1257 *list_state.ptr = token_index;1164 (list_state.ptr).* = token_index;
1258 continue;1165 continue;
1259 }1166 }
12601167
1261 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;1168 stack.append(State{ .ExprListCommaOrEnd = list_state }) catch unreachable;
1262 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });1169 try stack.append(State{ .Expression = OptionalCtx{ .Required = try list_state.list.addOne() } });
1263 continue;1170 continue;
1264 },1171 },
1265 State.ExprListCommaOrEnd => |list_state| {1172 State.ExprListCommaOrEnd => |list_state| {
1266 switch (expectCommaOrEnd(&tok_it, &tree, list_state.end)) {1173 switch (expectCommaOrEnd(&tok_it, &tree, list_state.end)) {
1267 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {1174 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1268 *list_state.ptr = end;1175 (list_state.ptr).* = end;
1269 continue;1176 continue;
1270 } else {1177 } else {
1271 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;1178 stack.append(State{ .ExprListItemOrEnd = list_state }) catch unreachable;
1272 continue;1179 continue;
1273 },1180 },
1274 ExpectCommaOrEndResult.parse_error => |e| {1181 ExpectCommaOrEndResult.parse_error => |e| {
...@@ -1278,49 +1185,39 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1278,49 +1185,39 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1278 }1185 }
1279 },1186 },
1280 State.FieldInitListItemOrEnd => |list_state| {1187 State.FieldInitListItemOrEnd => |list_state| {
1281 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1282 try list_state.list.push(&line_comment.base);
1283 }
1284
1285 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {1188 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1286 *list_state.ptr = rbrace;1189 (list_state.ptr).* = rbrace;
1287 continue;1190 continue;
1288 }1191 }
12891192
1290 const node = try arena.construct(ast.Node.FieldInitializer {1193 const node = try arena.construct(ast.Node.FieldInitializer{
1291 .base = ast.Node {1194 .base = ast.Node{ .id = ast.Node.Id.FieldInitializer },
1292 .id = ast.Node.Id.FieldInitializer,
1293 },
1294 .period_token = undefined,1195 .period_token = undefined,
1295 .name_token = undefined,1196 .name_token = undefined,
1296 .expr = undefined,1197 .expr = undefined,
1297 });1198 });
1298 try list_state.list.push(&node.base);1199 try list_state.list.push(&node.base);
12991200
1300 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;1201 stack.append(State{ .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1301 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });1202 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
1302 try stack.append(State { .ExpectToken = Token.Id.Equal });1203 try stack.append(State{ .ExpectToken = Token.Id.Equal });
1303 try stack.append(State {1204 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1304 .ExpectTokenSave = ExpectTokenSave {1205 .id = Token.Id.Identifier,
1305 .id = Token.Id.Identifier,1206 .ptr = &node.name_token,
1306 .ptr = &node.name_token,1207 } });
1307 }1208 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1308 });1209 .id = Token.Id.Period,
1309 try stack.append(State {1210 .ptr = &node.period_token,
1310 .ExpectTokenSave = ExpectTokenSave {1211 } });
1311 .id = Token.Id.Period,
1312 .ptr = &node.period_token,
1313 }
1314 });
1315 continue;1212 continue;
1316 },1213 },
1317 State.FieldInitListCommaOrEnd => |list_state| {1214 State.FieldInitListCommaOrEnd => |list_state| {
1318 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {1215 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1319 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {1216 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1320 *list_state.ptr = end;1217 (list_state.ptr).* = end;
1321 continue;1218 continue;
1322 } else {1219 } else {
1323 stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;1220 stack.append(State{ .FieldInitListItemOrEnd = list_state }) catch unreachable;
1324 continue;1221 continue;
1325 },1222 },
1326 ExpectCommaOrEndResult.parse_error => |e| {1223 ExpectCommaOrEndResult.parse_error => |e| {
...@@ -1335,7 +1232,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1335,7 +1232,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1335 container_decl.rbrace_token = end;1232 container_decl.rbrace_token = end;
1336 continue;1233 continue;
1337 } else {1234 } else {
1338 try stack.append(State { .ContainerDecl = container_decl });1235 try stack.append(State{ .ContainerDecl = container_decl });
1339 continue;1236 continue;
1340 },1237 },
1341 ExpectCommaOrEndResult.parse_error => |e| {1238 ExpectCommaOrEndResult.parse_error => |e| {
...@@ -1345,28 +1242,24 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1345,28 +1242,24 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1345 }1242 }
1346 },1243 },
1347 State.ErrorTagListItemOrEnd => |list_state| {1244 State.ErrorTagListItemOrEnd => |list_state| {
1348 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1349 try list_state.list.push(&line_comment.base);
1350 }
1351
1352 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {1245 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1353 *list_state.ptr = rbrace;1246 (list_state.ptr).* = rbrace;
1354 continue;1247 continue;
1355 }1248 }
13561249
1357 const node_ptr = try list_state.list.addOne();1250 const node_ptr = try list_state.list.addOne();
13581251
1359 try stack.append(State { .ErrorTagListCommaOrEnd = list_state });1252 try stack.append(State{ .ErrorTagListCommaOrEnd = list_state });
1360 try stack.append(State { .ErrorTag = node_ptr });1253 try stack.append(State{ .ErrorTag = node_ptr });
1361 continue;1254 continue;
1362 },1255 },
1363 State.ErrorTagListCommaOrEnd => |list_state| {1256 State.ErrorTagListCommaOrEnd => |list_state| {
1364 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {1257 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1365 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {1258 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1366 *list_state.ptr = end;1259 (list_state.ptr).* = end;
1367 continue;1260 continue;
1368 } else {1261 } else {
1369 stack.append(State { .ErrorTagListItemOrEnd = list_state }) catch unreachable;1262 stack.append(State{ .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1370 continue;1263 continue;
1371 },1264 },
1372 ExpectCommaOrEndResult.parse_error => |e| {1265 ExpectCommaOrEndResult.parse_error => |e| {
...@@ -1376,40 +1269,35 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1376,40 +1269,35 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1376 }1269 }
1377 },1270 },
1378 State.SwitchCaseOrEnd => |list_state| {1271 State.SwitchCaseOrEnd => |list_state| {
1379 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1380 try list_state.list.push(&line_comment.base);
1381 }
1382
1383 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {1272 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1384 *list_state.ptr = rbrace;1273 (list_state.ptr).* = rbrace;
1385 continue;1274 continue;
1386 }1275 }
13871276
1388 const comments = try eatDocComments(arena, &tok_it, &tree);1277 const comments = try eatDocComments(arena, &tok_it, &tree);
1389 const node = try arena.construct(ast.Node.SwitchCase {1278 const node = try arena.construct(ast.Node.SwitchCase{
1390 .base = ast.Node {1279 .base = ast.Node{ .id = ast.Node.Id.SwitchCase },
1391 .id = ast.Node.Id.SwitchCase,
1392 },
1393 .items = ast.Node.SwitchCase.ItemList.init(arena),1280 .items = ast.Node.SwitchCase.ItemList.init(arena),
1394 .payload = null,1281 .payload = null,
1395 .expr = undefined,1282 .expr = undefined,
1283 .arrow_token = undefined,
1396 });1284 });
1397 try list_state.list.push(&node.base);1285 try list_state.list.push(&node.base);
1398 try stack.append(State { .SwitchCaseCommaOrEnd = list_state });1286 try stack.append(State{ .SwitchCaseCommaOrEnd = list_state });
1399 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });1287 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1400 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });1288 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });
1401 try stack.append(State { .SwitchCaseFirstItem = &node.items });1289 try stack.append(State{ .SwitchCaseFirstItem = node });
14021290
1403 continue;1291 continue;
1404 },1292 },
14051293
1406 State.SwitchCaseCommaOrEnd => |list_state| {1294 State.SwitchCaseCommaOrEnd => |list_state| {
1407 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RParen)) {1295 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.RBrace)) {
1408 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {1296 ExpectCommaOrEndResult.end_token => |maybe_end| if (maybe_end) |end| {
1409 *list_state.ptr = end;1297 (list_state.ptr).* = end;
1410 continue;1298 continue;
1411 } else {1299 } else {
1412 try stack.append(State { .SwitchCaseOrEnd = list_state });1300 try stack.append(State{ .SwitchCaseOrEnd = list_state });
1413 continue;1301 continue;
1414 },1302 },
1415 ExpectCommaOrEndResult.parse_error => |e| {1303 ExpectCommaOrEndResult.parse_error => |e| {
...@@ -1419,34 +1307,48 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1419,34 +1307,48 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1419 }1307 }
1420 },1308 },
14211309
1422 State.SwitchCaseFirstItem => |case_items| {1310 State.SwitchCaseFirstItem => |switch_case| {
1423 const token = nextToken(&tok_it, &tree);1311 const token = nextToken(&tok_it, &tree);
1424 const token_index = token.index;1312 const token_index = token.index;
1425 const token_ptr = token.ptr;1313 const token_ptr = token.ptr;
1426 if (token_ptr.id == Token.Id.Keyword_else) {1314 if (token_ptr.id == Token.Id.Keyword_else) {
1427 const else_node = try arena.construct(ast.Node.SwitchElse {1315 const else_node = try arena.construct(ast.Node.SwitchElse{
1428 .base = ast.Node{ .id = ast.Node.Id.SwitchElse},1316 .base = ast.Node{ .id = ast.Node.Id.SwitchElse },
1429 .token = token_index,1317 .token = token_index,
1430 });1318 });
1431 try case_items.push(&else_node.base);1319 try switch_case.items.push(&else_node.base);
14321320
1433 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });1321 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1322 .id = Token.Id.EqualAngleBracketRight,
1323 .ptr = &switch_case.arrow_token,
1324 } });
1434 continue;1325 continue;
1435 } else {1326 } else {
1436 putBackToken(&tok_it, &tree);1327 prevToken(&tok_it, &tree);
1437 try stack.append(State { .SwitchCaseItem = case_items });1328 stack.append(State{ .SwitchCaseItemCommaOrEnd = switch_case }) catch unreachable;
1329 try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try switch_case.items.addOne() } });
1438 continue;1330 continue;
1439 }1331 }
1440 },1332 },
1441 State.SwitchCaseItem => |case_items| {1333 State.SwitchCaseItemOrEnd => |switch_case| {
1442 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;1334 const token = nextToken(&tok_it, &tree);
1443 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });1335 if (token.ptr.id == Token.Id.EqualAngleBracketRight) {
1336 switch_case.arrow_token = token.index;
1337 continue;
1338 } else {
1339 prevToken(&tok_it, &tree);
1340 stack.append(State{ .SwitchCaseItemCommaOrEnd = switch_case }) catch unreachable;
1341 try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try switch_case.items.addOne() } });
1342 continue;
1343 }
1444 },1344 },
1445 State.SwitchCaseItemCommaOrEnd => |case_items| {1345 State.SwitchCaseItemCommaOrEnd => |switch_case| {
1446 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.EqualAngleBracketRight)) {1346 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.EqualAngleBracketRight)) {
1447 ExpectCommaOrEndResult.end_token => |t| {1347 ExpectCommaOrEndResult.end_token => |end_token| {
1448 if (t == null) {1348 if (end_token) |t| {
1449 stack.append(State { .SwitchCaseItem = case_items }) catch unreachable;1349 switch_case.arrow_token = t;
1350 } else {
1351 stack.append(State{ .SwitchCaseItemOrEnd = switch_case }) catch unreachable;
1450 }1352 }
1451 continue;1353 continue;
1452 },1354 },
...@@ -1458,10 +1360,9 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1458,10 +1360,9 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1458 continue;1360 continue;
1459 },1361 },
14601362
1461
1462 State.SuspendBody => |suspend_node| {1363 State.SuspendBody => |suspend_node| {
1463 if (suspend_node.payload != null) {1364 if (suspend_node.payload != null) {
1464 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });1365 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = &suspend_node.body } });
1465 }1366 }
1466 continue;1367 continue;
1467 },1368 },
...@@ -1471,13 +1372,11 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1471,13 +1372,11 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1471 }1372 }
14721373
1473 async_node.rangle_bracket = TokenIndex(0);1374 async_node.rangle_bracket = TokenIndex(0);
1474 try stack.append(State {1375 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1475 .ExpectTokenSave = ExpectTokenSave {1376 .id = Token.Id.AngleBracketRight,
1476 .id = Token.Id.AngleBracketRight,1377 .ptr = &??async_node.rangle_bracket,
1477 .ptr = &??async_node.rangle_bracket,1378 } });
1478 }1379 try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &async_node.allocator_type } });
1479 });
1480 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1481 continue;1380 continue;
1482 },1381 },
1483 State.AsyncEnd => |ctx| {1382 State.AsyncEnd => |ctx| {
...@@ -1496,27 +1395,20 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1496,27 +1395,20 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1496 continue;1395 continue;
1497 }1396 }
14981397
1499 *(try tree.errors.addOne()) = Error {1398 ((try tree.errors.addOne())).* = Error{ .ExpectedCall = Error.ExpectedCall{ .node = node } };
1500 .ExpectedCall = Error.ExpectedCall { .node = node },
1501 };
1502 return tree;1399 return tree;
1503 },1400 },
1504 else => {1401 else => {
1505 *(try tree.errors.addOne()) = Error {1402 ((try tree.errors.addOne())).* = Error{ .ExpectedCallOrFnProto = Error.ExpectedCallOrFnProto{ .node = node } };
1506 .ExpectedCallOrFnProto = Error.ExpectedCallOrFnProto { .node = node },
1507 };
1508 return tree;1403 return tree;
1509 }1404 },
1510 }1405 }
1511 },1406 },
15121407
1513
1514 State.ExternType => |ctx| {1408 State.ExternType => |ctx| {
1515 if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| {1409 if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| {
1516 const fn_proto = try arena.construct(ast.Node.FnProto {1410 const fn_proto = try arena.construct(ast.Node.FnProto{
1517 .base = ast.Node {1411 .base = ast.Node{ .id = ast.Node.Id.FnProto },
1518 .id = ast.Node.Id.FnProto,
1519 },
1520 .doc_comments = ctx.comments,1412 .doc_comments = ctx.comments,
1521 .visib_token = null,1413 .visib_token = null,
1522 .name_token = null,1414 .name_token = null,
...@@ -1532,17 +1424,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1532,17 +1424,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1532 .align_expr = null,1424 .align_expr = null,
1533 });1425 });
1534 ctx.opt_ctx.store(&fn_proto.base);1426 ctx.opt_ctx.store(&fn_proto.base);
1535 stack.append(State { .FnProto = fn_proto }) catch unreachable;1427 stack.append(State{ .FnProto = fn_proto }) catch unreachable;
1536 continue;1428 continue;
1537 }1429 }
15381430
1539 stack.append(State {1431 stack.append(State{ .ContainerKind = ContainerKindCtx{
1540 .ContainerKind = ContainerKindCtx {1432 .opt_ctx = ctx.opt_ctx,
1541 .opt_ctx = ctx.opt_ctx,1433 .layout_token = ctx.extern_token,
1542 .ltoken = ctx.extern_token,1434 } }) catch unreachable;
1543 .layout = ast.Node.ContainerDecl.Layout.Extern,
1544 },
1545 }) catch unreachable;
1546 continue;1435 continue;
1547 },1436 },
1548 State.SliceOrArrayAccess => |node| {1437 State.SliceOrArrayAccess => |node| {
...@@ -1552,20 +1441,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1552,20 +1441,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1552 switch (token_ptr.id) {1441 switch (token_ptr.id) {
1553 Token.Id.Ellipsis2 => {1442 Token.Id.Ellipsis2 => {
1554 const start = node.op.ArrayAccess;1443 const start = node.op.ArrayAccess;
1555 node.op = ast.Node.SuffixOp.Op {1444 node.op = ast.Node.SuffixOp.Op{ .Slice = ast.Node.SuffixOp.Op.Slice{
1556 .Slice = ast.Node.SuffixOp.Op.Slice {1445 .start = start,
1557 .start = start,1446 .end = null,
1558 .end = null,1447 } };
1559 }
1560 };
15611448
1562 stack.append(State {1449 stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1563 .ExpectTokenSave = ExpectTokenSave {1450 .id = Token.Id.RBracket,
1564 .id = Token.Id.RBracket,1451 .ptr = &node.rtoken,
1565 .ptr = &node.rtoken,1452 } }) catch unreachable;
1566 }1453 try stack.append(State{ .Expression = OptionalCtx{ .Optional = &node.op.Slice.end } });
1567 }) catch unreachable;
1568 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
1569 continue;1454 continue;
1570 },1455 },
1571 Token.Id.RBracket => {1456 Token.Id.RBracket => {
...@@ -1573,35 +1458,30 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1573,35 +1458,30 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1573 continue;1458 continue;
1574 },1459 },
1575 else => {1460 else => {
1576 *(try tree.errors.addOne()) = Error {1461 ((try tree.errors.addOne())).* = Error{ .ExpectedSliceOrRBracket = Error.ExpectedSliceOrRBracket{ .token = token_index } };
1577 .ExpectedSliceOrRBracket = Error.ExpectedSliceOrRBracket { .token = token_index },
1578 };
1579 return tree;1462 return tree;
1580 }1463 },
1581 }1464 }
1582 },1465 },
1583 State.SliceOrArrayType => |node| {1466 State.SliceOrArrayType => |node| {
1584 if (eatToken(&tok_it, &tree, Token.Id.RBracket)) |_| {1467 if (eatToken(&tok_it, &tree, Token.Id.RBracket)) |_| {
1585 node.op = ast.Node.PrefixOp.Op {1468 node.op = ast.Node.PrefixOp.Op{ .SliceType = ast.Node.PrefixOp.AddrOfInfo{
1586 .SliceType = ast.Node.PrefixOp.AddrOfInfo {1469 .align_info = null,
1587 .align_expr = null,1470 .const_token = null,
1588 .bit_offset_start_token = null,1471 .volatile_token = null,
1589 .bit_offset_end_token = null,1472 } };
1590 .const_token = null,1473 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
1591 .volatile_token = null,1474 try stack.append(State{ .AddrOfModifiers = &node.op.SliceType });
1592 }
1593 };
1594 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1595 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1596 continue;1475 continue;
1597 }1476 }
15981477
1599 node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };1478 node.op = ast.Node.PrefixOp.Op{ .ArrayType = undefined };
1600 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;1479 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
1601 try stack.append(State { .ExpectToken = Token.Id.RBracket });1480 try stack.append(State{ .ExpectToken = Token.Id.RBracket });
1602 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });1481 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.op.ArrayType } });
1603 continue;1482 continue;
1604 },1483 },
1484
1605 State.AddrOfModifiers => |addr_of_info| {1485 State.AddrOfModifiers => |addr_of_info| {
1606 const token = nextToken(&tok_it, &tree);1486 const token = nextToken(&tok_it, &tree);
1607 const token_index = token.index;1487 const token_index = token.index;
...@@ -1609,23 +1489,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1609,23 +1489,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1609 switch (token_ptr.id) {1489 switch (token_ptr.id) {
1610 Token.Id.Keyword_align => {1490 Token.Id.Keyword_align => {
1611 stack.append(state) catch unreachable;1491 stack.append(state) catch unreachable;
1612 if (addr_of_info.align_expr != null) {1492 if (addr_of_info.align_info != null) {
1613 *(try tree.errors.addOne()) = Error {1493 ((try tree.errors.addOne())).* = Error{ .ExtraAlignQualifier = Error.ExtraAlignQualifier{ .token = token_index } };
1614 .ExtraAlignQualifier = Error.ExtraAlignQualifier { .token = token_index },
1615 };
1616 return tree;1494 return tree;
1617 }1495 }
1618 try stack.append(State { .ExpectToken = Token.Id.RParen });1496 addr_of_info.align_info = ast.Node.PrefixOp.AddrOfInfo.Align {
1619 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });1497 .node = undefined,
1620 try stack.append(State { .ExpectToken = Token.Id.LParen });1498 .bit_range = null,
1499 };
1500 // TODO https://github.com/ziglang/zig/issues/1022
1501 const align_info = &??addr_of_info.align_info;
1502
1503 try stack.append(State{ .AlignBitRange = align_info });
1504 try stack.append(State{ .Expression = OptionalCtx{ .Required = &align_info.node } });
1505 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1621 continue;1506 continue;
1622 },1507 },
1623 Token.Id.Keyword_const => {1508 Token.Id.Keyword_const => {
1624 stack.append(state) catch unreachable;1509 stack.append(state) catch unreachable;
1625 if (addr_of_info.const_token != null) {1510 if (addr_of_info.const_token != null) {
1626 *(try tree.errors.addOne()) = Error {1511 ((try tree.errors.addOne())).* = Error{ .ExtraConstQualifier = Error.ExtraConstQualifier{ .token = token_index } };
1627 .ExtraConstQualifier = Error.ExtraConstQualifier { .token = token_index },
1628 };
1629 return tree;1512 return tree;
1630 }1513 }
1631 addr_of_info.const_token = token_index;1514 addr_of_info.const_token = token_index;
...@@ -1634,21 +1517,43 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1634,21 +1517,43 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1634 Token.Id.Keyword_volatile => {1517 Token.Id.Keyword_volatile => {
1635 stack.append(state) catch unreachable;1518 stack.append(state) catch unreachable;
1636 if (addr_of_info.volatile_token != null) {1519 if (addr_of_info.volatile_token != null) {
1637 *(try tree.errors.addOne()) = Error {1520 ((try tree.errors.addOne())).* = Error{ .ExtraVolatileQualifier = Error.ExtraVolatileQualifier{ .token = token_index } };
1638 .ExtraVolatileQualifier = Error.ExtraVolatileQualifier { .token = token_index },
1639 };
1640 return tree;1521 return tree;
1641 }1522 }
1642 addr_of_info.volatile_token = token_index;1523 addr_of_info.volatile_token = token_index;
1643 continue;1524 continue;
1644 },1525 },
1645 else => {1526 else => {
1646 putBackToken(&tok_it, &tree);1527 prevToken(&tok_it, &tree);
1647 continue;1528 continue;
1648 },1529 },
1649 }1530 }
1650 },1531 },
16511532
1533 State.AlignBitRange => |align_info| {
1534 const token = nextToken(&tok_it, &tree);
1535 switch (token.ptr.id) {
1536 Token.Id.Colon => {
1537 align_info.bit_range = ast.Node.PrefixOp.AddrOfInfo.Align.BitRange(undefined);
1538 const bit_range = &??align_info.bit_range;
1539
1540 try stack.append(State{ .ExpectToken = Token.Id.RParen });
1541 try stack.append(State{ .Expression = OptionalCtx{ .Required = &bit_range.end } });
1542 try stack.append(State{ .ExpectToken = Token.Id.Colon });
1543 try stack.append(State{ .Expression = OptionalCtx{ .Required = &bit_range.start } });
1544 continue;
1545 },
1546 Token.Id.RParen => continue,
1547 else => {
1548 (try tree.errors.addOne()).* = Error{
1549 .ExpectedColonOrRParen = Error.ExpectedColonOrRParen{
1550 .token = token.index,
1551 }
1552 };
1553 return tree;
1554 },
1555 }
1556 },
16521557
1653 State.Payload => |opt_ctx| {1558 State.Payload => |opt_ctx| {
1654 const token = nextToken(&tok_it, &tree);1559 const token = nextToken(&tok_it, &tree);
...@@ -1656,35 +1561,30 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1656,35 +1561,30 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1656 const token_ptr = token.ptr;1561 const token_ptr = token.ptr;
1657 if (token_ptr.id != Token.Id.Pipe) {1562 if (token_ptr.id != Token.Id.Pipe) {
1658 if (opt_ctx != OptionalCtx.Optional) {1563 if (opt_ctx != OptionalCtx.Optional) {
1659 *(try tree.errors.addOne()) = Error {1564 ((try tree.errors.addOne())).* = Error{ .ExpectedToken = Error.ExpectedToken{
1660 .ExpectedToken = Error.ExpectedToken {1565 .token = token_index,
1661 .token = token_index,1566 .expected_id = Token.Id.Pipe,
1662 .expected_id = Token.Id.Pipe,1567 } };
1663 },
1664 };
1665 return tree;1568 return tree;
1666 }1569 }
16671570
1668 putBackToken(&tok_it, &tree);1571 prevToken(&tok_it, &tree);
1669 continue;1572 continue;
1670 }1573 }
16711574
1672 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Payload,1575 const node = try arena.construct(ast.Node.Payload{
1673 ast.Node.Payload {1576 .base = ast.Node{ .id = ast.Node.Id.Payload },
1674 .base = undefined,1577 .lpipe = token_index,
1675 .lpipe = token_index,1578 .error_symbol = undefined,
1676 .error_symbol = undefined,1579 .rpipe = undefined,
1677 .rpipe = undefined1580 });
1678 }1581 opt_ctx.store(&node.base);
1679 );
16801582
1681 stack.append(State {1583 stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1682 .ExpectTokenSave = ExpectTokenSave {1584 .id = Token.Id.Pipe,
1683 .id = Token.Id.Pipe,1585 .ptr = &node.rpipe,
1684 .ptr = &node.rpipe,1586 } }) catch unreachable;
1685 }1587 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.error_symbol } });
1686 }) catch unreachable;
1687 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1688 continue;1588 continue;
1689 },1589 },
1690 State.PointerPayload => |opt_ctx| {1590 State.PointerPayload => |opt_ctx| {
...@@ -1693,42 +1593,35 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1693,42 +1593,35 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1693 const token_ptr = token.ptr;1593 const token_ptr = token.ptr;
1694 if (token_ptr.id != Token.Id.Pipe) {1594 if (token_ptr.id != Token.Id.Pipe) {
1695 if (opt_ctx != OptionalCtx.Optional) {1595 if (opt_ctx != OptionalCtx.Optional) {
1696 *(try tree.errors.addOne()) = Error {1596 ((try tree.errors.addOne())).* = Error{ .ExpectedToken = Error.ExpectedToken{
1697 .ExpectedToken = Error.ExpectedToken {1597 .token = token_index,
1698 .token = token_index,1598 .expected_id = Token.Id.Pipe,
1699 .expected_id = Token.Id.Pipe,1599 } };
1700 },
1701 };
1702 return tree;1600 return tree;
1703 }1601 }
17041602
1705 putBackToken(&tok_it, &tree);1603 prevToken(&tok_it, &tree);
1706 continue;1604 continue;
1707 }1605 }
17081606
1709 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,1607 const node = try arena.construct(ast.Node.PointerPayload{
1710 ast.Node.PointerPayload {1608 .base = ast.Node{ .id = ast.Node.Id.PointerPayload },
1711 .base = undefined,1609 .lpipe = token_index,
1712 .lpipe = token_index,1610 .ptr_token = null,
1713 .ptr_token = null,1611 .value_symbol = undefined,
1714 .value_symbol = undefined,1612 .rpipe = undefined,
1715 .rpipe = undefined
1716 }
1717 );
1718
1719 try stack.append(State {
1720 .ExpectTokenSave = ExpectTokenSave {
1721 .id = Token.Id.Pipe,
1722 .ptr = &node.rpipe,
1723 }
1724 });
1725 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1726 try stack.append(State {
1727 .OptionalTokenSave = OptionalTokenSave {
1728 .id = Token.Id.Asterisk,
1729 .ptr = &node.ptr_token,
1730 }
1731 });1613 });
1614 opt_ctx.store(&node.base);
1615
1616 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1617 .id = Token.Id.Pipe,
1618 .ptr = &node.rpipe,
1619 } });
1620 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.value_symbol } });
1621 try stack.append(State{ .OptionalTokenSave = OptionalTokenSave{
1622 .id = Token.Id.Asterisk,
1623 .ptr = &node.ptr_token,
1624 } });
1732 continue;1625 continue;
1733 },1626 },
1734 State.PointerIndexPayload => |opt_ctx| {1627 State.PointerIndexPayload => |opt_ctx| {
...@@ -1737,76 +1630,69 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1737,76 +1630,69 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1737 const token_ptr = token.ptr;1630 const token_ptr = token.ptr;
1738 if (token_ptr.id != Token.Id.Pipe) {1631 if (token_ptr.id != Token.Id.Pipe) {
1739 if (opt_ctx != OptionalCtx.Optional) {1632 if (opt_ctx != OptionalCtx.Optional) {
1740 *(try tree.errors.addOne()) = Error {1633 ((try tree.errors.addOne())).* = Error{ .ExpectedToken = Error.ExpectedToken{
1741 .ExpectedToken = Error.ExpectedToken {1634 .token = token_index,
1742 .token = token_index,1635 .expected_id = Token.Id.Pipe,
1743 .expected_id = Token.Id.Pipe,1636 } };
1744 },
1745 };
1746 return tree;1637 return tree;
1747 }1638 }
17481639
1749 putBackToken(&tok_it, &tree);1640 prevToken(&tok_it, &tree);
1750 continue;1641 continue;
1751 }1642 }
17521643
1753 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,1644 const node = try arena.construct(ast.Node.PointerIndexPayload{
1754 ast.Node.PointerIndexPayload {1645 .base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload },
1755 .base = undefined,1646 .lpipe = token_index,
1756 .lpipe = token_index,1647 .ptr_token = null,
1757 .ptr_token = null,1648 .value_symbol = undefined,
1758 .value_symbol = undefined,1649 .index_symbol = null,
1759 .index_symbol = null,1650 .rpipe = undefined,
1760 .rpipe = undefined
1761 }
1762 );
1763
1764 stack.append(State {
1765 .ExpectTokenSave = ExpectTokenSave {
1766 .id = Token.Id.Pipe,
1767 .ptr = &node.rpipe,
1768 }
1769 }) catch unreachable;
1770 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1771 try stack.append(State { .IfToken = Token.Id.Comma });
1772 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1773 try stack.append(State {
1774 .OptionalTokenSave = OptionalTokenSave {
1775 .id = Token.Id.Asterisk,
1776 .ptr = &node.ptr_token,
1777 }
1778 });1651 });
1652 opt_ctx.store(&node.base);
1653
1654 stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1655 .id = Token.Id.Pipe,
1656 .ptr = &node.rpipe,
1657 } }) catch unreachable;
1658 try stack.append(State{ .Identifier = OptionalCtx{ .RequiredNull = &node.index_symbol } });
1659 try stack.append(State{ .IfToken = Token.Id.Comma });
1660 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.value_symbol } });
1661 try stack.append(State{ .OptionalTokenSave = OptionalTokenSave{
1662 .id = Token.Id.Asterisk,
1663 .ptr = &node.ptr_token,
1664 } });
1779 continue;1665 continue;
1780 },1666 },
17811667
1782
1783 State.Expression => |opt_ctx| {1668 State.Expression => |opt_ctx| {
1784 const token = nextToken(&tok_it, &tree);1669 const token = nextToken(&tok_it, &tree);
1785 const token_index = token.index;1670 const token_index = token.index;
1786 const token_ptr = token.ptr;1671 const token_ptr = token.ptr;
1787 switch (token_ptr.id) {1672 switch (token_ptr.id) {
1788 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {1673 Token.Id.Keyword_return,
1789 const node = try createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,1674 Token.Id.Keyword_break,
1790 ast.Node.ControlFlowExpression {1675 Token.Id.Keyword_continue => {
1791 .base = undefined,1676 const node = try arena.construct(ast.Node.ControlFlowExpression{
1792 .ltoken = token_index,1677 .base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression },
1793 .kind = undefined,1678 .ltoken = token_index,
1794 .rhs = null,1679 .kind = undefined,
1795 }1680 .rhs = null,
1796 );1681 });
1682 opt_ctx.store(&node.base);
17971683
1798 stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;1684 stack.append(State{ .Expression = OptionalCtx{ .Optional = &node.rhs } }) catch unreachable;
17991685
1800 switch (token_ptr.id) {1686 switch (token_ptr.id) {
1801 Token.Id.Keyword_break => {1687 Token.Id.Keyword_break => {
1802 node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };1688 node.kind = ast.Node.ControlFlowExpression.Kind{ .Break = null };
1803 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });1689 try stack.append(State{ .Identifier = OptionalCtx{ .RequiredNull = &node.kind.Break } });
1804 try stack.append(State { .IfToken = Token.Id.Colon });1690 try stack.append(State{ .IfToken = Token.Id.Colon });
1805 },1691 },
1806 Token.Id.Keyword_continue => {1692 Token.Id.Keyword_continue => {
1807 node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };1693 node.kind = ast.Node.ControlFlowExpression.Kind{ .Continue = null };
1808 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });1694 try stack.append(State{ .Identifier = OptionalCtx{ .RequiredNull = &node.kind.Continue } });
1809 try stack.append(State { .IfToken = Token.Id.Colon });1695 try stack.append(State{ .IfToken = Token.Id.Colon });
1810 },1696 },
1811 Token.Id.Keyword_return => {1697 Token.Id.Keyword_return => {
1812 node.kind = ast.Node.ControlFlowExpression.Kind.Return;1698 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
...@@ -1815,58 +1701,58 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1815,58 +1701,58 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1815 }1701 }
1816 continue;1702 continue;
1817 },1703 },
1818 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {1704 Token.Id.Keyword_try,
1819 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,1705 Token.Id.Keyword_cancel,
1820 ast.Node.PrefixOp {1706 Token.Id.Keyword_resume => {
1821 .base = undefined,1707 const node = try arena.construct(ast.Node.PrefixOp{
1822 .op_token = token_index,1708 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
1823 .op = switch (token_ptr.id) {1709 .op_token = token_index,
1824 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },1710 .op = switch (token_ptr.id) {
1825 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },1711 Token.Id.Keyword_try => ast.Node.PrefixOp.Op{ .Try = void{} },
1826 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },1712 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op{ .Cancel = void{} },
1827 else => unreachable,1713 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op{ .Resume = void{} },
1828 },1714 else => unreachable,
1829 .rhs = undefined,1715 },
1830 }1716 .rhs = undefined,
1831 );1717 });
1718 opt_ctx.store(&node.base);
18321719
1833 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;1720 stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
1834 continue;1721 continue;
1835 },1722 },
1836 else => {1723 else => {
1837 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {1724 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
1838 putBackToken(&tok_it, &tree);1725 prevToken(&tok_it, &tree);
1839 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;1726 stack.append(State{ .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1840 }1727 }
1841 continue;1728 continue;
1842 }1729 },
1843 }1730 }
1844 },1731 },
1845 State.RangeExpressionBegin => |opt_ctx| {1732 State.RangeExpressionBegin => |opt_ctx| {
1846 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;1733 stack.append(State{ .RangeExpressionEnd = opt_ctx }) catch unreachable;
1847 try stack.append(State { .Expression = opt_ctx });1734 try stack.append(State{ .Expression = opt_ctx });
1848 continue;1735 continue;
1849 },1736 },
1850 State.RangeExpressionEnd => |opt_ctx| {1737 State.RangeExpressionEnd => |opt_ctx| {
1851 const lhs = opt_ctx.get() ?? continue;1738 const lhs = opt_ctx.get() ?? continue;
18521739
1853 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {1740 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
1854 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,1741 const node = try arena.construct(ast.Node.InfixOp{
1855 ast.Node.InfixOp {1742 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1856 .base = undefined,1743 .lhs = lhs,
1857 .lhs = lhs,1744 .op_token = ellipsis3,
1858 .op_token = ellipsis3,1745 .op = ast.Node.InfixOp.Op.Range,
1859 .op = ast.Node.InfixOp.Op.Range,1746 .rhs = undefined,
1860 .rhs = undefined,1747 });
1861 }1748 opt_ctx.store(&node.base);
1862 );1749 stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
1863 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1864 continue;1750 continue;
1865 }1751 }
1866 },1752 },
1867 State.AssignmentExpressionBegin => |opt_ctx| {1753 State.AssignmentExpressionBegin => |opt_ctx| {
1868 stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;1754 stack.append(State{ .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
1869 try stack.append(State { .Expression = opt_ctx });1755 try stack.append(State{ .Expression = opt_ctx });
1870 continue;1756 continue;
1871 },1757 },
18721758
...@@ -1877,27 +1763,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1877,27 +1763,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1877 const token_index = token.index;1763 const token_index = token.index;
1878 const token_ptr = token.ptr;1764 const token_ptr = token.ptr;
1879 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {1765 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {
1880 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,1766 const node = try arena.construct(ast.Node.InfixOp{
1881 ast.Node.InfixOp {1767 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1882 .base = undefined,1768 .lhs = lhs,
1883 .lhs = lhs,1769 .op_token = token_index,
1884 .op_token = token_index,1770 .op = ass_id,
1885 .op = ass_id,1771 .rhs = undefined,
1886 .rhs = undefined,1772 });
1887 }1773 opt_ctx.store(&node.base);
1888 );1774 stack.append(State{ .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1889 stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;1775 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } });
1890 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1891 continue;1776 continue;
1892 } else {1777 } else {
1893 putBackToken(&tok_it, &tree);1778 prevToken(&tok_it, &tree);
1894 continue;1779 continue;
1895 }1780 }
1896 },1781 },
18971782
1898 State.UnwrapExpressionBegin => |opt_ctx| {1783 State.UnwrapExpressionBegin => |opt_ctx| {
1899 stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;1784 stack.append(State{ .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1900 try stack.append(State { .BoolOrExpressionBegin = opt_ctx });1785 try stack.append(State{ .BoolOrExpressionBegin = opt_ctx });
1901 continue;1786 continue;
1902 },1787 },
19031788
...@@ -1908,32 +1793,31 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1908,32 +1793,31 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1908 const token_index = token.index;1793 const token_index = token.index;
1909 const token_ptr = token.ptr;1794 const token_ptr = token.ptr;
1910 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {1795 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {
1911 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,1796 const node = try arena.construct(ast.Node.InfixOp{
1912 ast.Node.InfixOp {1797 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1913 .base = undefined,1798 .lhs = lhs,
1914 .lhs = lhs,1799 .op_token = token_index,
1915 .op_token = token_index,1800 .op = unwrap_id,
1916 .op = unwrap_id,1801 .rhs = undefined,
1917 .rhs = undefined,1802 });
1918 }1803 opt_ctx.store(&node.base);
1919 );
19201804
1921 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;1805 stack.append(State{ .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1922 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });1806 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } });
19231807
1924 if (node.op == ast.Node.InfixOp.Op.Catch) {1808 if (node.op == ast.Node.InfixOp.Op.Catch) {
1925 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });1809 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.op.Catch } });
1926 }1810 }
1927 continue;1811 continue;
1928 } else {1812 } else {
1929 putBackToken(&tok_it, &tree);1813 prevToken(&tok_it, &tree);
1930 continue;1814 continue;
1931 }1815 }
1932 },1816 },
19331817
1934 State.BoolOrExpressionBegin => |opt_ctx| {1818 State.BoolOrExpressionBegin => |opt_ctx| {
1935 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;1819 stack.append(State{ .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1936 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });1820 try stack.append(State{ .BoolAndExpressionBegin = opt_ctx });
1937 continue;1821 continue;
1938 },1822 },
19391823
...@@ -1941,24 +1825,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1941,24 +1825,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1941 const lhs = opt_ctx.get() ?? continue;1825 const lhs = opt_ctx.get() ?? continue;
19421826
1943 if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {1827 if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {
1944 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,1828 const node = try arena.construct(ast.Node.InfixOp{
1945 ast.Node.InfixOp {1829 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1946 .base = undefined,1830 .lhs = lhs,
1947 .lhs = lhs,1831 .op_token = or_token,
1948 .op_token = or_token,1832 .op = ast.Node.InfixOp.Op.BoolOr,
1949 .op = ast.Node.InfixOp.Op.BoolOr,1833 .rhs = undefined,
1950 .rhs = undefined,1834 });
1951 }1835 opt_ctx.store(&node.base);
1952 );1836 stack.append(State{ .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1953 stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;1837 try stack.append(State{ .BoolAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
1954 try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1955 continue;1838 continue;
1956 }1839 }
1957 },1840 },
19581841
1959 State.BoolAndExpressionBegin => |opt_ctx| {1842 State.BoolAndExpressionBegin => |opt_ctx| {
1960 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;1843 stack.append(State{ .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1961 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });1844 try stack.append(State{ .ComparisonExpressionBegin = opt_ctx });
1962 continue;1845 continue;
1963 },1846 },
19641847
...@@ -1966,24 +1849,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1966,24 +1849,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1966 const lhs = opt_ctx.get() ?? continue;1849 const lhs = opt_ctx.get() ?? continue;
19671850
1968 if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {1851 if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {
1969 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,1852 const node = try arena.construct(ast.Node.InfixOp{
1970 ast.Node.InfixOp {1853 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1971 .base = undefined,1854 .lhs = lhs,
1972 .lhs = lhs,1855 .op_token = and_token,
1973 .op_token = and_token,1856 .op = ast.Node.InfixOp.Op.BoolAnd,
1974 .op = ast.Node.InfixOp.Op.BoolAnd,1857 .rhs = undefined,
1975 .rhs = undefined,1858 });
1976 }1859 opt_ctx.store(&node.base);
1977 );1860 stack.append(State{ .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1978 stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;1861 try stack.append(State{ .ComparisonExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
1979 try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1980 continue;1862 continue;
1981 }1863 }
1982 },1864 },
19831865
1984 State.ComparisonExpressionBegin => |opt_ctx| {1866 State.ComparisonExpressionBegin => |opt_ctx| {
1985 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;1867 stack.append(State{ .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
1986 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });1868 try stack.append(State{ .BinaryOrExpressionBegin = opt_ctx });
1987 continue;1869 continue;
1988 },1870 },
19891871
...@@ -1994,27 +1876,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1994,27 +1876,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1994 const token_index = token.index;1876 const token_index = token.index;
1995 const token_ptr = token.ptr;1877 const token_ptr = token.ptr;
1996 if (tokenIdToComparison(token_ptr.id)) |comp_id| {1878 if (tokenIdToComparison(token_ptr.id)) |comp_id| {
1997 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,1879 const node = try arena.construct(ast.Node.InfixOp{
1998 ast.Node.InfixOp {1880 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1999 .base = undefined,1881 .lhs = lhs,
2000 .lhs = lhs,1882 .op_token = token_index,
2001 .op_token = token_index,1883 .op = comp_id,
2002 .op = comp_id,1884 .rhs = undefined,
2003 .rhs = undefined,1885 });
2004 }1886 opt_ctx.store(&node.base);
2005 );1887 stack.append(State{ .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2006 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;1888 try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2007 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2008 continue;1889 continue;
2009 } else {1890 } else {
2010 putBackToken(&tok_it, &tree);1891 prevToken(&tok_it, &tree);
2011 continue;1892 continue;
2012 }1893 }
2013 },1894 },
20141895
2015 State.BinaryOrExpressionBegin => |opt_ctx| {1896 State.BinaryOrExpressionBegin => |opt_ctx| {
2016 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;1897 stack.append(State{ .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2017 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });1898 try stack.append(State{ .BinaryXorExpressionBegin = opt_ctx });
2018 continue;1899 continue;
2019 },1900 },
20201901
...@@ -2022,24 +1903,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2022,24 +1903,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2022 const lhs = opt_ctx.get() ?? continue;1903 const lhs = opt_ctx.get() ?? continue;
20231904
2024 if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {1905 if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {
2025 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,1906 const node = try arena.construct(ast.Node.InfixOp{
2026 ast.Node.InfixOp {1907 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2027 .base = undefined,1908 .lhs = lhs,
2028 .lhs = lhs,1909 .op_token = pipe,
2029 .op_token = pipe,1910 .op = ast.Node.InfixOp.Op.BitOr,
2030 .op = ast.Node.InfixOp.Op.BitOr,1911 .rhs = undefined,
2031 .rhs = undefined,1912 });
2032 }1913 opt_ctx.store(&node.base);
2033 );1914 stack.append(State{ .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2034 stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;1915 try stack.append(State{ .BinaryXorExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2035 try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2036 continue;1916 continue;
2037 }1917 }
2038 },1918 },
20391919
2040 State.BinaryXorExpressionBegin => |opt_ctx| {1920 State.BinaryXorExpressionBegin => |opt_ctx| {
2041 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;1921 stack.append(State{ .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2042 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });1922 try stack.append(State{ .BinaryAndExpressionBegin = opt_ctx });
2043 continue;1923 continue;
2044 },1924 },
20451925
...@@ -2047,24 +1927,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2047,24 +1927,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2047 const lhs = opt_ctx.get() ?? continue;1927 const lhs = opt_ctx.get() ?? continue;
20481928
2049 if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {1929 if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {
2050 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,1930 const node = try arena.construct(ast.Node.InfixOp{
2051 ast.Node.InfixOp {1931 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2052 .base = undefined,1932 .lhs = lhs,
2053 .lhs = lhs,1933 .op_token = caret,
2054 .op_token = caret,1934 .op = ast.Node.InfixOp.Op.BitXor,
2055 .op = ast.Node.InfixOp.Op.BitXor,1935 .rhs = undefined,
2056 .rhs = undefined,1936 });
2057 }1937 opt_ctx.store(&node.base);
2058 );1938 stack.append(State{ .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2059 stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;1939 try stack.append(State{ .BinaryAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2060 try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2061 continue;1940 continue;
2062 }1941 }
2063 },1942 },
20641943
2065 State.BinaryAndExpressionBegin => |opt_ctx| {1944 State.BinaryAndExpressionBegin => |opt_ctx| {
2066 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;1945 stack.append(State{ .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2067 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });1946 try stack.append(State{ .BitShiftExpressionBegin = opt_ctx });
2068 continue;1947 continue;
2069 },1948 },
20701949
...@@ -2072,24 +1951,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2072,24 +1951,23 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2072 const lhs = opt_ctx.get() ?? continue;1951 const lhs = opt_ctx.get() ?? continue;
20731952
2074 if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {1953 if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {
2075 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,1954 const node = try arena.construct(ast.Node.InfixOp{
2076 ast.Node.InfixOp {1955 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2077 .base = undefined,1956 .lhs = lhs,
2078 .lhs = lhs,1957 .op_token = ampersand,
2079 .op_token = ampersand,1958 .op = ast.Node.InfixOp.Op.BitAnd,
2080 .op = ast.Node.InfixOp.Op.BitAnd,1959 .rhs = undefined,
2081 .rhs = undefined,1960 });
2082 }1961 opt_ctx.store(&node.base);
2083 );1962 stack.append(State{ .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2084 stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;1963 try stack.append(State{ .BitShiftExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2085 try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2086 continue;1964 continue;
2087 }1965 }
2088 },1966 },
20891967
2090 State.BitShiftExpressionBegin => |opt_ctx| {1968 State.BitShiftExpressionBegin => |opt_ctx| {
2091 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;1969 stack.append(State{ .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2092 try stack.append(State { .AdditionExpressionBegin = opt_ctx });1970 try stack.append(State{ .AdditionExpressionBegin = opt_ctx });
2093 continue;1971 continue;
2094 },1972 },
20951973
...@@ -2100,27 +1978,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2100,27 +1978,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2100 const token_index = token.index;1978 const token_index = token.index;
2101 const token_ptr = token.ptr;1979 const token_ptr = token.ptr;
2102 if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {1980 if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {
2103 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,1981 const node = try arena.construct(ast.Node.InfixOp{
2104 ast.Node.InfixOp {1982 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2105 .base = undefined,1983 .lhs = lhs,
2106 .lhs = lhs,1984 .op_token = token_index,
2107 .op_token = token_index,1985 .op = bitshift_id,
2108 .op = bitshift_id,1986 .rhs = undefined,
2109 .rhs = undefined,1987 });
2110 }1988 opt_ctx.store(&node.base);
2111 );1989 stack.append(State{ .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2112 stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;1990 try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2113 try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2114 continue;1991 continue;
2115 } else {1992 } else {
2116 putBackToken(&tok_it, &tree);1993 prevToken(&tok_it, &tree);
2117 continue;1994 continue;
2118 }1995 }
2119 },1996 },
21201997
2121 State.AdditionExpressionBegin => |opt_ctx| {1998 State.AdditionExpressionBegin => |opt_ctx| {
2122 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;1999 stack.append(State{ .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2123 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });2000 try stack.append(State{ .MultiplyExpressionBegin = opt_ctx });
2124 continue;2001 continue;
2125 },2002 },
21262003
...@@ -2131,27 +2008,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2131,27 +2008,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2131 const token_index = token.index;2008 const token_index = token.index;
2132 const token_ptr = token.ptr;2009 const token_ptr = token.ptr;
2133 if (tokenIdToAddition(token_ptr.id)) |add_id| {2010 if (tokenIdToAddition(token_ptr.id)) |add_id| {
2134 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,2011 const node = try arena.construct(ast.Node.InfixOp{
2135 ast.Node.InfixOp {2012 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2136 .base = undefined,2013 .lhs = lhs,
2137 .lhs = lhs,2014 .op_token = token_index,
2138 .op_token = token_index,2015 .op = add_id,
2139 .op = add_id,2016 .rhs = undefined,
2140 .rhs = undefined,2017 });
2141 }2018 opt_ctx.store(&node.base);
2142 );2019 stack.append(State{ .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2143 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;2020 try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2144 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2145 continue;2021 continue;
2146 } else {2022 } else {
2147 putBackToken(&tok_it, &tree);2023 prevToken(&tok_it, &tree);
2148 continue;2024 continue;
2149 }2025 }
2150 },2026 },
21512027
2152 State.MultiplyExpressionBegin => |opt_ctx| {2028 State.MultiplyExpressionBegin => |opt_ctx| {
2153 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;2029 stack.append(State{ .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2154 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });2030 try stack.append(State{ .CurlySuffixExpressionBegin = opt_ctx });
2155 continue;2031 continue;
2156 },2032 },
21572033
...@@ -2162,28 +2038,27 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2162,28 +2038,27 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2162 const token_index = token.index;2038 const token_index = token.index;
2163 const token_ptr = token.ptr;2039 const token_ptr = token.ptr;
2164 if (tokenIdToMultiply(token_ptr.id)) |mult_id| {2040 if (tokenIdToMultiply(token_ptr.id)) |mult_id| {
2165 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,2041 const node = try arena.construct(ast.Node.InfixOp{
2166 ast.Node.InfixOp {2042 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2167 .base = undefined,2043 .lhs = lhs,
2168 .lhs = lhs,2044 .op_token = token_index,
2169 .op_token = token_index,2045 .op = mult_id,
2170 .op = mult_id,2046 .rhs = undefined,
2171 .rhs = undefined,2047 });
2172 }2048 opt_ctx.store(&node.base);
2173 );2049 stack.append(State{ .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2174 stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;2050 try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2175 try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2176 continue;2051 continue;
2177 } else {2052 } else {
2178 putBackToken(&tok_it, &tree);2053 prevToken(&tok_it, &tree);
2179 continue;2054 continue;
2180 }2055 }
2181 },2056 },
21822057
2183 State.CurlySuffixExpressionBegin => |opt_ctx| {2058 State.CurlySuffixExpressionBegin => |opt_ctx| {
2184 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;2059 stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2185 try stack.append(State { .IfToken = Token.Id.LBrace });2060 try stack.append(State{ .IfToken = Token.Id.LBrace });
2186 try stack.append(State { .TypeExprBegin = opt_ctx });2061 try stack.append(State{ .TypeExprBegin = opt_ctx });
2187 continue;2062 continue;
2188 },2063 },
21892064
...@@ -2191,52 +2066,43 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2191,52 +2066,43 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2191 const lhs = opt_ctx.get() ?? continue;2066 const lhs = opt_ctx.get() ?? continue;
21922067
2193 if ((??tok_it.peek()).id == Token.Id.Period) {2068 if ((??tok_it.peek()).id == Token.Id.Period) {
2194 const node = try arena.construct(ast.Node.SuffixOp {2069 const node = try arena.construct(ast.Node.SuffixOp{
2195 .base = ast.Node { .id = ast.Node.Id.SuffixOp },2070 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2196 .lhs = lhs,2071 .lhs = lhs,
2197 .op = ast.Node.SuffixOp.Op {2072 .op = ast.Node.SuffixOp.Op{ .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },
2198 .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2199 },
2200 .rtoken = undefined,2073 .rtoken = undefined,
2201 });2074 });
2202 opt_ctx.store(&node.base);2075 opt_ctx.store(&node.base);
22032076
2204 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;2077 stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2205 try stack.append(State { .IfToken = Token.Id.LBrace });2078 try stack.append(State{ .IfToken = Token.Id.LBrace });
2206 try stack.append(State {2079 try stack.append(State{ .FieldInitListItemOrEnd = ListSave(@typeOf(node.op.StructInitializer)){
2207 .FieldInitListItemOrEnd = ListSave(@typeOf(node.op.StructInitializer)) {2080 .list = &node.op.StructInitializer,
2208 .list = &node.op.StructInitializer,2081 .ptr = &node.rtoken,
2209 .ptr = &node.rtoken,2082 } });
2210 }
2211 });
2212 continue;2083 continue;
2213 }2084 }
22142085
2215 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,2086 const node = try arena.construct(ast.Node.SuffixOp{
2216 ast.Node.SuffixOp {2087 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2217 .base = undefined,2088 .lhs = lhs,
2218 .lhs = lhs,2089 .op = ast.Node.SuffixOp.Op{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },
2219 .op = ast.Node.SuffixOp.Op {2090 .rtoken = undefined,
2220 .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena),
2221 },
2222 .rtoken = undefined,
2223 }
2224 );
2225 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2226 try stack.append(State { .IfToken = Token.Id.LBrace });
2227 try stack.append(State {
2228 .ExprListItemOrEnd = ExprListCtx {
2229 .list = &node.op.ArrayInitializer,
2230 .end = Token.Id.RBrace,
2231 .ptr = &node.rtoken,
2232 }
2233 });2091 });
2092 opt_ctx.store(&node.base);
2093 stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2094 try stack.append(State{ .IfToken = Token.Id.LBrace });
2095 try stack.append(State{ .ExprListItemOrEnd = ExprListCtx{
2096 .list = &node.op.ArrayInitializer,
2097 .end = Token.Id.RBrace,
2098 .ptr = &node.rtoken,
2099 } });
2234 continue;2100 continue;
2235 },2101 },
22362102
2237 State.TypeExprBegin => |opt_ctx| {2103 State.TypeExprBegin => |opt_ctx| {
2238 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;2104 stack.append(State{ .TypeExprEnd = opt_ctx }) catch unreachable;
2239 try stack.append(State { .PrefixOpExpression = opt_ctx });2105 try stack.append(State{ .PrefixOpExpression = opt_ctx });
2240 continue;2106 continue;
2241 },2107 },
22422108
...@@ -2244,17 +2110,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2244,17 +2110,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2244 const lhs = opt_ctx.get() ?? continue;2110 const lhs = opt_ctx.get() ?? continue;
22452111
2246 if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {2112 if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {
2247 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,2113 const node = try arena.construct(ast.Node.InfixOp{
2248 ast.Node.InfixOp {2114 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2249 .base = undefined,2115 .lhs = lhs,
2250 .lhs = lhs,2116 .op_token = bang,
2251 .op_token = bang,2117 .op = ast.Node.InfixOp.Op.ErrorUnion,
2252 .op = ast.Node.InfixOp.Op.ErrorUnion,2118 .rhs = undefined,
2253 .rhs = undefined,2119 });
2254 }2120 opt_ctx.store(&node.base);
2255 );2121 stack.append(State{ .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2256 stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;2122 try stack.append(State{ .PrefixOpExpression = OptionalCtx{ .Required = &node.rhs } });
2257 try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
2258 continue;2123 continue;
2259 }2124 }
2260 },2125 },
...@@ -2264,65 +2129,58 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2264,65 +2129,58 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2264 const token_index = token.index;2129 const token_index = token.index;
2265 const token_ptr = token.ptr;2130 const token_ptr = token.ptr;
2266 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {2131 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {
2267 var node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,2132 var node = try arena.construct(ast.Node.PrefixOp{
2268 ast.Node.PrefixOp {2133 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2269 .base = undefined,2134 .op_token = token_index,
2270 .op_token = token_index,2135 .op = prefix_id,
2271 .op = prefix_id,2136 .rhs = undefined,
2272 .rhs = undefined,2137 });
2273 }2138 opt_ctx.store(&node.base);
2274 );
22752139
2276 // Treat '**' token as two derefs2140 // Treat '**' token as two derefs
2277 if (token_ptr.id == Token.Id.AsteriskAsterisk) {2141 if (token_ptr.id == Token.Id.AsteriskAsterisk) {
2278 const child = try createNode(arena, ast.Node.PrefixOp,2142 const child = try arena.construct(ast.Node.PrefixOp{
2279 ast.Node.PrefixOp {2143 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2280 .base = undefined,2144 .op_token = token_index,
2281 .op_token = token_index,2145 .op = prefix_id,
2282 .op = prefix_id,2146 .rhs = undefined,
2283 .rhs = undefined,2147 });
2284 }
2285 );
2286 node.rhs = &child.base;2148 node.rhs = &child.base;
2287 node = child;2149 node = child;
2288 }2150 }
22892151
2290 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;2152 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
2291 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {2153 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
2292 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });2154 try stack.append(State{ .AddrOfModifiers = &node.op.AddrOf });
2293 }2155 }
2294 continue;2156 continue;
2295 } else {2157 } else {
2296 putBackToken(&tok_it, &tree);2158 prevToken(&tok_it, &tree);
2297 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;2159 stack.append(State{ .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2298 continue;2160 continue;
2299 }2161 }
2300 },2162 },
23012163
2302 State.SuffixOpExpressionBegin => |opt_ctx| {2164 State.SuffixOpExpressionBegin => |opt_ctx| {
2303 if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| {2165 if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| {
2304 const async_node = try createNode(arena, ast.Node.AsyncAttribute,2166 const async_node = try arena.construct(ast.Node.AsyncAttribute{
2305 ast.Node.AsyncAttribute {2167 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
2306 .base = undefined,2168 .async_token = async_token,
2307 .async_token = async_token,2169 .allocator_type = null,
2308 .allocator_type = null,2170 .rangle_bracket = null,
2309 .rangle_bracket = null,2171 });
2310 }2172 stack.append(State{ .AsyncEnd = AsyncEndCtx{
2311 );2173 .ctx = opt_ctx,
2312 stack.append(State {2174 .attribute = async_node,
2313 .AsyncEnd = AsyncEndCtx {2175 } }) catch unreachable;
2314 .ctx = opt_ctx,2176 try stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2315 .attribute = async_node,2177 try stack.append(State{ .PrimaryExpression = opt_ctx.toRequired() });
2316 }2178 try stack.append(State{ .AsyncAllocator = async_node });
2317 }) catch unreachable;
2318 try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2319 try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
2320 try stack.append(State { .AsyncAllocator = async_node });
2321 continue;2179 continue;
2322 }2180 }
23232181
2324 stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;2182 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2325 try stack.append(State { .PrimaryExpression = opt_ctx });2183 try stack.append(State{ .PrimaryExpression = opt_ctx });
2326 continue;2184 continue;
2327 },2185 },
23282186
...@@ -2334,61 +2192,66 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2334,61 +2192,66 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2334 const token_ptr = token.ptr;2192 const token_ptr = token.ptr;
2335 switch (token_ptr.id) {2193 switch (token_ptr.id) {
2336 Token.Id.LParen => {2194 Token.Id.LParen => {
2337 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,2195 const node = try arena.construct(ast.Node.SuffixOp{
2338 ast.Node.SuffixOp {2196 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2339 .base = undefined,2197 .lhs = lhs,
2340 .lhs = lhs,2198 .op = ast.Node.SuffixOp.Op{ .Call = ast.Node.SuffixOp.Op.Call{
2341 .op = ast.Node.SuffixOp.Op {2199 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena),
2342 .Call = ast.Node.SuffixOp.Op.Call {2200 .async_attr = null,
2343 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena),2201 } },
2344 .async_attr = null,2202 .rtoken = undefined,
2345 }
2346 },
2347 .rtoken = undefined,
2348 }
2349 );
2350 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2351 try stack.append(State {
2352 .ExprListItemOrEnd = ExprListCtx {
2353 .list = &node.op.Call.params,
2354 .end = Token.Id.RParen,
2355 .ptr = &node.rtoken,
2356 }
2357 });2203 });
2204 opt_ctx.store(&node.base);
2205
2206 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2207 try stack.append(State{ .ExprListItemOrEnd = ExprListCtx{
2208 .list = &node.op.Call.params,
2209 .end = Token.Id.RParen,
2210 .ptr = &node.rtoken,
2211 } });
2358 continue;2212 continue;
2359 },2213 },
2360 Token.Id.LBracket => {2214 Token.Id.LBracket => {
2361 const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,2215 const node = try arena.construct(ast.Node.SuffixOp{
2362 ast.Node.SuffixOp {2216 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2363 .base = undefined,2217 .lhs = lhs,
2364 .lhs = lhs,2218 .op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined },
2365 .op = ast.Node.SuffixOp.Op {2219 .rtoken = undefined,
2366 .ArrayAccess = undefined,2220 });
2367 },2221 opt_ctx.store(&node.base);
2368 .rtoken = undefined2222
2369 }2223 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2370 );2224 try stack.append(State{ .SliceOrArrayAccess = node });
2371 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;2225 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.op.ArrayAccess } });
2372 try stack.append(State { .SliceOrArrayAccess = node });
2373 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
2374 continue;2226 continue;
2375 },2227 },
2376 Token.Id.Period => {2228 Token.Id.Period => {
2377 const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,2229 if (eatToken(&tok_it, &tree, Token.Id.Asterisk)) |asterisk_token| {
2378 ast.Node.InfixOp {2230 const node = try arena.construct(ast.Node.SuffixOp{
2379 .base = undefined,2231 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2380 .lhs = lhs,2232 .lhs = lhs,
2381 .op_token = token_index,2233 .op = ast.Node.SuffixOp.Op.Deref,
2382 .op = ast.Node.InfixOp.Op.Period,2234 .rtoken = asterisk_token,
2383 .rhs = undefined,2235 });
2384 }2236 opt_ctx.store(&node.base);
2385 );2237 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2386 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;2238 continue;
2387 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });2239 }
2240 const node = try arena.construct(ast.Node.InfixOp{
2241 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2242 .lhs = lhs,
2243 .op_token = token_index,
2244 .op = ast.Node.InfixOp.Op.Period,
2245 .rhs = undefined,
2246 });
2247 opt_ctx.store(&node.base);
2248
2249 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2250 try stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.rhs } });
2388 continue;2251 continue;
2389 },2252 },
2390 else => {2253 else => {
2391 putBackToken(&tok_it, &tree);2254 prevToken(&tok_it, &tree);
2392 continue;2255 continue;
2393 },2256 },
2394 }2257 }
...@@ -2413,7 +2276,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2413,7 +2276,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2413 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token.index);2276 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token.index);
2414 continue;2277 continue;
2415 },2278 },
2416 Token.Id.Keyword_true, Token.Id.Keyword_false => {2279 Token.Id.Keyword_true,
2280 Token.Id.Keyword_false => {
2417 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token.index);2281 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token.index);
2418 continue;2282 continue;
2419 },2283 },
...@@ -2434,10 +2298,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2434,10 +2298,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2434 continue;2298 continue;
2435 },2299 },
2436 Token.Id.Keyword_promise => {2300 Token.Id.Keyword_promise => {
2437 const node = try arena.construct(ast.Node.PromiseType {2301 const node = try arena.construct(ast.Node.PromiseType{
2438 .base = ast.Node {2302 .base = ast.Node{ .id = ast.Node.Id.PromiseType },
2439 .id = ast.Node.Id.PromiseType,
2440 },
2441 .promise_token = token.index,2303 .promise_token = token.index,
2442 .result = null,2304 .result = null,
2443 });2305 });
...@@ -2446,124 +2308,109 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2446,124 +2308,109 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2446 const next_token_index = next_token.index;2308 const next_token_index = next_token.index;
2447 const next_token_ptr = next_token.ptr;2309 const next_token_ptr = next_token.ptr;
2448 if (next_token_ptr.id != Token.Id.Arrow) {2310 if (next_token_ptr.id != Token.Id.Arrow) {
2449 putBackToken(&tok_it, &tree);2311 prevToken(&tok_it, &tree);
2450 continue;2312 continue;
2451 }2313 }
2452 node.result = ast.Node.PromiseType.Result {2314 node.result = ast.Node.PromiseType.Result{
2453 .arrow_token = next_token_index,2315 .arrow_token = next_token_index,
2454 .return_type = undefined,2316 .return_type = undefined,
2455 };2317 };
2456 const return_type_ptr = &((??node.result).return_type);2318 const return_type_ptr = &((??node.result).return_type);
2457 try stack.append(State { .Expression = OptionalCtx { .Required = return_type_ptr, } });2319 try stack.append(State{ .Expression = OptionalCtx{ .Required = return_type_ptr } });
2458 continue;2320 continue;
2459 },2321 },
2460 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {2322 Token.Id.StringLiteral,
2323 Token.Id.MultilineStringLiteralLine => {
2461 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) ?? unreachable);2324 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token.ptr, token.index, &tree)) ?? unreachable);
2462 continue;2325 continue;
2463 },2326 },
2464 Token.Id.LParen => {2327 Token.Id.LParen => {
2465 const node = try createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,2328 const node = try arena.construct(ast.Node.GroupedExpression{
2466 ast.Node.GroupedExpression {2329 .base = ast.Node{ .id = ast.Node.Id.GroupedExpression },
2467 .base = undefined,2330 .lparen = token.index,
2468 .lparen = token.index,2331 .expr = undefined,
2469 .expr = undefined,2332 .rparen = undefined,
2470 .rparen = undefined,2333 });
2471 }2334 opt_ctx.store(&node.base);
2472 );2335
2473 stack.append(State {2336 stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
2474 .ExpectTokenSave = ExpectTokenSave {2337 .id = Token.Id.RParen,
2475 .id = Token.Id.RParen,2338 .ptr = &node.rparen,
2476 .ptr = &node.rparen,2339 } }) catch unreachable;
2477 }2340 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
2478 }) catch unreachable;
2479 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2480 continue;2341 continue;
2481 },2342 },
2482 Token.Id.Builtin => {2343 Token.Id.Builtin => {
2483 const node = try createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,2344 const node = try arena.construct(ast.Node.BuiltinCall{
2484 ast.Node.BuiltinCall {2345 .base = ast.Node{ .id = ast.Node.Id.BuiltinCall },
2485 .base = undefined,2346 .builtin_token = token.index,
2486 .builtin_token = token.index,2347 .params = ast.Node.BuiltinCall.ParamList.init(arena),
2487 .params = ast.Node.BuiltinCall.ParamList.init(arena),2348 .rparen_token = undefined,
2488 .rparen_token = undefined,2349 });
2489 }2350 opt_ctx.store(&node.base);
2490 );2351
2491 stack.append(State {2352 stack.append(State{ .ExprListItemOrEnd = ExprListCtx{
2492 .ExprListItemOrEnd = ExprListCtx {2353 .list = &node.params,
2493 .list = &node.params,2354 .end = Token.Id.RParen,
2494 .end = Token.Id.RParen,2355 .ptr = &node.rparen_token,
2495 .ptr = &node.rparen_token,2356 } }) catch unreachable;
2496 }2357 try stack.append(State{ .ExpectToken = Token.Id.LParen });
2497 }) catch unreachable;
2498 try stack.append(State { .ExpectToken = Token.Id.LParen, });
2499 continue;2358 continue;
2500 },2359 },
2501 Token.Id.LBracket => {2360 Token.Id.LBracket => {
2502 const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,2361 const node = try arena.construct(ast.Node.PrefixOp{
2503 ast.Node.PrefixOp {2362 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2504 .base = undefined,2363 .op_token = token.index,
2505 .op_token = token.index,2364 .op = undefined,
2506 .op = undefined,2365 .rhs = undefined,
2507 .rhs = undefined,2366 });
2508 }2367 opt_ctx.store(&node.base);
2509 );2368
2510 stack.append(State { .SliceOrArrayType = node }) catch unreachable;2369 stack.append(State{ .SliceOrArrayType = node }) catch unreachable;
2511 continue;2370 continue;
2512 },2371 },
2513 Token.Id.Keyword_error => {2372 Token.Id.Keyword_error => {
2514 stack.append(State {2373 stack.append(State{ .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx{
2515 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {2374 .error_token = token.index,
2516 .error_token = token.index,2375 .opt_ctx = opt_ctx,
2517 .opt_ctx = opt_ctx2376 } }) catch unreachable;
2518 }
2519 }) catch unreachable;
2520 continue;2377 continue;
2521 },2378 },
2522 Token.Id.Keyword_packed => {2379 Token.Id.Keyword_packed => {
2523 stack.append(State {2380 stack.append(State{ .ContainerKind = ContainerKindCtx{
2524 .ContainerKind = ContainerKindCtx {2381 .opt_ctx = opt_ctx,
2525 .opt_ctx = opt_ctx,2382 .layout_token = token.index,
2526 .ltoken = token.index,2383 } }) catch unreachable;
2527 .layout = ast.Node.ContainerDecl.Layout.Packed,
2528 },
2529 }) catch unreachable;
2530 continue;2384 continue;
2531 },2385 },
2532 Token.Id.Keyword_extern => {2386 Token.Id.Keyword_extern => {
2533 stack.append(State {2387 stack.append(State{ .ExternType = ExternTypeCtx{
2534 .ExternType = ExternTypeCtx {2388 .opt_ctx = opt_ctx,
2535 .opt_ctx = opt_ctx,2389 .extern_token = token.index,
2536 .extern_token = token.index,2390 .comments = null,
2537 .comments = null,2391 } }) catch unreachable;
2538 },
2539 }) catch unreachable;
2540 continue;2392 continue;
2541 },2393 },
2542 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {2394 Token.Id.Keyword_struct,
2543 putBackToken(&tok_it, &tree);2395 Token.Id.Keyword_union,
2544 stack.append(State {2396 Token.Id.Keyword_enum => {
2545 .ContainerKind = ContainerKindCtx {2397 prevToken(&tok_it, &tree);
2546 .opt_ctx = opt_ctx,2398 stack.append(State{ .ContainerKind = ContainerKindCtx{
2547 .ltoken = token.index,2399 .opt_ctx = opt_ctx,
2548 .layout = ast.Node.ContainerDecl.Layout.Auto,2400 .layout_token = null,
2549 },2401 } }) catch unreachable;
2550 }) catch unreachable;
2551 continue;2402 continue;
2552 },2403 },
2553 Token.Id.Identifier => {2404 Token.Id.Identifier => {
2554 stack.append(State {2405 stack.append(State{ .MaybeLabeledExpression = MaybeLabeledExpressionCtx{
2555 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {2406 .label = token.index,
2556 .label = token.index,2407 .opt_ctx = opt_ctx,
2557 .opt_ctx = opt_ctx2408 } }) catch unreachable;
2558 }
2559 }) catch unreachable;
2560 continue;2409 continue;
2561 },2410 },
2562 Token.Id.Keyword_fn => {2411 Token.Id.Keyword_fn => {
2563 const fn_proto = try arena.construct(ast.Node.FnProto {2412 const fn_proto = try arena.construct(ast.Node.FnProto{
2564 .base = ast.Node {2413 .base = ast.Node{ .id = ast.Node.Id.FnProto },
2565 .id = ast.Node.Id.FnProto,
2566 },
2567 .doc_comments = null,2414 .doc_comments = null,
2568 .visib_token = null,2415 .visib_token = null,
2569 .name_token = null,2416 .name_token = null,
...@@ -2579,14 +2426,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2579,14 +2426,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2579 .align_expr = null,2426 .align_expr = null,
2580 });2427 });
2581 opt_ctx.store(&fn_proto.base);2428 opt_ctx.store(&fn_proto.base);
2582 stack.append(State { .FnProto = fn_proto }) catch unreachable;2429 stack.append(State{ .FnProto = fn_proto }) catch unreachable;
2583 continue;2430 continue;
2584 },2431 },
2585 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {2432 Token.Id.Keyword_nakedcc,
2586 const fn_proto = try arena.construct(ast.Node.FnProto {2433 Token.Id.Keyword_stdcallcc => {
2587 .base = ast.Node {2434 const fn_proto = try arena.construct(ast.Node.FnProto{
2588 .id = ast.Node.Id.FnProto,2435 .base = ast.Node{ .id = ast.Node.Id.FnProto },
2589 },
2590 .doc_comments = null,2436 .doc_comments = null,
2591 .visib_token = null,2437 .visib_token = null,
2592 .name_token = null,2438 .name_token = null,
...@@ -2602,116 +2448,97 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2602,116 +2448,97 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2602 .align_expr = null,2448 .align_expr = null,
2603 });2449 });
2604 opt_ctx.store(&fn_proto.base);2450 opt_ctx.store(&fn_proto.base);
2605 stack.append(State { .FnProto = fn_proto }) catch unreachable;2451 stack.append(State{ .FnProto = fn_proto }) catch unreachable;
2606 try stack.append(State {2452 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
2607 .ExpectTokenSave = ExpectTokenSave {2453 .id = Token.Id.Keyword_fn,
2608 .id = Token.Id.Keyword_fn,2454 .ptr = &fn_proto.fn_token,
2609 .ptr = &fn_proto.fn_token2455 } });
2610 }
2611 });
2612 continue;2456 continue;
2613 },2457 },
2614 Token.Id.Keyword_asm => {2458 Token.Id.Keyword_asm => {
2615 const node = try createToCtxNode(arena, opt_ctx, ast.Node.Asm,2459 const node = try arena.construct(ast.Node.Asm{
2616 ast.Node.Asm {2460 .base = ast.Node{ .id = ast.Node.Id.Asm },
2617 .base = undefined,2461 .asm_token = token.index,
2618 .asm_token = token.index,2462 .volatile_token = null,
2619 .volatile_token = null,2463 .template = undefined,
2620 .template = undefined,2464 .outputs = ast.Node.Asm.OutputList.init(arena),
2621 .outputs = ast.Node.Asm.OutputList.init(arena),2465 .inputs = ast.Node.Asm.InputList.init(arena),
2622 .inputs = ast.Node.Asm.InputList.init(arena),2466 .clobbers = ast.Node.Asm.ClobberList.init(arena),
2623 .clobbers = ast.Node.Asm.ClobberList.init(arena),2467 .rparen = undefined,
2624 .rparen = undefined,
2625 }
2626 );
2627 stack.append(State {
2628 .ExpectTokenSave = ExpectTokenSave {
2629 .id = Token.Id.RParen,
2630 .ptr = &node.rparen,
2631 }
2632 }) catch unreachable;
2633 try stack.append(State { .AsmClobberItems = &node.clobbers });
2634 try stack.append(State { .IfToken = Token.Id.Colon });
2635 try stack.append(State { .AsmInputItems = &node.inputs });
2636 try stack.append(State { .IfToken = Token.Id.Colon });
2637 try stack.append(State { .AsmOutputItems = &node.outputs });
2638 try stack.append(State { .IfToken = Token.Id.Colon });
2639 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2640 try stack.append(State { .ExpectToken = Token.Id.LParen });
2641 try stack.append(State {
2642 .OptionalTokenSave = OptionalTokenSave {
2643 .id = Token.Id.Keyword_volatile,
2644 .ptr = &node.volatile_token,
2645 }
2646 });2468 });
2469 opt_ctx.store(&node.base);
2470
2471 stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
2472 .id = Token.Id.RParen,
2473 .ptr = &node.rparen,
2474 } }) catch unreachable;
2475 try stack.append(State{ .AsmClobberItems = &node.clobbers });
2476 try stack.append(State{ .IfToken = Token.Id.Colon });
2477 try stack.append(State{ .AsmInputItems = &node.inputs });
2478 try stack.append(State{ .IfToken = Token.Id.Colon });
2479 try stack.append(State{ .AsmOutputItems = &node.outputs });
2480 try stack.append(State{ .IfToken = Token.Id.Colon });
2481 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.template } });
2482 try stack.append(State{ .ExpectToken = Token.Id.LParen });
2483 try stack.append(State{ .OptionalTokenSave = OptionalTokenSave{
2484 .id = Token.Id.Keyword_volatile,
2485 .ptr = &node.volatile_token,
2486 } });
2647 },2487 },
2648 Token.Id.Keyword_inline => {2488 Token.Id.Keyword_inline => {
2649 stack.append(State {2489 stack.append(State{ .Inline = InlineCtx{
2650 .Inline = InlineCtx {2490 .label = null,
2651 .label = null,2491 .inline_token = token.index,
2652 .inline_token = token.index,2492 .opt_ctx = opt_ctx,
2653 .opt_ctx = opt_ctx,2493 } }) catch unreachable;
2654 }
2655 }) catch unreachable;
2656 continue;2494 continue;
2657 },2495 },
2658 else => {2496 else => {
2659 if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr, token.index)) {2497 if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr, token.index)) {
2660 putBackToken(&tok_it, &tree);2498 prevToken(&tok_it, &tree);
2661 if (opt_ctx != OptionalCtx.Optional) {2499 if (opt_ctx != OptionalCtx.Optional) {
2662 *(try tree.errors.addOne()) = Error {2500 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token.index } };
2663 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token.index },
2664 };
2665 return tree;2501 return tree;
2666 }2502 }
2667 }2503 }
2668 continue;2504 continue;
2669 }2505 },
2670 }2506 }
2671 },2507 },
26722508
2673
2674 State.ErrorTypeOrSetDecl => |ctx| {2509 State.ErrorTypeOrSetDecl => |ctx| {
2675 if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) {2510 if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) {
2676 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);2511 _ = try createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2677 continue;2512 continue;
2678 }2513 }
26792514
2680 const node = try arena.construct(ast.Node.ErrorSetDecl {2515 const node = try arena.construct(ast.Node.ErrorSetDecl{
2681 .base = ast.Node {2516 .base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl },
2682 .id = ast.Node.Id.ErrorSetDecl,
2683 },
2684 .error_token = ctx.error_token,2517 .error_token = ctx.error_token,
2685 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),2518 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
2686 .rbrace_token = undefined,2519 .rbrace_token = undefined,
2687 });2520 });
2688 ctx.opt_ctx.store(&node.base);2521 ctx.opt_ctx.store(&node.base);
26892522
2690 stack.append(State {2523 stack.append(State{ .ErrorTagListItemOrEnd = ListSave(@typeOf(node.decls)){
2691 .ErrorTagListItemOrEnd = ListSave(@typeOf(node.decls)) {2524 .list = &node.decls,
2692 .list = &node.decls,2525 .ptr = &node.rbrace_token,
2693 .ptr = &node.rbrace_token,2526 } }) catch unreachable;
2694 }
2695 }) catch unreachable;
2696 continue;2527 continue;
2697 },2528 },
2698 State.StringLiteral => |opt_ctx| {2529 State.StringLiteral => |opt_ctx| {
2699 const token = nextToken(&tok_it, &tree);2530 const token = nextToken(&tok_it, &tree);
2700 const token_index = token.index;2531 const token_index = token.index;
2701 const token_ptr = token.ptr;2532 const token_ptr = token.ptr;
2702 opt_ctx.store(2533 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) ?? {
2703 (try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) ?? {2534 prevToken(&tok_it, &tree);
2704 putBackToken(&tok_it, &tree);2535 if (opt_ctx != OptionalCtx.Optional) {
2705 if (opt_ctx != OptionalCtx.Optional) {2536 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token_index } };
2706 *(try tree.errors.addOne()) = Error {2537 return tree;
2707 .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr { .token = token_index },
2708 };
2709 return tree;
2710 }
2711
2712 continue;
2713 }2538 }
2714 );2539
2540 continue;
2541 });
2715 },2542 },
27162543
2717 State.Identifier => |opt_ctx| {2544 State.Identifier => |opt_ctx| {
...@@ -2724,12 +2551,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2724,12 +2551,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2724 const token = nextToken(&tok_it, &tree);2551 const token = nextToken(&tok_it, &tree);
2725 const token_index = token.index;2552 const token_index = token.index;
2726 const token_ptr = token.ptr;2553 const token_ptr = token.ptr;
2727 *(try tree.errors.addOne()) = Error {2554 ((try tree.errors.addOne())).* = Error{ .ExpectedToken = Error.ExpectedToken{
2728 .ExpectedToken = Error.ExpectedToken {2555 .token = token_index,
2729 .token = token_index,2556 .expected_id = Token.Id.Identifier,
2730 .expected_id = Token.Id.Identifier,2557 } };
2731 },
2732 };
2733 return tree;2558 return tree;
2734 }2559 }
2735 },2560 },
...@@ -2740,23 +2565,19 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2740,23 +2565,19 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2740 const ident_token_index = ident_token.index;2565 const ident_token_index = ident_token.index;
2741 const ident_token_ptr = ident_token.ptr;2566 const ident_token_ptr = ident_token.ptr;
2742 if (ident_token_ptr.id != Token.Id.Identifier) {2567 if (ident_token_ptr.id != Token.Id.Identifier) {
2743 *(try tree.errors.addOne()) = Error {2568 ((try tree.errors.addOne())).* = Error{ .ExpectedToken = Error.ExpectedToken{
2744 .ExpectedToken = Error.ExpectedToken {2569 .token = ident_token_index,
2745 .token = ident_token_index,2570 .expected_id = Token.Id.Identifier,
2746 .expected_id = Token.Id.Identifier,2571 } };
2747 },
2748 };
2749 return tree;2572 return tree;
2750 }2573 }
27512574
2752 const node = try arena.construct(ast.Node.ErrorTag {2575 const node = try arena.construct(ast.Node.ErrorTag{
2753 .base = ast.Node {2576 .base = ast.Node{ .id = ast.Node.Id.ErrorTag },
2754 .id = ast.Node.Id.ErrorTag,
2755 },
2756 .doc_comments = comments,2577 .doc_comments = comments,
2757 .name_token = ident_token_index,2578 .name_token = ident_token_index,
2758 });2579 });
2759 *node_ptr = &node.base;2580 node_ptr.* = &node.base;
2760 continue;2581 continue;
2761 },2582 },
27622583
...@@ -2765,12 +2586,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2765,12 +2586,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2765 const token_index = token.index;2586 const token_index = token.index;
2766 const token_ptr = token.ptr;2587 const token_ptr = token.ptr;
2767 if (token_ptr.id != token_id) {2588 if (token_ptr.id != token_id) {
2768 *(try tree.errors.addOne()) = Error {2589 ((try tree.errors.addOne())).* = Error{ .ExpectedToken = Error.ExpectedToken{
2769 .ExpectedToken = Error.ExpectedToken {2590 .token = token_index,
2770 .token = token_index,2591 .expected_id = token_id,
2771 .expected_id = token_id,2592 } };
2772 },
2773 };
2774 return tree;2593 return tree;
2775 }2594 }
2776 continue;2595 continue;
...@@ -2780,15 +2599,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2780,15 +2599,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2780 const token_index = token.index;2599 const token_index = token.index;
2781 const token_ptr = token.ptr;2600 const token_ptr = token.ptr;
2782 if (token_ptr.id != expect_token_save.id) {2601 if (token_ptr.id != expect_token_save.id) {
2783 *(try tree.errors.addOne()) = Error {2602 ((try tree.errors.addOne())).* = Error{ .ExpectedToken = Error.ExpectedToken{
2784 .ExpectedToken = Error.ExpectedToken {2603 .token = token_index,
2785 .token = token_index,2604 .expected_id = expect_token_save.id,
2786 .expected_id = expect_token_save.id,2605 } };
2787 },
2788 };
2789 return tree;2606 return tree;
2790 }2607 }
2791 *expect_token_save.ptr = token_index;2608 expect_token_save.ptr.* = token_index;
2792 continue;2609 continue;
2793 },2610 },
2794 State.IfToken => |token_id| {2611 State.IfToken => |token_id| {
...@@ -2801,7 +2618,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2801,7 +2618,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2801 },2618 },
2802 State.IfTokenSave => |if_token_save| {2619 State.IfTokenSave => |if_token_save| {
2803 if (eatToken(&tok_it, &tree, if_token_save.id)) |token_index| {2620 if (eatToken(&tok_it, &tree, if_token_save.id)) |token_index| {
2804 *if_token_save.ptr = token_index;2621 (if_token_save.ptr).* = token_index;
2805 continue;2622 continue;
2806 }2623 }
28072624
...@@ -2810,7 +2627,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2810,7 +2627,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2810 },2627 },
2811 State.OptionalTokenSave => |optional_token_save| {2628 State.OptionalTokenSave => |optional_token_save| {
2812 if (eatToken(&tok_it, &tree, optional_token_save.id)) |token_index| {2629 if (eatToken(&tok_it, &tree, optional_token_save.id)) |token_index| {
2813 *optional_token_save.ptr = token_index;2630 (optional_token_save.ptr).* = token_index;
2814 continue;2631 continue;
2815 }2632 }
28162633
...@@ -2857,8 +2674,7 @@ const ExternTypeCtx = struct {...@@ -2857,8 +2674,7 @@ const ExternTypeCtx = struct {
28572674
2858const ContainerKindCtx = struct {2675const ContainerKindCtx = struct {
2859 opt_ctx: OptionalCtx,2676 opt_ctx: OptionalCtx,
2860 ltoken: TokenIndex,2677 layout_token: ?TokenIndex,
2861 layout: ast.Node.ContainerDecl.Layout,
2862};2678};
28632679
2864const ExpectTokenSave = struct {2680const ExpectTokenSave = struct {
...@@ -2933,28 +2749,28 @@ const OptionalCtx = union(enum) {...@@ -2933,28 +2749,28 @@ const OptionalCtx = union(enum) {
2933 Required: &&ast.Node,2749 Required: &&ast.Node,
29342750
2935 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {2751 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
2936 switch (*self) {2752 switch (self.*) {
2937 OptionalCtx.Optional => |ptr| *ptr = value,2753 OptionalCtx.Optional => |ptr| ptr.* = value,
2938 OptionalCtx.RequiredNull => |ptr| *ptr = value,2754 OptionalCtx.RequiredNull => |ptr| ptr.* = value,
2939 OptionalCtx.Required => |ptr| *ptr = value,2755 OptionalCtx.Required => |ptr| ptr.* = value,
2940 }2756 }
2941 }2757 }
29422758
2943 pub fn get(self: &const OptionalCtx) ?&ast.Node {2759 pub fn get(self: &const OptionalCtx) ?&ast.Node {
2944 switch (*self) {2760 switch (self.*) {
2945 OptionalCtx.Optional => |ptr| return *ptr,2761 OptionalCtx.Optional => |ptr| return ptr.*,
2946 OptionalCtx.RequiredNull => |ptr| return ??*ptr,2762 OptionalCtx.RequiredNull => |ptr| return ??ptr.*,
2947 OptionalCtx.Required => |ptr| return *ptr,2763 OptionalCtx.Required => |ptr| return ptr.*,
2948 }2764 }
2949 }2765 }
29502766
2951 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {2767 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
2952 switch (*self) {2768 switch (self.*) {
2953 OptionalCtx.Optional => |ptr| {2769 OptionalCtx.Optional => |ptr| {
2954 return OptionalCtx { .RequiredNull = ptr };2770 return OptionalCtx{ .RequiredNull = ptr };
2955 },2771 },
2956 OptionalCtx.RequiredNull => |ptr| return *self,2772 OptionalCtx.RequiredNull => |ptr| return self.*,
2957 OptionalCtx.Required => |ptr| return *self,2773 OptionalCtx.Required => |ptr| return self.*,
2958 }2774 }
2959 }2775 }
2960};2776};
...@@ -2979,6 +2795,7 @@ const State = union(enum) {...@@ -2979,6 +2795,7 @@ const State = union(enum) {
2979 VarDecl: VarDeclCtx,2795 VarDecl: VarDeclCtx,
2980 VarDeclAlign: &ast.Node.VarDecl,2796 VarDeclAlign: &ast.Node.VarDecl,
2981 VarDeclEq: &ast.Node.VarDecl,2797 VarDeclEq: &ast.Node.VarDecl,
2798 VarDeclSemiColon: &ast.Node.VarDecl,
29822799
2983 FnDef: &ast.Node.FnProto,2800 FnDef: &ast.Node.FnProto,
2984 FnProto: &ast.Node.FnProto,2801 FnProto: &ast.Node.FnProto,
...@@ -3019,9 +2836,9 @@ const State = union(enum) {...@@ -3019,9 +2836,9 @@ const State = union(enum) {
3019 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),2836 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
3020 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),2837 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),
3021 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),2838 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),
3022 SwitchCaseFirstItem: &ast.Node.SwitchCase.ItemList,2839 SwitchCaseFirstItem: &ast.Node.SwitchCase,
3023 SwitchCaseItem: &ast.Node.SwitchCase.ItemList,2840 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase,
3024 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase.ItemList,2841 SwitchCaseItemOrEnd: &ast.Node.SwitchCase,
30252842
3026 SuspendBody: &ast.Node.Suspend,2843 SuspendBody: &ast.Node.Suspend,
3027 AsyncAllocator: &ast.Node.AsyncAttribute,2844 AsyncAllocator: &ast.Node.AsyncAttribute,
...@@ -3031,6 +2848,7 @@ const State = union(enum) {...@@ -3031,6 +2848,7 @@ const State = union(enum) {
3031 SliceOrArrayAccess: &ast.Node.SuffixOp,2848 SliceOrArrayAccess: &ast.Node.SuffixOp,
3032 SliceOrArrayType: &ast.Node.PrefixOp,2849 SliceOrArrayType: &ast.Node.PrefixOp,
3033 AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,2850 AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,
2851 AlignBitRange: &ast.Node.PrefixOp.AddrOfInfo.Align,
30342852
3035 Payload: OptionalCtx,2853 Payload: OptionalCtx,
3036 PointerPayload: OptionalCtx,2854 PointerPayload: OptionalCtx,
...@@ -3075,7 +2893,6 @@ const State = union(enum) {...@@ -3075,7 +2893,6 @@ const State = union(enum) {
3075 Identifier: OptionalCtx,2893 Identifier: OptionalCtx,
3076 ErrorTag: &&ast.Node,2894 ErrorTag: &&ast.Node,
30772895
3078
3079 IfToken: @TagType(Token.Id),2896 IfToken: @TagType(Token.Id),
3080 IfTokenSave: ExpectTokenSave,2897 IfTokenSave: ExpectTokenSave,
3081 ExpectToken: @TagType(Token.Id),2898 ExpectToken: @TagType(Token.Id),
...@@ -3083,25 +2900,27 @@ const State = union(enum) {...@@ -3083,25 +2900,27 @@ const State = union(enum) {
3083 OptionalTokenSave: OptionalTokenSave,2900 OptionalTokenSave: OptionalTokenSave,
3084};2901};
30852902
2903fn pushDocComment(arena: &mem.Allocator, line_comment: TokenIndex, result: &?&ast.Node.DocComment) !void {
2904 const node = blk: {
2905 if (result.*) |comment_node| {
2906 break :blk comment_node;
2907 } else {
2908 const comment_node = try arena.construct(ast.Node.DocComment{
2909 .base = ast.Node{ .id = ast.Node.Id.DocComment },
2910 .lines = ast.Node.DocComment.LineList.init(arena),
2911 });
2912 result.* = comment_node;
2913 break :blk comment_node;
2914 }
2915 };
2916 try node.lines.push(line_comment);
2917}
2918
3086fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.DocComment {2919fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.DocComment {
3087 var result: ?&ast.Node.DocComment = null;2920 var result: ?&ast.Node.DocComment = null;
3088 while (true) {2921 while (true) {
3089 if (eatToken(tok_it, tree, Token.Id.DocComment)) |line_comment| {2922 if (eatToken(tok_it, tree, Token.Id.DocComment)) |line_comment| {
3090 const node = blk: {2923 try pushDocComment(arena, line_comment, &result);
3091 if (result) |comment_node| {
3092 break :blk comment_node;
3093 } else {
3094 const comment_node = try arena.construct(ast.Node.DocComment {
3095 .base = ast.Node {
3096 .id = ast.Node.Id.DocComment,
3097 },
3098 .lines = ast.Node.DocComment.LineList.init(arena),
3099 });
3100 result = comment_node;
3101 break :blk comment_node;
3102 }
3103 };
3104 try node.lines.push(line_comment);
3105 continue;2924 continue;
3106 }2925 }
3107 break;2926 break;
...@@ -3109,26 +2928,14 @@ fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, t...@@ -3109,26 +2928,14 @@ fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, t
3109 return result;2928 return result;
3110}2929}
31112930
3112fn eatLineComment(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.LineComment {2931fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, token_ptr: &const Token, token_index: TokenIndex, tree: &ast.Tree) !?&ast.Node {
3113 const token = eatToken(tok_it, tree, Token.Id.LineComment) ?? return null;
3114 return try arena.construct(ast.Node.LineComment {
3115 .base = ast.Node {
3116 .id = ast.Node.Id.LineComment,
3117 },
3118 .token = token,
3119 });
3120}
3121
3122fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator,
3123 token_ptr: &const Token, token_index: TokenIndex, tree: &ast.Tree) !?&ast.Node
3124{
3125 switch (token_ptr.id) {2932 switch (token_ptr.id) {
3126 Token.Id.StringLiteral => {2933 Token.Id.StringLiteral => {
3127 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;2934 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
3128 },2935 },
3129 Token.Id.MultilineStringLiteralLine => {2936 Token.Id.MultilineStringLiteralLine => {
3130 const node = try arena.construct(ast.Node.MultilineStringLiteral {2937 const node = try arena.construct(ast.Node.MultilineStringLiteral{
3131 .base = ast.Node { .id = ast.Node.Id.MultilineStringLiteral },2938 .base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral },
3132 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),2939 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
3133 });2940 });
3134 try node.lines.push(token_index);2941 try node.lines.push(token_index);
...@@ -3137,7 +2944,7 @@ fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterato...@@ -3137,7 +2944,7 @@ fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterato
3137 const multiline_str_index = multiline_str.index;2944 const multiline_str_index = multiline_str.index;
3138 const multiline_str_ptr = multiline_str.ptr;2945 const multiline_str_ptr = multiline_str.ptr;
3139 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {2946 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {
3140 putBackToken(tok_it, tree);2947 prevToken(tok_it, tree);
3141 break;2948 break;
3142 }2949 }
31432950
...@@ -3152,71 +2959,62 @@ fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterato...@@ -3152,71 +2959,62 @@ fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterato
3152 }2959 }
3153}2960}
31542961
3155fn parseBlockExpr(stack: &std.ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx,2962fn parseBlockExpr(stack: &std.ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx, token_ptr: &const Token, token_index: TokenIndex) !bool {
3156 token_ptr: &const Token, token_index: TokenIndex) !bool {
3157 switch (token_ptr.id) {2963 switch (token_ptr.id) {
3158 Token.Id.Keyword_suspend => {2964 Token.Id.Keyword_suspend => {
3159 const node = try createToCtxNode(arena, ctx, ast.Node.Suspend,2965 const node = try arena.construct(ast.Node.Suspend{
3160 ast.Node.Suspend {2966 .base = ast.Node{ .id = ast.Node.Id.Suspend },
3161 .base = undefined,2967 .label = null,
3162 .label = null,2968 .suspend_token = token_index,
3163 .suspend_token = token_index,2969 .payload = null,
3164 .payload = null,2970 .body = null,
3165 .body = null,2971 });
3166 }2972 ctx.store(&node.base);
3167 );
31682973
3169 stack.append(State { .SuspendBody = node }) catch unreachable;2974 stack.append(State{ .SuspendBody = node }) catch unreachable;
3170 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });2975 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
3171 return true;2976 return true;
3172 },2977 },
3173 Token.Id.Keyword_if => {2978 Token.Id.Keyword_if => {
3174 const node = try createToCtxNode(arena, ctx, ast.Node.If,2979 const node = try arena.construct(ast.Node.If{
3175 ast.Node.If {2980 .base = ast.Node{ .id = ast.Node.Id.If },
3176 .base = undefined,2981 .if_token = token_index,
3177 .if_token = token_index,2982 .condition = undefined,
3178 .condition = undefined,2983 .payload = null,
3179 .payload = null,2984 .body = undefined,
3180 .body = undefined,2985 .@"else" = null,
3181 .@"else" = null,2986 });
3182 }2987 ctx.store(&node.base);
3183 );
31842988
3185 stack.append(State { .Else = &node.@"else" }) catch unreachable;2989 stack.append(State{ .Else = &node.@"else" }) catch unreachable;
3186 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });2990 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } });
3187 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });2991 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });
3188 try stack.append(State { .ExpectToken = Token.Id.RParen });2992 try stack.append(State{ .ExpectToken = Token.Id.RParen });
3189 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });2993 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.condition } });
3190 try stack.append(State { .ExpectToken = Token.Id.LParen });2994 try stack.append(State{ .ExpectToken = Token.Id.LParen });
3191 return true;2995 return true;
3192 },2996 },
3193 Token.Id.Keyword_while => {2997 Token.Id.Keyword_while => {
3194 stack.append(State {2998 stack.append(State{ .While = LoopCtx{
3195 .While = LoopCtx {2999 .label = null,
3196 .label = null,3000 .inline_token = null,
3197 .inline_token = null,3001 .loop_token = token_index,
3198 .loop_token = token_index,3002 .opt_ctx = ctx.*,
3199 .opt_ctx = *ctx,3003 } }) catch unreachable;
3200 }
3201 }) catch unreachable;
3202 return true;3004 return true;
3203 },3005 },
3204 Token.Id.Keyword_for => {3006 Token.Id.Keyword_for => {
3205 stack.append(State {3007 stack.append(State{ .For = LoopCtx{
3206 .For = LoopCtx {3008 .label = null,
3207 .label = null,3009 .inline_token = null,
3208 .inline_token = null,3010 .loop_token = token_index,
3209 .loop_token = token_index,3011 .opt_ctx = ctx.*,
3210 .opt_ctx = *ctx,3012 } }) catch unreachable;
3211 }
3212 }) catch unreachable;
3213 return true;3013 return true;
3214 },3014 },
3215 Token.Id.Keyword_switch => {3015 Token.Id.Keyword_switch => {
3216 const node = try arena.construct(ast.Node.Switch {3016 const node = try arena.construct(ast.Node.Switch{
3217 .base = ast.Node {3017 .base = ast.Node{ .id = ast.Node.Id.Switch },
3218 .id = ast.Node.Id.Switch,
3219 },
3220 .switch_token = token_index,3018 .switch_token = token_index,
3221 .expr = undefined,3019 .expr = undefined,
3222 .cases = ast.Node.Switch.CaseList.init(arena),3020 .cases = ast.Node.Switch.CaseList.init(arena),
...@@ -3224,45 +3022,43 @@ fn parseBlockExpr(stack: &std.ArrayList(State), arena: &mem.Allocator, ctx: &con...@@ -3224,45 +3022,43 @@ fn parseBlockExpr(stack: &std.ArrayList(State), arena: &mem.Allocator, ctx: &con
3224 });3022 });
3225 ctx.store(&node.base);3023 ctx.store(&node.base);
32263024
3227 stack.append(State {3025 stack.append(State{ .SwitchCaseOrEnd = ListSave(@typeOf(node.cases)){
3228 .SwitchCaseOrEnd = ListSave(@typeOf(node.cases)) {3026 .list = &node.cases,
3229 .list = &node.cases,3027 .ptr = &node.rbrace,
3230 .ptr = &node.rbrace,3028 } }) catch unreachable;
3231 },3029 try stack.append(State{ .ExpectToken = Token.Id.LBrace });
3232 }) catch unreachable;3030 try stack.append(State{ .ExpectToken = Token.Id.RParen });
3233 try stack.append(State { .ExpectToken = Token.Id.LBrace });3031 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
3234 try stack.append(State { .ExpectToken = Token.Id.RParen });3032 try stack.append(State{ .ExpectToken = Token.Id.LParen });
3235 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
3236 try stack.append(State { .ExpectToken = Token.Id.LParen });
3237 return true;3033 return true;
3238 },3034 },
3239 Token.Id.Keyword_comptime => {3035 Token.Id.Keyword_comptime => {
3240 const node = try createToCtxNode(arena, ctx, ast.Node.Comptime,3036 const node = try arena.construct(ast.Node.Comptime{
3241 ast.Node.Comptime {3037 .base = ast.Node{ .id = ast.Node.Id.Comptime },
3242 .base = undefined,3038 .comptime_token = token_index,
3243 .comptime_token = token_index,3039 .expr = undefined,
3244 .expr = undefined,3040 .doc_comments = null,
3245 .doc_comments = null,3041 });
3246 }3042 ctx.store(&node.base);
3247 );3043
3248 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });3044 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
3249 return true;3045 return true;
3250 },3046 },
3251 Token.Id.LBrace => {3047 Token.Id.LBrace => {
3252 const block = try arena.construct(ast.Node.Block {3048 const block = try arena.construct(ast.Node.Block{
3253 .base = ast.Node {.id = ast.Node.Id.Block },3049 .base = ast.Node{ .id = ast.Node.Id.Block },
3254 .label = null,3050 .label = null,
3255 .lbrace = token_index,3051 .lbrace = token_index,
3256 .statements = ast.Node.Block.StatementList.init(arena),3052 .statements = ast.Node.Block.StatementList.init(arena),
3257 .rbrace = undefined,3053 .rbrace = undefined,
3258 });3054 });
3259 ctx.store(&block.base);3055 ctx.store(&block.base);
3260 stack.append(State { .Block = block }) catch unreachable;3056 stack.append(State{ .Block = block }) catch unreachable;
3261 return true;3057 return true;
3262 },3058 },
3263 else => {3059 else => {
3264 return false;3060 return false;
3265 }3061 },
3266 }3062 }
3267}3063}
32683064
...@@ -3276,20 +3072,16 @@ fn expectCommaOrEnd(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, end:...@@ -3276,20 +3072,16 @@ fn expectCommaOrEnd(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, end:
3276 const token_index = token.index;3072 const token_index = token.index;
3277 const token_ptr = token.ptr;3073 const token_ptr = token.ptr;
3278 switch (token_ptr.id) {3074 switch (token_ptr.id) {
3279 Token.Id.Comma => return ExpectCommaOrEndResult { .end_token = null},3075 Token.Id.Comma => return ExpectCommaOrEndResult{ .end_token = null },
3280 else => {3076 else => {
3281 if (end == token_ptr.id) {3077 if (end == token_ptr.id) {
3282 return ExpectCommaOrEndResult { .end_token = token_index };3078 return ExpectCommaOrEndResult{ .end_token = token_index };
3283 }3079 }
32843080
3285 return ExpectCommaOrEndResult {3081 return ExpectCommaOrEndResult{ .parse_error = Error{ .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd{
3286 .parse_error = Error {3082 .token = token_index,
3287 .ExpectedCommaOrEnd = Error.ExpectedCommaOrEnd {3083 .end_id = end,
3288 .token = token_index,3084 } } };
3289 .end_id = end,
3290 },
3291 },
3292 };
3293 },3085 },
3294 }3086 }
3295}3087}
...@@ -3297,127 +3089,102 @@ fn expectCommaOrEnd(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, end:...@@ -3297,127 +3089,102 @@ fn expectCommaOrEnd(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, end:
3297fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {3089fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
3298 // TODO: We have to cast all cases because of this:3090 // TODO: We have to cast all cases because of this:
3299 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'3091 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
3300 return switch (*id) {3092 return switch (id.*) {
3301 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = {} },3093 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op{ .AssignBitAnd = {} },
3302 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = {} },3094 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op{ .AssignBitShiftLeft = {} },
3303 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = {} },3095 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op{ .AssignBitShiftRight = {} },
3304 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = {} },3096 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op{ .AssignTimes = {} },
3305 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = {} },3097 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op{ .AssignTimesWarp = {} },
3306 Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = {} },3098 Token.Id.CaretEqual => ast.Node.InfixOp.Op{ .AssignBitXor = {} },
3307 Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = {} },3099 Token.Id.Equal => ast.Node.InfixOp.Op{ .Assign = {} },
3308 Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = {} },3100 Token.Id.MinusEqual => ast.Node.InfixOp.Op{ .AssignMinus = {} },
3309 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = {} },3101 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op{ .AssignMinusWrap = {} },
3310 Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = {} },3102 Token.Id.PercentEqual => ast.Node.InfixOp.Op{ .AssignMod = {} },
3311 Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = {} },3103 Token.Id.PipeEqual => ast.Node.InfixOp.Op{ .AssignBitOr = {} },
3312 Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = {} },3104 Token.Id.PlusEqual => ast.Node.InfixOp.Op{ .AssignPlus = {} },
3313 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = {} },3105 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op{ .AssignPlusWrap = {} },
3314 Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = {} },3106 Token.Id.SlashEqual => ast.Node.InfixOp.Op{ .AssignDiv = {} },
3315 else => null,3107 else => null,
3316 };3108 };
3317}3109}
33183110
3319fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {3111fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3320 return switch (id) {3112 return switch (id) {
3321 Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },3113 Token.Id.Keyword_catch => ast.Node.InfixOp.Op{ .Catch = null },
3322 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },3114 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op{ .UnwrapMaybe = void{} },
3323 else => null,3115 else => null,
3324 };3116 };
3325}3117}
33263118
3327fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {3119fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3328 return switch (id) {3120 return switch (id) {
3329 Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },3121 Token.Id.BangEqual => ast.Node.InfixOp.Op{ .BangEqual = void{} },
3330 Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },3122 Token.Id.EqualEqual => ast.Node.InfixOp.Op{ .EqualEqual = void{} },
3331 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },3123 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op{ .LessThan = void{} },
3332 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },3124 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op{ .LessOrEqual = void{} },
3333 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },3125 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op{ .GreaterThan = void{} },
3334 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },3126 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op{ .GreaterOrEqual = void{} },
3335 else => null,3127 else => null,
3336 };3128 };
3337}3129}
33383130
3339fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {3131fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3340 return switch (id) {3132 return switch (id) {
3341 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },3133 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op{ .BitShiftLeft = void{} },
3342 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },3134 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op{ .BitShiftRight = void{} },
3343 else => null,3135 else => null,
3344 };3136 };
3345}3137}
33463138
3347fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {3139fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3348 return switch (id) {3140 return switch (id) {
3349 Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },3141 Token.Id.Minus => ast.Node.InfixOp.Op{ .Sub = void{} },
3350 Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },3142 Token.Id.MinusPercent => ast.Node.InfixOp.Op{ .SubWrap = void{} },
3351 Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },3143 Token.Id.Plus => ast.Node.InfixOp.Op{ .Add = void{} },
3352 Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },3144 Token.Id.PlusPercent => ast.Node.InfixOp.Op{ .AddWrap = void{} },
3353 Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },3145 Token.Id.PlusPlus => ast.Node.InfixOp.Op{ .ArrayCat = void{} },
3354 else => null,3146 else => null,
3355 };3147 };
3356}3148}
33573149
3358fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {3150fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3359 return switch (id) {3151 return switch (id) {
3360 Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },3152 Token.Id.Slash => ast.Node.InfixOp.Op{ .Div = void{} },
3361 Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },3153 Token.Id.Asterisk => ast.Node.InfixOp.Op{ .Mult = void{} },
3362 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },3154 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op{ .ArrayMult = void{} },
3363 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },3155 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op{ .MultWrap = void{} },
3364 Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },3156 Token.Id.Percent => ast.Node.InfixOp.Op{ .Mod = void{} },
3365 Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },3157 Token.Id.PipePipe => ast.Node.InfixOp.Op{ .MergeErrorSets = void{} },
3366 else => null,3158 else => null,
3367 };3159 };
3368}3160}
33693161
3370fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {3162fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3371 return switch (id) {3163 return switch (id) {
3372 Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },3164 Token.Id.Bang => ast.Node.PrefixOp.Op{ .BoolNot = void{} },
3373 Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },3165 Token.Id.Tilde => ast.Node.PrefixOp.Op{ .BitNot = void{} },
3374 Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },3166 Token.Id.Minus => ast.Node.PrefixOp.Op{ .Negation = void{} },
3375 Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },3167 Token.Id.MinusPercent => ast.Node.PrefixOp.Op{ .NegationWrap = void{} },
3376 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },3168 Token.Id.Asterisk,
3377 Token.Id.Ampersand => ast.Node.PrefixOp.Op {3169 Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op{ .PointerType = void{} },
3378 .AddrOf = ast.Node.PrefixOp.AddrOfInfo {3170 Token.Id.Ampersand => ast.Node.PrefixOp.Op{ .AddrOf = ast.Node.PrefixOp.AddrOfInfo{
3379 .align_expr = null,3171 .align_info = null,
3380 .bit_offset_start_token = null,3172 .const_token = null,
3381 .bit_offset_end_token = null,3173 .volatile_token = null,
3382 .const_token = null,3174 } },
3383 .volatile_token = null,3175 Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .MaybeType = void{} },
3384 },3176 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op{ .UnwrapMaybe = void{} },
3385 },3177 Token.Id.Keyword_await => ast.Node.PrefixOp.Op{ .Await = void{} },
3386 Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },3178 Token.Id.Keyword_try => ast.Node.PrefixOp.Op{ .Try = void{} },
3387 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
3388 Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
3389 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
3390 else => null,3179 else => null,
3391 };3180 };
3392}3181}
33933182
3394fn createNode(arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3395 const node = try arena.create(T);
3396 *node = *init_to;
3397 node.base = blk: {
3398 const id = ast.Node.typeToId(T);
3399 break :blk ast.Node {
3400 .id = id,
3401 };
3402 };
3403
3404 return node;
3405}
3406
3407fn createToCtxNode(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3408 const node = try createNode(arena, T, init_to);
3409 opt_ctx.store(&node.base);
3410
3411 return node;
3412}
3413
3414fn createLiteral(arena: &mem.Allocator, comptime T: type, token_index: TokenIndex) !&T {3183fn createLiteral(arena: &mem.Allocator, comptime T: type, token_index: TokenIndex) !&T {
3415 return createNode(arena, T,3184 return arena.construct(T{
3416 T {3185 .base = ast.Node{ .id = ast.Node.typeToId(T) },
3417 .base = undefined,3186 .token = token_index,
3418 .token = token_index,3187 });
3419 }
3420 );
3421}3188}
34223189
3423fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token_index: TokenIndex) !&T {3190fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token_index: TokenIndex) !&T {
...@@ -3428,73 +3195,34 @@ fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, compti...@@ -3428,73 +3195,34 @@ fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, compti
3428}3195}
34293196
3430fn eatToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {3197fn eatToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {
3431 const token = nextToken(tok_it, tree);3198 const token = ??tok_it.peek();
34323199
3433 if (token.ptr.id == id)3200 if (token.id == id) {
3434 return token.index;3201 return nextToken(tok_it, tree).index;
3202 }
34353203
3436 putBackToken(tok_it, tree);
3437 return null;3204 return null;
3438}3205}
34393206
3440fn nextToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) AnnotatedToken {3207fn nextToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) AnnotatedToken {
3441 const result = AnnotatedToken {3208 const result = AnnotatedToken{
3442 .index = tok_it.index,3209 .index = tok_it.index,
3443 .ptr = ??tok_it.next(),3210 .ptr = ??tok_it.next(),
3444 };3211 };
3445 // possibly skip a following same line token3212 assert(result.ptr.id != Token.Id.LineComment);
3446 const token = tok_it.next() ?? return result;
3447 if (token.id != Token.Id.LineComment) {
3448 putBackToken(tok_it, tree);
3449 return result;
3450 }
3451 const loc = tree.tokenLocationPtr(result.ptr.end, token);
3452 if (loc.line != 0) {
3453 putBackToken(tok_it, tree);
3454 }
3455 return result;
3456}
34573213
3458fn putBackToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) void {3214 while (true) {
3459 const prev_tok = ??tok_it.prev();3215 const next_tok = tok_it.peek() ?? return result;
3460 if (prev_tok.id == Token.Id.LineComment) {3216 if (next_tok.id != Token.Id.LineComment) return result;
3461 const minus2_tok = tok_it.prev() ?? return;3217 _ = tok_it.next();
3462 const loc = tree.tokenLocationPtr(minus2_tok.end, prev_tok);
3463 if (loc.line != 0) {
3464 _ = tok_it.next();
3465 }
3466 }3218 }
3467}3219}
34683220
3469const RenderAstFrame = struct {3221fn prevToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) void {
3470 node: &ast.Node,3222 while (true) {
3471 indent: usize,3223 const prev_tok = tok_it.prev() ?? return;
3472};3224 if (prev_tok.id == Token.Id.LineComment) continue;
34733225 return;
3474pub fn renderAst(allocator: &mem.Allocator, tree: &const ast.Tree, stream: var) !void {
3475 var stack = std.ArrayList(State).init(allocator);
3476 defer stack.deinit();
3477
3478 try stack.append(RenderAstFrame {
3479 .node = &root_node.base,
3480 .indent = 0,
3481 });
3482
3483 while (stack.popOrNull()) |frame| {
3484 {
3485 var i: usize = 0;
3486 while (i < frame.indent) : (i += 1) {
3487 try stream.print(" ");
3488 }
3489 }
3490 try stream.print("{}\n", @tagName(frame.node.id));
3491 var child_i: usize = 0;
3492 while (frame.node.iterate(child_i)) |child| : (child_i += 1) {
3493 try stack.append(RenderAstFrame {
3494 .node = child,
3495 .indent = frame.indent + 2,
3496 });
3497 }
3498 }3226 }
3499}3227}
35003228
std/zig/parser_test.zig+274-9
...@@ -1,3 +1,271 @@...@@ -1,3 +1,271 @@
1test "zig fmt: switch cases trailing comma" {
2 try testTransform(
3 \\fn switch_cases(x: i32) void {
4 \\ switch (x) {
5 \\ 1,2,3 => {},
6 \\ 4,5, => {},
7 \\ 6...8, => {},
8 \\ else => {},
9 \\ }
10 \\}
11 ,
12 \\fn switch_cases(x: i32) void {
13 \\ switch (x) {
14 \\ 1, 2, 3 => {},
15 \\ 4,
16 \\ 5, => {},
17 \\ 6 ... 8 => {},
18 \\ else => {},
19 \\ }
20 \\}
21 \\
22 );
23}
24
25test "zig fmt: slice align" {
26 try testCanonical(
27 \\const A = struct {
28 \\ items: []align(A) T,
29 \\};
30 \\
31 );
32}
33
34test "zig fmt: add trailing comma to array literal" {
35 try testTransform(
36 \\comptime {
37 \\ return []u16{'m', 's', 'y', 's', '-' // hi
38 \\ };
39 \\}
40 ,
41 \\comptime {
42 \\ return []u16{
43 \\ 'm',
44 \\ 's',
45 \\ 'y',
46 \\ 's',
47 \\ '-', // hi
48 \\ };
49 \\}
50 \\
51 );
52}
53
54test "zig fmt: first thing in file is line comment" {
55 try testCanonical(
56 \\// Introspection and determination of system libraries needed by zig.
57 \\
58 \\// Introspection and determination of system libraries needed by zig.
59 \\
60 \\const std = @import("std");
61 \\
62 );
63}
64
65test "zig fmt: line comment after doc comment" {
66 try testCanonical(
67 \\/// doc comment
68 \\// line comment
69 \\fn foo() void {}
70 \\
71 );
72}
73
74test "zig fmt: float literal with exponent" {
75 try testCanonical(
76 \\test "bit field alignment" {
77 \\ assert(@typeOf(&blah.b) == &align(1:3:6) const u3);
78 \\}
79 \\
80 );
81}
82
83test "zig fmt: float literal with exponent" {
84 try testCanonical(
85 \\test "aoeu" {
86 \\ switch (state) {
87 \\ TermState.Start => switch (c) {
88 \\ '\x1b' => state = TermState.Escape,
89 \\ else => try out.writeByte(c),
90 \\ },
91 \\ }
92 \\}
93 \\
94 );
95}
96test "zig fmt: float literal with exponent" {
97 try testCanonical(
98 \\pub const f64_true_min = 4.94065645841246544177e-324;
99 \\const threshold = 0x1.a827999fcef32p+1022;
100 \\
101 );
102}
103
104test "zig fmt: if-else end of comptime" {
105 try testCanonical(
106 \\comptime {
107 \\ if (a) {
108 \\ b();
109 \\ } else {
110 \\ b();
111 \\ }
112 \\}
113 \\
114 );
115}
116
117test "zig fmt: nested blocks" {
118 try testCanonical(
119 \\comptime {
120 \\ {
121 \\ {
122 \\ {
123 \\ a();
124 \\ }
125 \\ }
126 \\ }
127 \\}
128 \\
129 );
130}
131
132test "zig fmt: block with same line comment after end brace" {
133 try testCanonical(
134 \\comptime {
135 \\ {
136 \\ b();
137 \\ } // comment
138 \\}
139 \\
140 );
141}
142
143test "zig fmt: statements with comment between" {
144 try testCanonical(
145 \\comptime {
146 \\ a = b;
147 \\ // comment
148 \\ a = b;
149 \\}
150 \\
151 );
152}
153
154test "zig fmt: statements with empty line between" {
155 try testCanonical(
156 \\comptime {
157 \\ a = b;
158 \\
159 \\ a = b;
160 \\}
161 \\
162 );
163}
164
165test "zig fmt: ptr deref operator" {
166 try testCanonical(
167 \\const a = b.*;
168 \\
169 );
170}
171
172test "zig fmt: comment after if before another if" {
173 try testCanonical(
174 \\test "aoeu" {
175 \\ // comment
176 \\ if (x) {
177 \\ bar();
178 \\ }
179 \\}
180 \\
181 \\test "aoeu" {
182 \\ if (x) {
183 \\ foo();
184 \\ }
185 \\ // comment
186 \\ if (x) {
187 \\ bar();
188 \\ }
189 \\}
190 \\
191 );
192}
193
194test "zig fmt: line comment between if block and else keyword" {
195 try testCanonical(
196 \\test "aoeu" {
197 \\ // cexp(finite|nan +- i inf|nan) = nan + i nan
198 \\ if ((hx & 0x7fffffff) != 0x7f800000) {
199 \\ return Complex(f32).new(y - y, y - y);
200 \\ }
201 \\ // cexp(-inf +- i inf|nan) = 0 + i0
202 \\ else if (hx & 0x80000000 != 0) {
203 \\ return Complex(f32).new(0, 0);
204 \\ }
205 \\ // cexp(+inf +- i inf|nan) = inf + i nan
206 \\ // another comment
207 \\ else {
208 \\ return Complex(f32).new(x, y - y);
209 \\ }
210 \\}
211 \\
212 );
213}
214
215test "zig fmt: same line comments in expression" {
216 try testCanonical(
217 \\test "aoeu" {
218 \\ const x = ( // a
219 \\ 0 // b
220 \\ ); // c
221 \\}
222 \\
223 );
224}
225
226test "zig fmt: add comma on last switch prong" {
227 try testTransform(
228 \\test "aoeu" {
229 \\switch (self.init_arg_expr) {
230 \\ InitArg.Type => |t| { },
231 \\ InitArg.None,
232 \\ InitArg.Enum => { }
233 \\}
234 \\ switch (self.init_arg_expr) {
235 \\ InitArg.Type => |t| { },
236 \\ InitArg.None,
237 \\ InitArg.Enum => { }//line comment
238 \\ }
239 \\}
240 ,
241 \\test "aoeu" {
242 \\ switch (self.init_arg_expr) {
243 \\ InitArg.Type => |t| {},
244 \\ InitArg.None, InitArg.Enum => {},
245 \\ }
246 \\ switch (self.init_arg_expr) {
247 \\ InitArg.Type => |t| {},
248 \\ InitArg.None, InitArg.Enum => {}, //line comment
249 \\ }
250 \\}
251 \\
252 );
253}
254
255test "zig fmt: same-line doc comment on variable declaration" {
256 try testTransform(
257 \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space
258 \\pub const MAP_FILE = 0x0000; /// map from file (default)
259 \\
260 ,
261 \\/// allocated from memory, swap space
262 \\pub const MAP_ANONYMOUS = 0x1000;
263 \\/// map from file (default)
264 \\pub const MAP_FILE = 0x0000;
265 \\
266 );
267}
268
1test "zig fmt: same-line comment after a statement" {269test "zig fmt: same-line comment after a statement" {
2 try testCanonical(270 try testCanonical(
3 \\test "" {271 \\test "" {
...@@ -71,13 +339,6 @@ test "zig fmt: switch with empty body" {...@@ -71,13 +339,6 @@ test "zig fmt: switch with empty body" {
71 );339 );
72}340}
73341
74test "zig fmt: float literal with exponent" {
75 try testCanonical(
76 \\pub const f64_true_min = 4.94065645841246544177e-324;
77 \\
78 );
79}
80
81test "zig fmt: line comments in struct initializer" {342test "zig fmt: line comments in struct initializer" {
82 try testCanonical(343 try testCanonical(
83 \\fn foo() void {344 \\fn foo() void {
...@@ -539,6 +800,11 @@ test "zig fmt: multiline string" {...@@ -539,6 +800,11 @@ test "zig fmt: multiline string" {
539 \\ c\\two)800 \\ c\\two)
540 \\ c\\three801 \\ c\\three
541 \\ ;802 \\ ;
803 \\ const s3 = // hi
804 \\ \\one
805 \\ \\two)
806 \\ \\three
807 \\ ;
542 \\}808 \\}
543 \\809 \\
544 );810 );
...@@ -759,8 +1025,7 @@ test "zig fmt: switch" {...@@ -759,8 +1025,7 @@ test "zig fmt: switch" {
759 \\ switch (0) {1025 \\ switch (0) {
760 \\ 0 => {},1026 \\ 0 => {},
761 \\ 1 => unreachable,1027 \\ 1 => unreachable,
762 \\ 2,1028 \\ 2, 3 => {},
763 \\ 3 => {},
764 \\ 4 ... 7 => {},1029 \\ 4 ... 7 => {},
765 \\ 1 + 4 * 3 + 22 => {},1030 \\ 1 + 4 * 3 + 22 => {},
766 \\ else => {1031 \\ else => {
std/zig/render.zig+1363-1120
...@@ -1,1270 +1,1513 @@...@@ -1,1270 +1,1513 @@
1const std = @import("../index.zig");1const std = @import("../index.zig");
2const builtin = @import("builtin");
2const assert = std.debug.assert;3const assert = std.debug.assert;
3const mem = std.mem;4const mem = std.mem;
4const ast = std.zig.ast;5const ast = std.zig.ast;
5const Token = std.zig.Token;6const Token = std.zig.Token;
67
7const RenderState = union(enum) {
8 TopLevelDecl: &ast.Node,
9 ParamDecl: &ast.Node,
10 Text: []const u8,
11 Expression: &ast.Node,
12 VarDecl: &ast.Node.VarDecl,
13 Statement: &ast.Node,
14 PrintIndent,
15 Indent: usize,
16 MaybeSemiColon: &ast.Node,
17 Token: ast.TokenIndex,
18 NonBreakToken: ast.TokenIndex,
19};
20
21const indent_delta = 4;8const indent_delta = 4;
229
23pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) !void {10pub const Error = error{
24 var stack = std.ArrayList(RenderState).init(allocator);11 /// Ran out of memory allocating call stack frames to complete rendering.
25 defer stack.deinit();12 OutOfMemory,
2613};
27 {14
28 try stack.append(RenderState { .Text = "\n"});15pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(stream).Child.Error || Error)!void {
2916 comptime assert(@typeId(@typeOf(stream)) == builtin.TypeId.Pointer);
30 var i = tree.root_node.decls.len;17
31 while (i != 0) {18 // render all the line comments at the beginning of the file
32 i -= 1;19 var tok_it = tree.tokens.iterator(0);
33 const decl = *tree.root_node.decls.at(i);20 while (tok_it.next()) |token| {
34 try stack.append(RenderState {.TopLevelDecl = decl});21 if (token.id != Token.Id.LineComment) break;
35 if (i != 0) {22 try stream.print("{}\n", tree.tokenSlicePtr(token));
36 try stack.append(RenderState {23 if (tok_it.peek()) |next_token| {
37 .Text = blk: {24 const loc = tree.tokenLocationPtr(token.end, next_token);
38 const prev_node = *tree.root_node.decls.at(i - 1);25 if (loc.line >= 2) {
39 const prev_node_last_token = tree.tokens.at(prev_node.lastToken());26 try stream.writeByte('\n');
40 const loc = tree.tokenLocation(prev_node_last_token.end, decl.firstToken());
41 if (loc.line >= 2) {
42 break :blk "\n\n";
43 }
44 break :blk "\n";
45 },
46 });
47 }27 }
48 }28 }
49 }29 }
5030
51 var indent: usize = 0;
52 while (stack.popOrNull()) |state| {
53 switch (state) {
54 RenderState.TopLevelDecl => |decl| {
55 switch (decl.id) {
56 ast.Node.Id.FnProto => {
57 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
58 try renderComments(tree, stream, fn_proto, indent);
59
60 if (fn_proto.body_node) |body_node| {
61 stack.append(RenderState { .Expression = body_node}) catch unreachable;
62 try stack.append(RenderState { .Text = " "});
63 } else {
64 stack.append(RenderState { .Text = ";" }) catch unreachable;
65 }
6631
67 try stack.append(RenderState { .Expression = decl });32 var it = tree.root_node.decls.iterator(0);
68 },33 while (it.next()) |decl| {
69 ast.Node.Id.Use => {34 try renderTopLevelDecl(allocator, stream, tree, 0, decl.*);
70 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);35 if (it.peek()) |next_decl| {
71 if (use_decl.visib_token) |visib_token| {36 try renderExtraNewline(tree, stream, next_decl.*);
72 try stream.print("{} ", tree.tokenSlice(visib_token));37 }
73 }38 }
74 try stream.print("use ");39}
75 try stack.append(RenderState { .Text = ";" });
76 try stack.append(RenderState { .Expression = use_decl.expr });
77 },
78 ast.Node.Id.VarDecl => {
79 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
80 try renderComments(tree, stream, var_decl, indent);
81 try stack.append(RenderState { .VarDecl = var_decl});
82 },
83 ast.Node.Id.TestDecl => {
84 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
85 try renderComments(tree, stream, test_decl, indent);
86 try stream.print("test ");
87 try stack.append(RenderState { .Expression = test_decl.body_node });
88 try stack.append(RenderState { .Text = " " });
89 try stack.append(RenderState { .Expression = test_decl.name });
90 },
91 ast.Node.Id.StructField => {
92 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
93 try renderComments(tree, stream, field, indent);
94 if (field.visib_token) |visib_token| {
95 try stream.print("{} ", tree.tokenSlice(visib_token));
96 }
97 try stream.print("{}: ", tree.tokenSlice(field.name_token));
98 try stack.append(RenderState { .Token = field.lastToken() + 1 });
99 try stack.append(RenderState { .Expression = field.type_expr});
100 },
101 ast.Node.Id.UnionTag => {
102 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
103 try renderComments(tree, stream, tag, indent);
104 try stream.print("{}", tree.tokenSlice(tag.name_token));
105
106 try stack.append(RenderState { .Text = "," });
107
108 if (tag.value_expr) |value_expr| {
109 try stack.append(RenderState { .Expression = value_expr });
110 try stack.append(RenderState { .Text = " = " });
111 }
11240
113 if (tag.type_expr) |type_expr| {41fn renderExtraNewline(tree: &ast.Tree, stream: var, node: &ast.Node) !void {
114 try stream.print(": ");42 var first_token = node.firstToken();
115 try stack.append(RenderState { .Expression = type_expr});43 while (tree.tokens.at(first_token - 1).id == Token.Id.DocComment) {
116 }44 first_token -= 1;
117 },45 }
118 ast.Node.Id.EnumTag => {46 const prev_token_end = tree.tokens.at(first_token - 1).end;
119 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);47 const loc = tree.tokenLocation(prev_token_end, first_token);
120 try renderComments(tree, stream, tag, indent);48 if (loc.line >= 2) {
121 try stream.print("{}", tree.tokenSlice(tag.name_token));49 try stream.writeByte('\n');
12250 }
123 try stack.append(RenderState { .Text = "," });51}
124 if (tag.value) |value| {
125 try stream.print(" = ");
126 try stack.append(RenderState { .Expression = value});
127 }
128 },
129 ast.Node.Id.ErrorTag => {
130 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
131 try renderComments(tree, stream, tag, indent);
132 try stream.print("{}", tree.tokenSlice(tag.name_token));
133 },
134 ast.Node.Id.Comptime => {
135 try stack.append(RenderState { .MaybeSemiColon = decl });
136 try stack.append(RenderState { .Expression = decl });
137 },
138 ast.Node.Id.LineComment => {
139 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
140 try stream.write(tree.tokenSlice(line_comment_node.token));
141 },
142 else => unreachable,
143 }
144 },
145
146 RenderState.VarDecl => |var_decl| {
147 try stack.append(RenderState { .Token = var_decl.semicolon_token });
148 if (var_decl.init_node) |init_node| {
149 try stack.append(RenderState { .Expression = init_node });
150 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
151 try stack.append(RenderState { .Text = text });
152 }
153 if (var_decl.align_node) |align_node| {
154 try stack.append(RenderState { .Text = ")" });
155 try stack.append(RenderState { .Expression = align_node });
156 try stack.append(RenderState { .Text = " align(" });
157 }
158 if (var_decl.type_node) |type_node| {
159 try stack.append(RenderState { .Expression = type_node });
160 try stack.append(RenderState { .Text = ": " });
161 }
162 try stack.append(RenderState { .Text = tree.tokenSlice(var_decl.name_token) });
163 try stack.append(RenderState { .Text = " " });
164 try stack.append(RenderState { .Text = tree.tokenSlice(var_decl.mut_token) });
16552
166 if (var_decl.comptime_token) |comptime_token| {53fn renderTopLevelDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, decl: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
167 try stack.append(RenderState { .Text = " " });54 switch (decl.id) {
168 try stack.append(RenderState { .Text = tree.tokenSlice(comptime_token) });55 ast.Node.Id.FnProto => {
169 }56 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
57
58 try renderDocComments(tree, stream, fn_proto, indent);
59
60 if (fn_proto.body_node) |body_node| {
61 try renderExpression(allocator, stream, tree, indent, decl, Space.Space);
62 try renderExpression(allocator, stream, tree, indent, body_node, Space.Newline);
63 } else {
64 try renderExpression(allocator, stream, tree, indent, decl, Space.None);
65 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, Space.Newline);
66 }
67 },
68
69 ast.Node.Id.Use => {
70 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
71
72 if (use_decl.visib_token) |visib_token| {
73 try renderToken(tree, stream, visib_token, indent, Space.Space); // pub
74 }
75 try renderToken(tree, stream, use_decl.use_token, indent, Space.Space); // use
76 try renderExpression(allocator, stream, tree, indent, use_decl.expr, Space.None);
77 try renderToken(tree, stream, use_decl.semicolon_token, indent, Space.Newline); // ;
78 },
79
80 ast.Node.Id.VarDecl => {
81 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
82
83 try renderDocComments(tree, stream, var_decl, indent);
84 try renderVarDecl(allocator, stream, tree, indent, var_decl);
85 },
86
87 ast.Node.Id.TestDecl => {
88 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
89
90 try renderDocComments(tree, stream, test_decl, indent);
91 try renderToken(tree, stream, test_decl.test_token, indent, Space.Space);
92 try renderExpression(allocator, stream, tree, indent, test_decl.name, Space.Space);
93 try renderExpression(allocator, stream, tree, indent, test_decl.body_node, Space.Newline);
94 },
95
96 ast.Node.Id.StructField => {
97 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
98
99 try renderDocComments(tree, stream, field, indent);
100 if (field.visib_token) |visib_token| {
101 try renderToken(tree, stream, visib_token, indent, Space.Space); // pub
102 }
103 try renderToken(tree, stream, field.name_token, indent, Space.None); // name
104 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, Space.Space); // :
105 try renderExpression(allocator, stream, tree, indent, field.type_expr, Space.None); // type
106 try renderToken(tree, stream, tree.nextToken(field.lastToken()), indent, Space.Newline); // ,
107 },
108
109 ast.Node.Id.UnionTag => {
110 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
111
112 try renderDocComments(tree, stream, tag, indent);
113
114 const name_space = if (tag.type_expr == null and tag.value_expr != null) Space.Space else Space.None;
115 try renderToken(tree, stream, tag.name_token, indent, name_space); // name
116
117 if (tag.type_expr) |type_expr| {
118 try renderToken(tree, stream, tree.nextToken(tag.name_token), indent, Space.Space); // :
119
120 const after_type_space = if (tag.value_expr == null) Space.None else Space.Space;
121 try renderExpression(allocator, stream, tree, indent, type_expr, after_type_space);
122 }
123
124 if (tag.value_expr) |value_expr| {
125 try renderToken(tree, stream, tree.prevToken(value_expr.firstToken()), indent, Space.Space); // =
126 try renderExpression(allocator, stream, tree, indent, value_expr, Space.None);
127 }
128
129 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, Space.Newline); // ,
130 },
131
132 ast.Node.Id.EnumTag => {
133 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
134
135 try renderDocComments(tree, stream, tag, indent);
136
137 const after_name_space = if (tag.value == null) Space.None else Space.Space;
138 try renderToken(tree, stream, tag.name_token, indent, after_name_space); // name
139
140 if (tag.value) |value| {
141 try renderToken(tree, stream, tree.nextToken(tag.name_token), indent, Space.Space); // =
142 try renderExpression(allocator, stream, tree, indent, value, Space.None);
143 }
144
145 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, Space.Newline); // ,
146 },
170147
171 if (var_decl.extern_export_token) |extern_export_token| {148 ast.Node.Id.Comptime => {
172 if (var_decl.lib_name != null) {149 assert(!decl.requireSemiColon());
173 try stack.append(RenderState { .Text = " " });150 try renderExpression(allocator, stream, tree, indent, decl, Space.Newline);
174 try stack.append(RenderState { .Expression = ??var_decl.lib_name });151 },
152 else => unreachable,
153 }
154}
155
156fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node, space: Space) (@typeOf(stream).Child.Error || Error)!void {
157 switch (base.id) {
158 ast.Node.Id.Identifier => {
159 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
160 try renderToken(tree, stream, identifier.token, indent, space);
161 },
162 ast.Node.Id.Block => {
163 const block = @fieldParentPtr(ast.Node.Block, "base", base);
164
165 if (block.label) |label| {
166 try renderToken(tree, stream, label, indent, Space.None);
167 try renderToken(tree, stream, tree.nextToken(label), indent, Space.Space);
168 }
169
170 if (block.statements.len == 0) {
171 try renderToken(tree, stream, block.lbrace, indent + indent_delta, Space.None);
172 try renderToken(tree, stream, block.rbrace, indent, space);
173 } else {
174 const block_indent = indent + indent_delta;
175 try renderToken(tree, stream, block.lbrace, block_indent, Space.Newline);
176
177 var it = block.statements.iterator(0);
178 while (it.next()) |statement| {
179 try stream.writeByteNTimes(' ', block_indent);
180 try renderStatement(allocator, stream, tree, block_indent, statement.*);
181
182 if (it.peek()) |next_statement| {
183 try renderExtraNewline(tree, stream, next_statement.*);
175 }184 }
176 try stack.append(RenderState { .Text = " " });
177 try stack.append(RenderState { .Text = tree.tokenSlice(extern_export_token) });
178 }185 }
179186
180 if (var_decl.visib_token) |visib_token| {187 try stream.writeByteNTimes(' ', indent);
181 try stack.append(RenderState { .Text = " " });188 try renderToken(tree, stream, block.rbrace, indent, space);
182 try stack.append(RenderState { .Text = tree.tokenSlice(visib_token) });189 }
183 }190 },
184 },191 ast.Node.Id.Defer => {
192 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
193
194 try renderToken(tree, stream, defer_node.defer_token, indent, Space.Space);
195 try renderExpression(allocator, stream, tree, indent, defer_node.expr, space);
196 },
197 ast.Node.Id.Comptime => {
198 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
199
200 try renderToken(tree, stream, comptime_node.comptime_token, indent, Space.Space);
201 try renderExpression(allocator, stream, tree, indent, comptime_node.expr, space);
202 },
203
204 ast.Node.Id.AsyncAttribute => {
205 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
206
207 if (async_attr.allocator_type) |allocator_type| {
208 try renderToken(tree, stream, async_attr.async_token, indent, Space.None);
209
210 try renderToken(tree, stream, tree.nextToken(async_attr.async_token), indent, Space.None);
211 try renderExpression(allocator, stream, tree, indent, allocator_type, Space.None);
212 try renderToken(tree, stream, tree.nextToken(allocator_type.lastToken()), indent, space);
213 } else {
214 try renderToken(tree, stream, async_attr.async_token, indent, space);
215 }
216 },
185217
186 RenderState.ParamDecl => |base| {218 ast.Node.Id.Suspend => {
187 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);219 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
188 if (param_decl.comptime_token) |comptime_token| {220
189 try stream.print("{} ", tree.tokenSlice(comptime_token));221 if (suspend_node.label) |label| {
190 }222 try renderToken(tree, stream, label, indent, Space.None);
191 if (param_decl.noalias_token) |noalias_token| {223 try renderToken(tree, stream, tree.nextToken(label), indent, Space.Space);
192 try stream.print("{} ", tree.tokenSlice(noalias_token));224 }
193 }225
194 if (param_decl.name_token) |name_token| {226 if (suspend_node.payload) |payload| {
195 try stream.print("{}: ", tree.tokenSlice(name_token));227 if (suspend_node.body) |body| {
196 }228 try renderToken(tree, stream, suspend_node.suspend_token, indent, Space.Space);
197 if (param_decl.var_args_token) |var_args_token| {229 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
198 try stream.print("{}", tree.tokenSlice(var_args_token));230 try renderExpression(allocator, stream, tree, indent, body, space);
199 } else {231 } else {
200 try stack.append(RenderState { .Expression = param_decl.type_node});232 try renderToken(tree, stream, suspend_node.suspend_token, indent, Space.Space);
233 try renderExpression(allocator, stream, tree, indent, payload, space);
201 }234 }
202 },235 } else if (suspend_node.body) |body| {
203 RenderState.Text => |bytes| {236 try renderToken(tree, stream, suspend_node.suspend_token, indent, Space.Space);
204 try stream.write(bytes);237 try renderExpression(allocator, stream, tree, indent, body, space);
205 },238 } else {
206 RenderState.Expression => |base| switch (base.id) {239 try renderToken(tree, stream, suspend_node.suspend_token, indent, space);
207 ast.Node.Id.Identifier => {240 }
208 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);241 },
209 try stream.print("{}", tree.tokenSlice(identifier.token));242
243 ast.Node.Id.InfixOp => {
244 const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
245
246 const op_token = tree.tokens.at(infix_op_node.op_token);
247 const op_space = switch (infix_op_node.op) {
248 ast.Node.InfixOp.Op.Period, ast.Node.InfixOp.Op.ErrorUnion => Space.None,
249 else => Space.Space,
250 };
251 try renderExpression(allocator, stream, tree, indent, infix_op_node.lhs, op_space);
252 try renderToken(tree, stream, infix_op_node.op_token, indent, op_space);
253
254 switch (infix_op_node.op) {
255 ast.Node.InfixOp.Op.Catch => |maybe_payload| if (maybe_payload) |payload| {
256 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
210 },257 },
211 ast.Node.Id.Block => {258 else => {},
212 const block = @fieldParentPtr(ast.Node.Block, "base", base);259 }
213 if (block.label) |label| {
214 try stream.print("{}: ", tree.tokenSlice(label));
215 }
216260
217 if (block.statements.len == 0) {261 try renderExpression(allocator, stream, tree, indent, infix_op_node.rhs, space);
218 try stream.write("{}");262 },
219 } else {263
220 try stream.write("{");264 ast.Node.Id.PrefixOp => {
221 try stack.append(RenderState { .Text = "}"});265 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
222 try stack.append(RenderState.PrintIndent);266
223 try stack.append(RenderState { .Indent = indent});267 switch (prefix_op_node.op) {
224 try stack.append(RenderState { .Text = "\n"});268 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
225 var i = block.statements.len;269 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.None); // &
226 while (i != 0) {270 if (addr_of_info.align_info) |align_info| {
227 i -= 1;271 const lparen_token = tree.prevToken(align_info.node.firstToken());
228 const statement_node = *block.statements.at(i);272 const align_token = tree.prevToken(lparen_token);
229 try stack.append(RenderState { .Statement = statement_node});273
230 try stack.append(RenderState.PrintIndent);274 try renderToken(tree, stream, align_token, indent, Space.None); // align
231 try stack.append(RenderState { .Indent = indent + indent_delta});275 try renderToken(tree, stream, lparen_token, indent, Space.None); // (
232 try stack.append(RenderState {276
233 .Text = blk: {277 try renderExpression(allocator, stream, tree, indent, align_info.node, Space.None);
234 if (i != 0) {278
235 const prev_node = *block.statements.at(i - 1);279 if (align_info.bit_range) |bit_range| {
236 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;280 const colon1 = tree.prevToken(bit_range.start.firstToken());
237 const loc = tree.tokenLocation(prev_node_last_token_end, statement_node.firstToken());281 const colon2 = tree.prevToken(bit_range.end.firstToken());
238 if (loc.line >= 2) {282
239 break :blk "\n\n";283 try renderToken(tree, stream, colon1, indent, Space.None); // :
240 }284 try renderExpression(allocator, stream, tree, indent, bit_range.start, Space.None);
241 }285 try renderToken(tree, stream, colon2, indent, Space.None); // :
242 break :blk "\n";286 try renderExpression(allocator, stream, tree, indent, bit_range.end, Space.None);
243 },287
244 });288 const rparen_token = tree.nextToken(bit_range.end.lastToken());
289 try renderToken(tree, stream, rparen_token, indent, Space.Space); // )
290 } else {
291 const rparen_token = tree.nextToken(align_info.node.lastToken());
292 try renderToken(tree, stream, rparen_token, indent, Space.Space); // )
245 }293 }
246 }294 }
247 },295 if (addr_of_info.const_token) |const_token| {
248 ast.Node.Id.Defer => {296 try renderToken(tree, stream, const_token, indent, Space.Space); // const
249 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
250 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));
251 try stack.append(RenderState { .Expression = defer_node.expr });
252 },
253 ast.Node.Id.Comptime => {
254 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
255 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));
256 try stack.append(RenderState { .Expression = comptime_node.expr });
257 },
258 ast.Node.Id.AsyncAttribute => {
259 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
260 try stream.print("{}", tree.tokenSlice(async_attr.async_token));
261
262 if (async_attr.allocator_type) |allocator_type| {
263 try stack.append(RenderState { .Text = ">" });
264 try stack.append(RenderState { .Expression = allocator_type });
265 try stack.append(RenderState { .Text = "<" });
266 }297 }
267 },298 if (addr_of_info.volatile_token) |volatile_token| {
268 ast.Node.Id.Suspend => {299 try renderToken(tree, stream, volatile_token, indent, Space.Space); // volatile
269 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
270 if (suspend_node.label) |label| {
271 try stream.print("{}: ", tree.tokenSlice(label));
272 }300 }
273 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));301 },
274302
275 if (suspend_node.body) |body| {303 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
276 try stack.append(RenderState { .Expression = body });304 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.None); // [
277 try stack.append(RenderState { .Text = " " });305 try renderToken(tree, stream, tree.nextToken(prefix_op_node.op_token), indent, Space.None); // ]
278 }
279306
280 if (suspend_node.payload) |payload| {307 if (addr_of_info.align_info) |align_info| {
281 try stack.append(RenderState { .Expression = payload });308 const lparen_token = tree.prevToken(align_info.node.firstToken());
282 try stack.append(RenderState { .Text = " " });309 const align_token = tree.prevToken(lparen_token);
283 }310
284 },311 try renderToken(tree, stream, align_token, indent, Space.None); // align
285 ast.Node.Id.InfixOp => {312 try renderToken(tree, stream, lparen_token, indent, Space.None); // (
286 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);313
287 try stack.append(RenderState { .Expression = prefix_op_node.rhs });314 try renderExpression(allocator, stream, tree, indent, align_info.node, Space.None);
288315
289 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {316 if (align_info.bit_range) |bit_range| {
290 if (prefix_op_node.op.Catch) |payload| {317 const colon1 = tree.prevToken(bit_range.start.firstToken());
291 try stack.append(RenderState { .Text = " " });318 const colon2 = tree.prevToken(bit_range.end.firstToken());
292 try stack.append(RenderState { .Expression = payload });319
320 try renderToken(tree, stream, colon1, indent, Space.None); // :
321 try renderExpression(allocator, stream, tree, indent, bit_range.start, Space.None);
322 try renderToken(tree, stream, colon2, indent, Space.None); // :
323 try renderExpression(allocator, stream, tree, indent, bit_range.end, Space.None);
324
325 const rparen_token = tree.nextToken(bit_range.end.lastToken());
326 try renderToken(tree, stream, rparen_token, indent, Space.Space); // )
327 } else {
328 const rparen_token = tree.nextToken(align_info.node.lastToken());
329 try renderToken(tree, stream, rparen_token, indent, Space.Space); // )
293 }330 }
294 try stack.append(RenderState { .Text = " catch " });
295 } else {
296 const text = switch (prefix_op_node.op) {
297 ast.Node.InfixOp.Op.Add => " + ",
298 ast.Node.InfixOp.Op.AddWrap => " +% ",
299 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
300 ast.Node.InfixOp.Op.ArrayMult => " ** ",
301 ast.Node.InfixOp.Op.Assign => " = ",
302 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
303 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
304 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
305 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
306 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
307 ast.Node.InfixOp.Op.AssignDiv => " /= ",
308 ast.Node.InfixOp.Op.AssignMinus => " -= ",
309 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
310 ast.Node.InfixOp.Op.AssignMod => " %= ",
311 ast.Node.InfixOp.Op.AssignPlus => " += ",
312 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
313 ast.Node.InfixOp.Op.AssignTimes => " *= ",
314 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
315 ast.Node.InfixOp.Op.BangEqual => " != ",
316 ast.Node.InfixOp.Op.BitAnd => " & ",
317 ast.Node.InfixOp.Op.BitOr => " | ",
318 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
319 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
320 ast.Node.InfixOp.Op.BitXor => " ^ ",
321 ast.Node.InfixOp.Op.BoolAnd => " and ",
322 ast.Node.InfixOp.Op.BoolOr => " or ",
323 ast.Node.InfixOp.Op.Div => " / ",
324 ast.Node.InfixOp.Op.EqualEqual => " == ",
325 ast.Node.InfixOp.Op.ErrorUnion => "!",
326 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
327 ast.Node.InfixOp.Op.GreaterThan => " > ",
328 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
329 ast.Node.InfixOp.Op.LessThan => " < ",
330 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
331 ast.Node.InfixOp.Op.Mod => " % ",
332 ast.Node.InfixOp.Op.Mult => " * ",
333 ast.Node.InfixOp.Op.MultWrap => " *% ",
334 ast.Node.InfixOp.Op.Period => ".",
335 ast.Node.InfixOp.Op.Sub => " - ",
336 ast.Node.InfixOp.Op.SubWrap => " -% ",
337 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
338 ast.Node.InfixOp.Op.Range => " ... ",
339 ast.Node.InfixOp.Op.Catch => unreachable,
340 };
341
342 try stack.append(RenderState { .Text = text });
343 }331 }
344 try stack.append(RenderState { .Expression = prefix_op_node.lhs });332 if (addr_of_info.const_token) |const_token| {
345 },333 try renderToken(tree, stream, const_token, indent, Space.Space);
346 ast.Node.Id.PrefixOp => {
347 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
348 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
349 switch (prefix_op_node.op) {
350 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
351 try stream.write("&");
352 if (addr_of_info.volatile_token != null) {
353 try stack.append(RenderState { .Text = "volatile "});
354 }
355 if (addr_of_info.const_token != null) {
356 try stack.append(RenderState { .Text = "const "});
357 }
358 if (addr_of_info.align_expr) |align_expr| {
359 try stream.print("align(");
360 try stack.append(RenderState { .Text = ") "});
361 try stack.append(RenderState { .Expression = align_expr});
362 }
363 },
364 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
365 try stream.write("[]");
366 if (addr_of_info.volatile_token != null) {
367 try stack.append(RenderState { .Text = "volatile "});
368 }
369 if (addr_of_info.const_token != null) {
370 try stack.append(RenderState { .Text = "const "});
371 }
372 if (addr_of_info.align_expr) |align_expr| {
373 try stream.print("align(");
374 try stack.append(RenderState { .Text = ") "});
375 try stack.append(RenderState { .Expression = align_expr});
376 }
377 },
378 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
379 try stack.append(RenderState { .Text = "]"});
380 try stack.append(RenderState { .Expression = array_index});
381 try stack.append(RenderState { .Text = "["});
382 },
383 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
384 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
385 ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
386 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
387 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
388 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
389 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
390 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
391 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
392 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
393 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
394 }334 }
395 },335 if (addr_of_info.volatile_token) |volatile_token| {
396 ast.Node.Id.SuffixOp => {336 try renderToken(tree, stream, volatile_token, indent, Space.Space);
397 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
398
399 switch (suffix_op.op) {
400 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
401 try stack.append(RenderState { .Text = ")"});
402 var i = call_info.params.len;
403 while (i != 0) {
404 i -= 1;
405 const param_node = *call_info.params.at(i);
406 try stack.append(RenderState { .Expression = param_node});
407 if (i != 0) {
408 try stack.append(RenderState { .Text = ", " });
409 }
410 }
411 try stack.append(RenderState { .Text = "("});
412 try stack.append(RenderState { .Expression = suffix_op.lhs });
413
414 if (call_info.async_attr) |async_attr| {
415 try stack.append(RenderState { .Text = " "});
416 try stack.append(RenderState { .Expression = &async_attr.base });
417 }
418 },
419 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
420 try stack.append(RenderState { .Text = "]"});
421 try stack.append(RenderState { .Expression = index_expr});
422 try stack.append(RenderState { .Text = "["});
423 try stack.append(RenderState { .Expression = suffix_op.lhs });
424 },
425 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
426 try stack.append(RenderState { .Text = "]"});
427 if (range.end) |end| {
428 try stack.append(RenderState { .Expression = end});
429 }
430 try stack.append(RenderState { .Text = ".."});
431 try stack.append(RenderState { .Expression = range.start});
432 try stack.append(RenderState { .Text = "["});
433 try stack.append(RenderState { .Expression = suffix_op.lhs });
434 },
435 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
436 if (field_inits.len == 0) {
437 try stack.append(RenderState { .Text = "{}" });
438 try stack.append(RenderState { .Expression = suffix_op.lhs });
439 continue;
440 }
441 if (field_inits.len == 1) {
442 const field_init = *field_inits.at(0);
443
444 try stack.append(RenderState { .Text = " }" });
445 try stack.append(RenderState { .Expression = field_init });
446 try stack.append(RenderState { .Text = "{ " });
447 try stack.append(RenderState { .Expression = suffix_op.lhs });
448 continue;
449 }
450 try stack.append(RenderState { .Text = "}"});
451 try stack.append(RenderState.PrintIndent);
452 try stack.append(RenderState { .Indent = indent });
453 try stack.append(RenderState { .Text = "\n" });
454 var i = field_inits.len;
455 while (i != 0) {
456 i -= 1;
457 const field_init = *field_inits.at(i);
458 if (field_init.id != ast.Node.Id.LineComment) {
459 try stack.append(RenderState { .Text = "," });
460 }
461 try stack.append(RenderState { .Expression = field_init });
462 try stack.append(RenderState.PrintIndent);
463 if (i != 0) {
464 try stack.append(RenderState { .Text = blk: {
465 const prev_node = *field_inits.at(i - 1);
466 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
467 const loc = tree.tokenLocation(prev_node_last_token_end, field_init.firstToken());
468 if (loc.line >= 2) {
469 break :blk "\n\n";
470 }
471 break :blk "\n";
472 }});
473 }
474 }
475 try stack.append(RenderState { .Indent = indent + indent_delta });
476 try stack.append(RenderState { .Text = "{\n"});
477 try stack.append(RenderState { .Expression = suffix_op.lhs });
478 },
479 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
480 if (exprs.len == 0) {
481 try stack.append(RenderState { .Text = "{}" });
482 try stack.append(RenderState { .Expression = suffix_op.lhs });
483 continue;
484 }
485 if (exprs.len == 1) {
486 const expr = *exprs.at(0);
487
488 try stack.append(RenderState { .Text = "}" });
489 try stack.append(RenderState { .Expression = expr });
490 try stack.append(RenderState { .Text = "{" });
491 try stack.append(RenderState { .Expression = suffix_op.lhs });
492 continue;
493 }
494
495 try stack.append(RenderState { .Text = "}"});
496 try stack.append(RenderState.PrintIndent);
497 try stack.append(RenderState { .Indent = indent });
498 var i = exprs.len;
499 while (i != 0) {
500 i -= 1;
501 const expr = *exprs.at(i);
502 try stack.append(RenderState { .Text = ",\n" });
503 try stack.append(RenderState { .Expression = expr });
504 try stack.append(RenderState.PrintIndent);
505 }
506 try stack.append(RenderState { .Indent = indent + indent_delta });
507 try stack.append(RenderState { .Text = "{\n"});
508 try stack.append(RenderState { .Expression = suffix_op.lhs });
509 },
510 }337 }
511 },338 },
512 ast.Node.Id.ControlFlowExpression => {
513 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
514339
515 if (flow_expr.rhs) |rhs| {340 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
516 try stack.append(RenderState { .Expression = rhs });341 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.None); // [
517 try stack.append(RenderState { .Text = " " });342 try renderExpression(allocator, stream, tree, indent, array_index, Space.None);
518 }343 try renderToken(tree, stream, tree.nextToken(array_index.lastToken()), indent, Space.None); // ]
519
520 switch (flow_expr.kind) {
521 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
522 try stream.print("break");
523 if (maybe_label) |label| {
524 try stream.print(" :");
525 try stack.append(RenderState { .Expression = label });
526 }
527 },
528 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
529 try stream.print("continue");
530 if (maybe_label) |label| {
531 try stream.print(" :");
532 try stack.append(RenderState { .Expression = label });
533 }
534 },
535 ast.Node.ControlFlowExpression.Kind.Return => {
536 try stream.print("return");
537 },
538
539 }
540 },344 },
541 ast.Node.Id.Payload => {345 ast.Node.PrefixOp.Op.BitNot,
542 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);346 ast.Node.PrefixOp.Op.BoolNot,
543 try stack.append(RenderState { .Text = "|"});347 ast.Node.PrefixOp.Op.Negation,
544 try stack.append(RenderState { .Expression = payload.error_symbol });348 ast.Node.PrefixOp.Op.NegationWrap,
545 try stack.append(RenderState { .Text = "|"});349 ast.Node.PrefixOp.Op.UnwrapMaybe,
350 ast.Node.PrefixOp.Op.MaybeType,
351 ast.Node.PrefixOp.Op.PointerType => {
352 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.None);
546 },353 },
547 ast.Node.Id.PointerPayload => {
548 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
549 try stack.append(RenderState { .Text = "|"});
550 try stack.append(RenderState { .Expression = payload.value_symbol });
551
552 if (payload.ptr_token) |ptr_token| {
553 try stack.append(RenderState { .Text = tree.tokenSlice(ptr_token) });
554 }
555354
556 try stack.append(RenderState { .Text = "|"});355 ast.Node.PrefixOp.Op.Try,
356 ast.Node.PrefixOp.Op.Await,
357 ast.Node.PrefixOp.Op.Cancel,
358 ast.Node.PrefixOp.Op.Resume => {
359 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.Space);
557 },360 },
558 ast.Node.Id.PointerIndexPayload => {361 }
559 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);362
560 try stack.append(RenderState { .Text = "|"});363 try renderExpression(allocator, stream, tree, indent, prefix_op_node.rhs, space);
364 },
561365
562 if (payload.index_symbol) |index_symbol| {366 ast.Node.Id.SuffixOp => {
563 try stack.append(RenderState { .Expression = index_symbol });367 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
564 try stack.append(RenderState { .Text = ", "});368
369 switch (suffix_op.op) {
370 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
371 if (call_info.async_attr) |async_attr| {
372 try renderExpression(allocator, stream, tree, indent, &async_attr.base, Space.Space);
565 }373 }
566374
567 try stack.append(RenderState { .Expression = payload.value_symbol });375 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
376
377 const lparen = tree.nextToken(suffix_op.lhs.lastToken());
378 try renderToken(tree, stream, lparen, indent, Space.None);
568379
569 if (payload.ptr_token) |ptr_token| {380 var it = call_info.params.iterator(0);
570 try stack.append(RenderState { .Text = tree.tokenSlice(ptr_token) });381 while (it.next()) |param_node| {
382 try renderExpression(allocator, stream, tree, indent, param_node.*, Space.None);
383
384 if (it.peek() != null) {
385 const comma = tree.nextToken(param_node.*.lastToken());
386 try renderToken(tree, stream, comma, indent, Space.Space);
387 }
571 }388 }
572389
573 try stack.append(RenderState { .Text = "|"});390 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
574 },
575 ast.Node.Id.GroupedExpression => {
576 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
577 try stack.append(RenderState { .Text = ")"});
578 try stack.append(RenderState { .Expression = grouped_expr.expr });
579 try stack.append(RenderState { .Text = "("});
580 },
581 ast.Node.Id.FieldInitializer => {
582 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
583 try stream.print(".{} = ", tree.tokenSlice(field_init.name_token));
584 try stack.append(RenderState { .Expression = field_init.expr });
585 },
586 ast.Node.Id.IntegerLiteral => {
587 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
588 try stream.print("{}", tree.tokenSlice(integer_literal.token));
589 },
590 ast.Node.Id.FloatLiteral => {
591 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
592 try stream.print("{}", tree.tokenSlice(float_literal.token));
593 },
594 ast.Node.Id.StringLiteral => {
595 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
596 try stream.print("{}", tree.tokenSlice(string_literal.token));
597 },
598 ast.Node.Id.CharLiteral => {
599 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
600 try stream.print("{}", tree.tokenSlice(char_literal.token));
601 },
602 ast.Node.Id.BoolLiteral => {
603 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
604 try stream.print("{}", tree.tokenSlice(bool_literal.token));
605 },391 },
606 ast.Node.Id.NullLiteral => {392
607 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);393 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
608 try stream.print("{}", tree.tokenSlice(null_literal.token));394 const lbracket = tree.prevToken(index_expr.firstToken());
609 },395 const rbracket = tree.nextToken(index_expr.lastToken());
610 ast.Node.Id.ThisLiteral => {396
611 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);397 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
612 try stream.print("{}", tree.tokenSlice(this_literal.token));398 try renderToken(tree, stream, lbracket, indent, Space.None); // [
613 },399 try renderExpression(allocator, stream, tree, indent, index_expr, Space.None);
614 ast.Node.Id.Unreachable => {400 try renderToken(tree, stream, rbracket, indent, space); // ]
615 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
616 try stream.print("{}", tree.tokenSlice(unreachable_node.token));
617 },
618 ast.Node.Id.ErrorType => {
619 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
620 try stream.print("{}", tree.tokenSlice(error_type.token));
621 },401 },
622 ast.Node.Id.VarType => {402
623 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);403 ast.Node.SuffixOp.Op.Deref => {
624 try stream.print("{}", tree.tokenSlice(var_type.token));404 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
405 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, Space.None); // .
406 try renderToken(tree, stream, suffix_op.rtoken, indent, space); // *
625 },407 },
626 ast.Node.Id.ContainerDecl => {
627 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
628408
629 switch (container_decl.layout) {409 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
630 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),410 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
631 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
632 ast.Node.ContainerDecl.Layout.Auto => { },
633 }
634411
635 switch (container_decl.kind) {412 const lbracket = tree.prevToken(range.start.firstToken());
636 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),413 const dotdot = tree.nextToken(range.start.lastToken());
637 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
638 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
639 }
640414
641 if (container_decl.fields_and_decls.len == 0) {415 try renderToken(tree, stream, lbracket, indent, Space.None); // [
642 try stack.append(RenderState { .Text = "{}"});416 try renderExpression(allocator, stream, tree, indent, range.start, Space.None);
643 } else {417 try renderToken(tree, stream, dotdot, indent, Space.None); // ..
644 try stack.append(RenderState { .Text = "}"});418 if (range.end) |end| {
645 try stack.append(RenderState.PrintIndent);419 try renderExpression(allocator, stream, tree, indent, end, Space.None);
646 try stack.append(RenderState { .Indent = indent });
647 try stack.append(RenderState { .Text = "\n"});
648
649 var i = container_decl.fields_and_decls.len;
650 while (i != 0) {
651 i -= 1;
652 const node = *container_decl.fields_and_decls.at(i);
653 try stack.append(RenderState { .TopLevelDecl = node});
654 try stack.append(RenderState.PrintIndent);
655 try stack.append(RenderState {
656 .Text = blk: {
657 if (i != 0) {
658 const prev_node = *container_decl.fields_and_decls.at(i - 1);
659 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
660 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
661 if (loc.line >= 2) {
662 break :blk "\n\n";
663 }
664 }
665 break :blk "\n";
666 },
667 });
668 }
669 try stack.append(RenderState { .Indent = indent + indent_delta});
670 try stack.append(RenderState { .Text = "{"});
671 }420 }
421 try renderToken(tree, stream, suffix_op.rtoken, indent, space); // ]
422 },
423
424 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
425 const lbrace = tree.nextToken(suffix_op.lhs.lastToken());
672426
673 switch (container_decl.init_arg_expr) {427 if (field_inits.len == 0) {
674 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),428 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
675 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {429 try renderToken(tree, stream, lbrace, indent, Space.None);
676 if (enum_tag_type) |expr| {430 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
677 try stack.append(RenderState { .Text = ")) "});431 return;
678 try stack.append(RenderState { .Expression = expr});
679 try stack.append(RenderState { .Text = "(enum("});
680 } else {
681 try stack.append(RenderState { .Text = "(enum) "});
682 }
683 },
684 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
685 try stack.append(RenderState { .Text = ") "});
686 try stack.append(RenderState { .Expression = type_expr});
687 try stack.append(RenderState { .Text = "("});
688 },
689 }432 }
690 },
691 ast.Node.Id.ErrorSetDecl => {
692 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
693433
694 if (err_set_decl.decls.len == 0) {434 if (field_inits.len == 1) {
695 try stream.write("error{}");435 const field_init = field_inits.at(0).*;
696 continue;436
437 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
438 try renderToken(tree, stream, lbrace, indent, Space.Space);
439 try renderExpression(allocator, stream, tree, indent, field_init, Space.Space);
440 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
441 return;
697 }442 }
698443
699 if (err_set_decl.decls.len == 1) blk: {444 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
700 const node = *err_set_decl.decls.at(0);445 try renderToken(tree, stream, lbrace, indent, Space.Newline);
446
447 const new_indent = indent + indent_delta;
448
449 var it = field_inits.iterator(0);
450 while (it.next()) |field_init| {
451 try stream.writeByteNTimes(' ', new_indent);
452
453 if (it.peek()) |next_field_init| {
454 try renderExpression(allocator, stream, tree, new_indent, field_init.*, Space.None);
701455
702 // if there are any doc comments or same line comments456 const comma = tree.nextToken(field_init.*.lastToken());
703 // don't try to put it all on one line457 try renderToken(tree, stream, comma, new_indent, Space.Newline);
704 if (node.cast(ast.Node.ErrorTag)) |tag| {458
705 if (tag.doc_comments != null) break :blk;459 try renderExtraNewline(tree, stream, next_field_init.*);
706 } else {460 } else {
707 break :blk;461 try renderTrailingComma(allocator, stream, tree, new_indent, field_init.*, Space.Newline);
708 }462 }
463 }
709464
465 try stream.writeByteNTimes(' ', indent);
466 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
467 },
468
469 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
470 const lbrace = tree.nextToken(suffix_op.lhs.lastToken());
710471
711 try stream.write("error{");472 if (exprs.len == 0) {
712 try stack.append(RenderState { .Text = "}" });473 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
713 try stack.append(RenderState { .TopLevelDecl = node });474 try renderToken(tree, stream, lbrace, indent, Space.None);
714 continue;475 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
476 return;
477 }
478 if (exprs.len == 1) {
479 const expr = exprs.at(0).*;
480
481 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
482 try renderToken(tree, stream, lbrace, indent, Space.None);
483 try renderExpression(allocator, stream, tree, indent, expr, Space.None);
484 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
485 return;
715 }486 }
716487
717 try stream.write("error{");488 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
489
490 const new_indent = indent + indent_delta;
491 try renderToken(tree, stream, lbrace, new_indent, Space.Newline);
492
493 var it = exprs.iterator(0);
494 while (it.next()) |expr| {
495 try stream.writeByteNTimes(' ', new_indent);
496
497 if (it.peek()) |next_expr| {
498 try renderExpression(allocator, stream, tree, new_indent, expr.*, Space.None);
718499
719 try stack.append(RenderState { .Text = "}"});500 const comma = tree.nextToken(expr.*.lastToken());
720 try stack.append(RenderState.PrintIndent);501 try renderToken(tree, stream, comma, new_indent, Space.Newline); // ,
721 try stack.append(RenderState { .Indent = indent });
722 try stack.append(RenderState { .Text = "\n"});
723502
724 var i = err_set_decl.decls.len;503 try renderExtraNewline(tree, stream, next_expr.*);
725 while (i != 0) {504 } else {
726 i -= 1;505 try renderTrailingComma(allocator, stream, tree, new_indent, expr.*, Space.Newline);
727 const node = *err_set_decl.decls.at(i);
728 if (node.id != ast.Node.Id.LineComment) {
729 try stack.append(RenderState { .Text = "," });
730 }506 }
731 try stack.append(RenderState { .TopLevelDecl = node });
732 try stack.append(RenderState.PrintIndent);
733 try stack.append(RenderState {
734 .Text = blk: {
735 if (i != 0) {
736 const prev_node = *err_set_decl.decls.at(i - 1);
737 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
738 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
739 if (loc.line >= 2) {
740 break :blk "\n\n";
741 }
742 }
743 break :blk "\n";
744 },
745 });
746 }
747 try stack.append(RenderState { .Indent = indent + indent_delta});
748 },
749 ast.Node.Id.MultilineStringLiteral => {
750 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
751 try stream.print("\n");
752
753 var i : usize = 0;
754 while (i < multiline_str_literal.lines.len) : (i += 1) {
755 const t = *multiline_str_literal.lines.at(i);
756 try stream.writeByteNTimes(' ', indent + indent_delta);
757 try stream.print("{}", tree.tokenSlice(t));
758 }507 }
508
759 try stream.writeByteNTimes(' ', indent);509 try stream.writeByteNTimes(' ', indent);
510 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
760 },511 },
761 ast.Node.Id.UndefinedLiteral => {512 }
762 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);513 },
763 try stream.print("{}", tree.tokenSlice(undefined_literal.token));514
764 },515 ast.Node.Id.ControlFlowExpression => {
765 ast.Node.Id.BuiltinCall => {516 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
766 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);517
767 try stream.print("{}(", tree.tokenSlice(builtin_call.builtin_token));518 switch (flow_expr.kind) {
768 try stack.append(RenderState { .Text = ")"});519 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
769 var i = builtin_call.params.len;520 const kw_space = if (maybe_label != null or flow_expr.rhs != null) Space.Space else space;
770 while (i != 0) {521 try renderToken(tree, stream, flow_expr.ltoken, indent, kw_space);
771 i -= 1;522 if (maybe_label) |label| {
772 const param_node = *builtin_call.params.at(i);523 const colon = tree.nextToken(flow_expr.ltoken);
773 try stack.append(RenderState { .Expression = param_node});524 try renderToken(tree, stream, colon, indent, Space.None);
774 if (i != 0) {525
775 try stack.append(RenderState { .Text = ", " });526 const expr_space = if (flow_expr.rhs != null) Space.Space else space;
776 }527 try renderExpression(allocator, stream, tree, indent, label, expr_space);
777 }528 }
778 },529 },
779 ast.Node.Id.FnProto => {530 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
780 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);531 const kw_space = if (maybe_label != null or flow_expr.rhs != null) Space.Space else space;
781532 try renderToken(tree, stream, flow_expr.ltoken, indent, kw_space);
782 switch (fn_proto.return_type) {533 if (maybe_label) |label| {
783 ast.Node.FnProto.ReturnType.Explicit => |node| {534 const colon = tree.nextToken(flow_expr.ltoken);
784 try stack.append(RenderState { .Expression = node});535 try renderToken(tree, stream, colon, indent, Space.None);
785 },536
786 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {537 const expr_space = if (flow_expr.rhs != null) Space.Space else space;
787 try stack.append(RenderState { .Expression = node});538 try renderExpression(allocator, stream, tree, indent, label, space);
788 try stack.append(RenderState { .Text = "!"});
789 },
790 }539 }
540 },
541 ast.Node.ControlFlowExpression.Kind.Return => {
542 const kw_space = if (flow_expr.rhs != null) Space.Space else space;
543 try renderToken(tree, stream, flow_expr.ltoken, indent, kw_space);
544 },
545 }
791546
792 if (fn_proto.align_expr) |align_expr| {547 if (flow_expr.rhs) |rhs| {
793 try stack.append(RenderState { .Text = ") " });548 try renderExpression(allocator, stream, tree, indent, rhs, space);
794 try stack.append(RenderState { .Expression = align_expr});549 }
795 try stack.append(RenderState { .Text = "align(" });550 },
796 }
797551
798 try stack.append(RenderState { .Text = ") " });552 ast.Node.Id.Payload => {
799 var i = fn_proto.params.len;553 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
800 while (i != 0) {
801 i -= 1;
802 const param_decl_node = *fn_proto.params.at(i);
803 try stack.append(RenderState { .ParamDecl = param_decl_node});
804 if (i != 0) {
805 try stack.append(RenderState { .Text = ", " });
806 }
807 }
808554
809 try stack.append(RenderState { .Text = "(" });555 try renderToken(tree, stream, payload.lpipe, indent, Space.None);
810 if (fn_proto.name_token) |name_token| {556 try renderExpression(allocator, stream, tree, indent, payload.error_symbol, Space.None);
811 try stack.append(RenderState { .Text = tree.tokenSlice(name_token) });557 try renderToken(tree, stream, payload.rpipe, indent, space);
812 try stack.append(RenderState { .Text = " " });558 },
813 }
814559
815 try stack.append(RenderState { .Text = "fn" });560 ast.Node.Id.PointerPayload => {
561 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
816562
817 if (fn_proto.async_attr) |async_attr| {563 try renderToken(tree, stream, payload.lpipe, indent, Space.None);
818 try stack.append(RenderState { .Text = " " });564 if (payload.ptr_token) |ptr_token| {
819 try stack.append(RenderState { .Expression = &async_attr.base });565 try renderToken(tree, stream, ptr_token, indent, Space.None);
820 }566 }
567 try renderExpression(allocator, stream, tree, indent, payload.value_symbol, Space.None);
568 try renderToken(tree, stream, payload.rpipe, indent, space);
569 },
821570
822 if (fn_proto.cc_token) |cc_token| {571 ast.Node.Id.PointerIndexPayload => {
823 try stack.append(RenderState { .Text = " " });572 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
824 try stack.append(RenderState { .Text = tree.tokenSlice(cc_token) });
825 }
826573
827 if (fn_proto.lib_name) |lib_name| {574 try renderToken(tree, stream, payload.lpipe, indent, Space.None);
828 try stack.append(RenderState { .Text = " " });575 if (payload.ptr_token) |ptr_token| {
829 try stack.append(RenderState { .Expression = lib_name });576 try renderToken(tree, stream, ptr_token, indent, Space.None);
830 }577 }
831 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {578 try renderExpression(allocator, stream, tree, indent, payload.value_symbol, Space.None);
832 try stack.append(RenderState { .Text = " " });
833 try stack.append(RenderState { .Text = tree.tokenSlice(extern_export_inline_token) });
834 }
835579
836 if (fn_proto.visib_token) |visib_token_index| {580 if (payload.index_symbol) |index_symbol| {
837 const visib_token = tree.tokens.at(visib_token_index);581 const comma = tree.nextToken(payload.value_symbol.lastToken());
838 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);582
839 try stack.append(RenderState { .Text = " " });583 try renderToken(tree, stream, comma, indent, Space.Space);
840 try stack.append(RenderState { .Text = tree.tokenSlice(visib_token_index) });584 try renderExpression(allocator, stream, tree, indent, index_symbol, Space.None);
841 }585 }
586
587 try renderToken(tree, stream, payload.rpipe, indent, space);
588 },
589
590 ast.Node.Id.GroupedExpression => {
591 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
592
593 try renderToken(tree, stream, grouped_expr.lparen, indent, Space.None);
594 try renderExpression(allocator, stream, tree, indent, grouped_expr.expr, Space.None);
595 try renderToken(tree, stream, grouped_expr.rparen, indent, space);
596 },
597
598 ast.Node.Id.FieldInitializer => {
599 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
600
601 try renderToken(tree, stream, field_init.period_token, indent, Space.None); // .
602 try renderToken(tree, stream, field_init.name_token, indent, Space.Space); // name
603 try renderToken(tree, stream, tree.nextToken(field_init.name_token), indent, Space.Space); // =
604 try renderExpression(allocator, stream, tree, indent, field_init.expr, space);
605 },
606
607 ast.Node.Id.IntegerLiteral => {
608 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
609 try renderToken(tree, stream, integer_literal.token, indent, space);
610 },
611 ast.Node.Id.FloatLiteral => {
612 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
613 try renderToken(tree, stream, float_literal.token, indent, space);
614 },
615 ast.Node.Id.StringLiteral => {
616 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
617 try renderToken(tree, stream, string_literal.token, indent, space);
618 },
619 ast.Node.Id.CharLiteral => {
620 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
621 try renderToken(tree, stream, char_literal.token, indent, space);
622 },
623 ast.Node.Id.BoolLiteral => {
624 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
625 try renderToken(tree, stream, bool_literal.token, indent, space);
626 },
627 ast.Node.Id.NullLiteral => {
628 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
629 try renderToken(tree, stream, null_literal.token, indent, space);
630 },
631 ast.Node.Id.ThisLiteral => {
632 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
633 try renderToken(tree, stream, this_literal.token, indent, space);
634 },
635 ast.Node.Id.Unreachable => {
636 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
637 try renderToken(tree, stream, unreachable_node.token, indent, space);
638 },
639 ast.Node.Id.ErrorType => {
640 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
641 try renderToken(tree, stream, error_type.token, indent, space);
642 },
643 ast.Node.Id.VarType => {
644 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
645 try renderToken(tree, stream, var_type.token, indent, space);
646 },
647 ast.Node.Id.ContainerDecl => {
648 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
649
650 if (container_decl.layout_token) |layout_token| {
651 try renderToken(tree, stream, layout_token, indent, Space.Space);
652 }
653
654 switch (container_decl.init_arg_expr) {
655 ast.Node.ContainerDecl.InitArg.None => {
656 try renderToken(tree, stream, container_decl.kind_token, indent, Space.Space); // union
842 },657 },
843 ast.Node.Id.PromiseType => {658 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
844 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);659 try renderToken(tree, stream, container_decl.kind_token, indent, Space.None); // union
845 try stream.write(tree.tokenSlice(promise_type.promise_token));660
846 if (promise_type.result) |result| {661 const lparen = tree.nextToken(container_decl.kind_token);
847 try stream.write(tree.tokenSlice(result.arrow_token));662 const enum_token = tree.nextToken(lparen);
848 try stack.append(RenderState { .Expression = result.return_type});663
664 try renderToken(tree, stream, lparen, indent, Space.None); // (
665 try renderToken(tree, stream, enum_token, indent, Space.None); // enum
666
667 if (enum_tag_type) |expr| {
668 try renderToken(tree, stream, tree.nextToken(enum_token), indent, Space.None); // (
669 try renderExpression(allocator, stream, tree, indent, expr, Space.None);
670
671 const rparen = tree.nextToken(expr.lastToken());
672 try renderToken(tree, stream, rparen, indent, Space.None); // )
673 try renderToken(tree, stream, tree.nextToken(rparen), indent, Space.Space); // )
674 } else {
675 try renderToken(tree, stream, tree.nextToken(enum_token), indent, Space.Space); // )
849 }676 }
850 },677 },
851 ast.Node.Id.LineComment => {678 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
852 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);679 try renderToken(tree, stream, container_decl.kind_token, indent, Space.None); // union
853 try stream.write(tree.tokenSlice(line_comment_node.token));680
681 const lparen = tree.nextToken(container_decl.kind_token);
682 const rparen = tree.nextToken(type_expr.lastToken());
683
684 try renderToken(tree, stream, lparen, indent, Space.None); // (
685 try renderExpression(allocator, stream, tree, indent, type_expr, Space.None);
686 try renderToken(tree, stream, rparen, indent, Space.Space); // )
854 },687 },
855 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes688 }
856 ast.Node.Id.Switch => {
857 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
858689
859 try stream.print("{} (", tree.tokenSlice(switch_node.switch_token));690 if (container_decl.fields_and_decls.len == 0) {
691 try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, Space.None); // {
692 try renderToken(tree, stream, container_decl.rbrace_token, indent, space); // }
693 } else {
694 const new_indent = indent + indent_delta;
695 try renderToken(tree, stream, container_decl.lbrace_token, new_indent, Space.Newline); // {
860696
861 if (switch_node.cases.len == 0) {697 var it = container_decl.fields_and_decls.iterator(0);
862 try stack.append(RenderState { .Text = ") {}"});698 while (it.next()) |decl| {
863 try stack.append(RenderState { .Expression = switch_node.expr });699 try stream.writeByteNTimes(' ', new_indent);
864 continue;700 try renderTopLevelDecl(allocator, stream, tree, new_indent, decl.*);
865 }
866701
867 try stack.append(RenderState { .Text = "}"});702 if (it.peek()) |next_decl| {
868 try stack.append(RenderState.PrintIndent);703 try renderExtraNewline(tree, stream, next_decl.*);
869 try stack.append(RenderState { .Indent = indent });
870 try stack.append(RenderState { .Text = "\n"});
871
872 var i = switch_node.cases.len;
873 while (i != 0) {
874 i -= 1;
875 const node = *switch_node.cases.at(i);
876 try stack.append(RenderState { .Expression = node});
877 try stack.append(RenderState.PrintIndent);
878 try stack.append(RenderState {
879 .Text = blk: {
880 if (i != 0) {
881 const prev_node = *switch_node.cases.at(i - 1);
882 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
883 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
884 if (loc.line >= 2) {
885 break :blk "\n\n";
886 }
887 }
888 break :blk "\n";
889 },
890 });
891 }704 }
892 try stack.append(RenderState { .Indent = indent + indent_delta});705 }
893 try stack.append(RenderState { .Text = ") {"});
894 try stack.append(RenderState { .Expression = switch_node.expr });
895 },
896 ast.Node.Id.SwitchCase => {
897 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
898
899 try stack.append(RenderState { .Token = switch_case.lastToken() + 1 });
900 try stack.append(RenderState { .Expression = switch_case.expr });
901 if (switch_case.payload) |payload| {
902 try stack.append(RenderState { .Text = " " });
903 try stack.append(RenderState { .Expression = payload });
904 }
905 try stack.append(RenderState { .Text = " => "});
906706
907 var i = switch_case.items.len;707 try stream.writeByteNTimes(' ', indent);
908 while (i != 0) {708 try renderToken(tree, stream, container_decl.rbrace_token, indent, space); // }
909 i -= 1;709 }
910 try stack.append(RenderState { .Expression = *switch_case.items.at(i) });710 },
911711
912 if (i != 0) {712 ast.Node.Id.ErrorSetDecl => {
913 try stack.append(RenderState.PrintIndent);713 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
914 try stack.append(RenderState { .Text = ",\n" });714
915 }715 const lbrace = tree.nextToken(err_set_decl.error_token);
916 }716
717 if (err_set_decl.decls.len == 0) {
718 try renderToken(tree, stream, err_set_decl.error_token, indent, Space.None);
719 try renderToken(tree, stream, lbrace, indent, Space.None);
720 try renderToken(tree, stream, err_set_decl.rbrace_token, indent, space);
721 return;
722 }
723
724 if (err_set_decl.decls.len == 1) blk: {
725 const node = err_set_decl.decls.at(0).*;
726
727 // if there are any doc comments or same line comments
728 // don't try to put it all on one line
729 if (node.cast(ast.Node.ErrorTag)) |tag| {
730 if (tag.doc_comments != null) break :blk;
731 } else {
732 break :blk;
733 }
734
735 try renderToken(tree, stream, err_set_decl.error_token, indent, Space.None); // error
736 try renderToken(tree, stream, lbrace, indent, Space.None); // {
737 try renderExpression(allocator, stream, tree, indent, node, Space.None);
738 try renderToken(tree, stream, err_set_decl.rbrace_token, indent, space); // }
739 return;
740 }
741
742 try renderToken(tree, stream, err_set_decl.error_token, indent, Space.None); // error
743 try renderToken(tree, stream, lbrace, indent, Space.Newline); // {
744 const new_indent = indent + indent_delta;
745
746 var it = err_set_decl.decls.iterator(0);
747 while (it.next()) |node| {
748 try stream.writeByteNTimes(' ', new_indent);
749
750 if (it.peek()) |next_node| {
751 try renderExpression(allocator, stream, tree, new_indent, node.*, Space.None);
752 try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, Space.Newline); // ,
753
754 try renderExtraNewline(tree, stream, next_node.*);
755 } else {
756 try renderTrailingComma(allocator, stream, tree, new_indent, node.*, Space.Newline);
757 }
758 }
759
760 try stream.writeByteNTimes(' ', indent);
761 try renderToken(tree, stream, err_set_decl.rbrace_token, indent, space); // }
762 },
763
764 ast.Node.Id.ErrorTag => {
765 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
766
767 try renderDocComments(tree, stream, tag, indent);
768 try renderToken(tree, stream, tag.name_token, indent, space); // name
769 },
770
771 ast.Node.Id.MultilineStringLiteral => {
772 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
773
774 var skip_first_indent = true;
775 if (tree.tokens.at(multiline_str_literal.firstToken() - 1).id != Token.Id.LineComment) {
776 try stream.print("\n");
777 skip_first_indent = false;
778 }
779
780 var i: usize = 0;
781 while (i < multiline_str_literal.lines.len) : (i += 1) {
782 const t = multiline_str_literal.lines.at(i).*;
783 if (!skip_first_indent) {
784 try stream.writeByteNTimes(' ', indent + indent_delta);
785 }
786 try renderToken(tree, stream, t, indent, Space.None);
787 skip_first_indent = false;
788 }
789 try stream.writeByteNTimes(' ', indent);
790 },
791 ast.Node.Id.UndefinedLiteral => {
792 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
793 try renderToken(tree, stream, undefined_literal.token, indent, space);
794 },
795
796 ast.Node.Id.BuiltinCall => {
797 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
798
799 try renderToken(tree, stream, builtin_call.builtin_token, indent, Space.None); // @name
800 try renderToken(tree, stream, tree.nextToken(builtin_call.builtin_token), indent, Space.None); // (
801
802 var it = builtin_call.params.iterator(0);
803 while (it.next()) |param_node| {
804 try renderExpression(allocator, stream, tree, indent, param_node.*, Space.None);
805
806 if (it.peek() != null) {
807 const comma_token = tree.nextToken(param_node.*.lastToken());
808 try renderToken(tree, stream, comma_token, indent, Space.Space); // ,
809 }
810 }
811 try renderToken(tree, stream, builtin_call.rparen_token, indent, space); // )
812 },
813
814 ast.Node.Id.FnProto => {
815 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
816
817 if (fn_proto.visib_token) |visib_token_index| {
818 const visib_token = tree.tokens.at(visib_token_index);
819 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
820
821 try renderToken(tree, stream, visib_token_index, indent, Space.Space); // pub
822 }
823
824 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
825 try renderToken(tree, stream, extern_export_inline_token, indent, Space.Space); // extern/export
826 }
827
828 if (fn_proto.lib_name) |lib_name| {
829 try renderExpression(allocator, stream, tree, indent, lib_name, Space.Space);
830 }
831
832 if (fn_proto.cc_token) |cc_token| {
833 try renderToken(tree, stream, cc_token, indent, Space.Space); // stdcallcc
834 }
835
836 if (fn_proto.async_attr) |async_attr| {
837 try renderExpression(allocator, stream, tree, indent, &async_attr.base, Space.Space);
838 }
839
840 if (fn_proto.name_token) |name_token| blk: {
841 try renderToken(tree, stream, fn_proto.fn_token, indent, Space.Space); // fn
842 try renderToken(tree, stream, name_token, indent, Space.None); // name
843 try renderToken(tree, stream, tree.nextToken(name_token), indent, Space.None); // (
844 } else blk: {
845 try renderToken(tree, stream, fn_proto.fn_token, indent, Space.None); // fn
846 try renderToken(tree, stream, tree.nextToken(fn_proto.fn_token), indent, Space.None); // (
847 }
848
849 var it = fn_proto.params.iterator(0);
850 while (it.next()) |param_decl_node| {
851 try renderParamDecl(allocator, stream, tree, indent, param_decl_node.*);
852
853 if (it.peek() != null) {
854 const comma = tree.nextToken(param_decl_node.*.lastToken());
855 try renderToken(tree, stream, comma, indent, Space.Space); // ,
856 }
857 }
858
859 const rparen = tree.prevToken(switch (fn_proto.return_type) {
860 ast.Node.FnProto.ReturnType.Explicit => |node| node.firstToken(),
861 ast.Node.FnProto.ReturnType.InferErrorSet => |node| tree.prevToken(node.firstToken()),
862 });
863 try renderToken(tree, stream, rparen, indent, Space.Space); // )
864
865 if (fn_proto.align_expr) |align_expr| {
866 const align_rparen = tree.nextToken(align_expr.lastToken());
867 const align_lparen = tree.prevToken(align_expr.firstToken());
868 const align_kw = tree.prevToken(align_lparen);
869
870 try renderToken(tree, stream, align_kw, indent, Space.None); // align
871 try renderToken(tree, stream, align_lparen, indent, Space.None); // (
872 try renderExpression(allocator, stream, tree, indent, align_expr, Space.None);
873 try renderToken(tree, stream, align_rparen, indent, Space.Space); // )
874 }
875
876 switch (fn_proto.return_type) {
877 ast.Node.FnProto.ReturnType.Explicit => |node| {
878 try renderExpression(allocator, stream, tree, indent, node, space);
917 },879 },
918 ast.Node.Id.SwitchElse => {880 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
919 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);881 try renderToken(tree, stream, tree.prevToken(node.firstToken()), indent, Space.None); // !
920 try stream.print("{}", tree.tokenSlice(switch_else.token));882 try renderExpression(allocator, stream, tree, indent, node, space);
921 },883 },
922 ast.Node.Id.Else => {884 }
923 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);885 },
924 try stream.print("{}", tree.tokenSlice(else_node.else_token));886
925887 ast.Node.Id.PromiseType => {
926 switch (else_node.body.id) {888 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
927 ast.Node.Id.Block, ast.Node.Id.If,889
928 ast.Node.Id.For, ast.Node.Id.While,890 if (promise_type.result) |result| {
929 ast.Node.Id.Switch => {891 try renderToken(tree, stream, promise_type.promise_token, indent, Space.None); // promise
930 try stream.print(" ");892 try renderToken(tree, stream, result.arrow_token, indent, Space.None); // ->
931 try stack.append(RenderState { .Expression = else_node.body });893 try renderExpression(allocator, stream, tree, indent, result.return_type, space);
932 },894 } else {
933 else => {895 try renderToken(tree, stream, promise_type.promise_token, indent, space); // promise
934 try stack.append(RenderState { .Indent = indent });896 }
935 try stack.append(RenderState { .Expression = else_node.body });897 },
936 try stack.append(RenderState.PrintIndent);898
937 try stack.append(RenderState { .Indent = indent + indent_delta });899 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
938 try stack.append(RenderState { .Text = "\n" });900
939 }901 ast.Node.Id.Switch => {
940 }902 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
903
904 try renderToken(tree, stream, switch_node.switch_token, indent, Space.Space); // switch
905 try renderToken(tree, stream, tree.nextToken(switch_node.switch_token), indent, Space.None); // (
906
907 const rparen = tree.nextToken(switch_node.expr.lastToken());
908 const lbrace = tree.nextToken(rparen);
909
910 if (switch_node.cases.len == 0) {
911 try renderExpression(allocator, stream, tree, indent, switch_node.expr, Space.None);
912 try renderToken(tree, stream, rparen, indent, Space.Space); // )
913 try renderToken(tree, stream, lbrace, indent, Space.None); // {
914 try renderToken(tree, stream, switch_node.rbrace, indent, space); // }
915 return;
916 }
917
918 try renderExpression(allocator, stream, tree, indent, switch_node.expr, Space.None);
919
920 try renderToken(tree, stream, rparen, indent, Space.Space); // )
921 try renderToken(tree, stream, lbrace, indent, Space.Newline); // {
922
923 const new_indent = indent + indent_delta;
924
925 var it = switch_node.cases.iterator(0);
926 while (it.next()) |node| {
927 try stream.writeByteNTimes(' ', new_indent);
928 try renderExpression(allocator, stream, tree, new_indent, node.*, Space.Newline);
941929
942 if (else_node.payload) |payload| {930 if (it.peek()) |next_node| {
943 try stack.append(RenderState { .Text = " " });931 try renderExtraNewline(tree, stream, next_node.*);
944 try stack.append(RenderState { .Expression = payload });932 }
933 }
934
935 try stream.writeByteNTimes(' ', indent);
936 try renderToken(tree, stream, switch_node.rbrace, indent, space); // }
937 },
938
939 ast.Node.Id.SwitchCase => {
940 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
941
942 assert(switch_case.items.len != 0);
943 const src_has_trailing_comma = blk: {
944 const last_node = switch_case.items.at(switch_case.items.len - 1).*;
945 const maybe_comma = tree.nextToken(last_node.lastToken());
946 break :blk tree.tokens.at(maybe_comma).id == Token.Id.Comma;
947 };
948
949 if (switch_case.items.len == 1 or !src_has_trailing_comma) {
950 var it = switch_case.items.iterator(0);
951 while (it.next()) |node| {
952 if (it.peek()) |next_node| {
953 try renderExpression(allocator, stream, tree, indent, node.*, Space.None);
954
955 const comma_token = tree.nextToken(node.*.lastToken());
956 try renderToken(tree, stream, comma_token, indent, Space.Space); // ,
957 try renderExtraNewline(tree, stream, next_node.*);
958 } else {
959 try renderExpression(allocator, stream, tree, indent, node.*, Space.Space);
945 }960 }
946 },961 }
947 ast.Node.Id.While => {962 } else {
948 const while_node = @fieldParentPtr(ast.Node.While, "base", base);963 var it = switch_case.items.iterator(0);
949 if (while_node.label) |label| {964 while (true) {
950 try stream.print("{}: ", tree.tokenSlice(label));965 const node = ??it.next();
966 if (it.peek()) |next_node| {
967 try renderExpression(allocator, stream, tree, indent, node.*, Space.None);
968
969 const comma_token = tree.nextToken(node.*.lastToken());
970 try renderToken(tree, stream, comma_token, indent, Space.Newline); // ,
971 try renderExtraNewline(tree, stream, next_node.*);
972 try stream.writeByteNTimes(' ', indent);
973 } else {
974 try renderTrailingComma(allocator, stream, tree, indent, node.*, Space.Space);
975 break;
951 }976 }
977 }
978 }
952979
953 if (while_node.inline_token) |inline_token| {980 try renderToken(tree, stream, switch_case.arrow_token, indent, Space.Space); // =>
954 try stream.print("{} ", tree.tokenSlice(inline_token));
955 }
956981
957 try stream.print("{} ", tree.tokenSlice(while_node.while_token));982 if (switch_case.payload) |payload| {
983 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
984 }
958985
959 if (while_node.@"else") |@"else"| {986 try renderTrailingComma(allocator, stream, tree, indent, switch_case.expr, space);
960 try stack.append(RenderState { .Expression = &@"else".base });987 },
988 ast.Node.Id.SwitchElse => {
989 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
990 try renderToken(tree, stream, switch_else.token, indent, space);
991 },
992 ast.Node.Id.Else => {
993 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
994
995 const block_body = switch (else_node.body.id) {
996 ast.Node.Id.Block,
997 ast.Node.Id.If,
998 ast.Node.Id.For,
999 ast.Node.Id.While,
1000 ast.Node.Id.Switch => true,
1001 else => false,
1002 };
1003
1004 const after_else_space = if (block_body or else_node.payload != null) Space.Space else Space.Newline;
1005 try renderToken(tree, stream, else_node.else_token, indent, after_else_space);
1006
1007 if (else_node.payload) |payload| {
1008 const payload_space = if (block_body) Space.Space else Space.Newline;
1009 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
1010 }
9611011
962 if (while_node.body.id == ast.Node.Id.Block) {1012 if (block_body) {
963 try stack.append(RenderState { .Text = " " });1013 try renderExpression(allocator, stream, tree, indent, else_node.body, space);
964 } else {1014 } else {
965 try stack.append(RenderState.PrintIndent);1015 try stream.writeByteNTimes(' ', indent + indent_delta);
966 try stack.append(RenderState { .Text = "\n" });1016 try renderExpression(allocator, stream, tree, indent, else_node.body, space);
967 }1017 }
968 }1018 },
1019
1020 ast.Node.Id.While => {
1021 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
1022
1023 if (while_node.label) |label| {
1024 try renderToken(tree, stream, label, indent, Space.None); // label
1025 try renderToken(tree, stream, tree.nextToken(label), indent, Space.Space); // :
1026 }
1027
1028 if (while_node.inline_token) |inline_token| {
1029 try renderToken(tree, stream, inline_token, indent, Space.Space); // inline
1030 }
1031
1032 try renderToken(tree, stream, while_node.while_token, indent, Space.Space); // while
1033 try renderToken(tree, stream, tree.nextToken(while_node.while_token), indent, Space.None); // (
1034 try renderExpression(allocator, stream, tree, indent, while_node.condition, Space.None);
1035
1036 {
1037 const rparen = tree.nextToken(while_node.condition.lastToken());
1038 const rparen_space = if (while_node.payload != null or while_node.continue_expr != null or
1039 while_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1040 try renderToken(tree, stream, rparen, indent, rparen_space); // )
1041 }
1042
1043 if (while_node.payload) |payload| {
1044 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
1045 }
1046
1047 if (while_node.continue_expr) |continue_expr| {
1048 const rparen = tree.nextToken(continue_expr.lastToken());
1049 const lparen = tree.prevToken(continue_expr.firstToken());
1050 const colon = tree.prevToken(lparen);
1051
1052 try renderToken(tree, stream, colon, indent, Space.Space); // :
1053 try renderToken(tree, stream, lparen, indent, Space.None); // (
1054
1055 try renderExpression(allocator, stream, tree, indent, continue_expr, Space.None);
1056
1057 const rparen_space = if (while_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1058 try renderToken(tree, stream, rparen, indent, rparen_space); // )
1059 }
1060
1061 const body_space = blk: {
1062 if (while_node.@"else" != null) {
1063 break :blk if (while_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1064 } else {
1065 break :blk space;
1066 }
1067 };
1068
1069 if (while_node.body.id == ast.Node.Id.Block) {
1070 try renderExpression(allocator, stream, tree, indent, while_node.body, body_space);
1071 } else {
1072 try stream.writeByteNTimes(' ', indent + indent_delta);
1073 try renderExpression(allocator, stream, tree, indent, while_node.body, body_space);
1074 }
1075
1076 if (while_node.@"else") |@"else"| {
1077 if (while_node.body.id == ast.Node.Id.Block) {
1078 } else {
1079 try stream.writeByteNTimes(' ', indent);
1080 }
1081
1082 try renderExpression(allocator, stream, tree, indent, &@"else".base, space);
1083 }
1084 },
1085
1086 ast.Node.Id.For => {
1087 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
1088
1089 if (for_node.label) |label| {
1090 try renderToken(tree, stream, label, indent, Space.None); // label
1091 try renderToken(tree, stream, tree.nextToken(label), indent, Space.Space); // :
1092 }
1093
1094 if (for_node.inline_token) |inline_token| {
1095 try renderToken(tree, stream, inline_token, indent, Space.Space); // inline
1096 }
1097
1098 try renderToken(tree, stream, for_node.for_token, indent, Space.Space); // for
1099 try renderToken(tree, stream, tree.nextToken(for_node.for_token), indent, Space.None); // (
1100 try renderExpression(allocator, stream, tree, indent, for_node.array_expr, Space.None);
9691101
970 if (while_node.body.id == ast.Node.Id.Block) {1102 const rparen = tree.nextToken(for_node.array_expr.lastToken());
971 try stack.append(RenderState { .Expression = while_node.body });1103 const rparen_space = if (for_node.payload != null or
972 try stack.append(RenderState { .Text = " " });1104 for_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1105 try renderToken(tree, stream, rparen, indent, rparen_space); // )
1106
1107 if (for_node.payload) |payload| {
1108 const payload_space = if (for_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1109 try renderExpression(allocator, stream, tree, indent, payload, payload_space);
1110 }
1111
1112 const body_space = blk: {
1113 if (for_node.@"else" != null) {
1114 if (for_node.body.id == ast.Node.Id.Block) {
1115 break :blk Space.Space;
973 } else {1116 } else {
974 try stack.append(RenderState { .Indent = indent });1117 break :blk Space.Newline;
975 try stack.append(RenderState { .Expression = while_node.body });
976 try stack.append(RenderState.PrintIndent);
977 try stack.append(RenderState { .Indent = indent + indent_delta });
978 try stack.append(RenderState { .Text = "\n" });
979 }1118 }
1119 } else {
1120 break :blk space;
1121 }
1122 };
1123 if (for_node.body.id == ast.Node.Id.Block) {
1124 try renderExpression(allocator, stream, tree, indent, for_node.body, body_space);
1125 } else {
1126 try stream.writeByteNTimes(' ', indent + indent_delta);
1127 try renderExpression(allocator, stream, tree, indent, for_node.body, body_space);
1128 }
9801129
981 if (while_node.continue_expr) |continue_expr| {1130 if (for_node.@"else") |@"else"| {
982 try stack.append(RenderState { .Text = ")" });1131 if (for_node.body.id != ast.Node.Id.Block) {
983 try stack.append(RenderState { .Expression = continue_expr });1132 try stream.writeByteNTimes(' ', indent);
984 try stack.append(RenderState { .Text = ": (" });1133 }
985 try stack.append(RenderState { .Text = " " });
986 }
9871134
988 if (while_node.payload) |payload| {1135 try renderExpression(allocator, stream, tree, indent, &@"else".base, space);
989 try stack.append(RenderState { .Expression = payload });1136 }
990 try stack.append(RenderState { .Text = " " });1137 },
991 }
9921138
993 try stack.append(RenderState { .Text = ")" });1139 ast.Node.Id.If => {
994 try stack.append(RenderState { .Expression = while_node.condition });1140 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
995 try stack.append(RenderState { .Text = "(" });
996 },
997 ast.Node.Id.For => {
998 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
999 if (for_node.label) |label| {
1000 try stream.print("{}: ", tree.tokenSlice(label));
1001 }
10021141
1003 if (for_node.inline_token) |inline_token| {1142 try renderToken(tree, stream, if_node.if_token, indent, Space.Space);
1004 try stream.print("{} ", tree.tokenSlice(inline_token));1143 try renderToken(tree, stream, tree.prevToken(if_node.condition.firstToken()), indent, Space.None);
1005 }
10061144
1007 try stream.print("{} ", tree.tokenSlice(for_node.for_token));1145 try renderExpression(allocator, stream, tree, indent, if_node.condition, Space.None);
1146 try renderToken(tree, stream, tree.nextToken(if_node.condition.lastToken()), indent, Space.Space);
10081147
1009 if (for_node.@"else") |@"else"| {1148 if (if_node.payload) |payload| {
1010 try stack.append(RenderState { .Expression = &@"else".base });1149 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
1150 }
10111151
1012 if (for_node.body.id == ast.Node.Id.Block) {1152 switch (if_node.body.id) {
1013 try stack.append(RenderState { .Text = " " });1153 ast.Node.Id.Block,
1154 ast.Node.Id.If,
1155 ast.Node.Id.For,
1156 ast.Node.Id.While,
1157 ast.Node.Id.Switch => {
1158 if (if_node.@"else") |@"else"| {
1159 if (if_node.body.id == ast.Node.Id.Block) {
1160 try renderExpression(allocator, stream, tree, indent, if_node.body, Space.Space);
1014 } else {1161 } else {
1015 try stack.append(RenderState.PrintIndent);1162 try renderExpression(allocator, stream, tree, indent, if_node.body, Space.Newline);
1016 try stack.append(RenderState { .Text = "\n" });1163 try stream.writeByteNTimes(' ', indent);
1017 }1164 }
1018 }
10191165
1020 if (for_node.body.id == ast.Node.Id.Block) {1166 try renderExpression(allocator, stream, tree, indent, &@"else".base, space);
1021 try stack.append(RenderState { .Expression = for_node.body });
1022 try stack.append(RenderState { .Text = " " });
1023 } else {1167 } else {
1024 try stack.append(RenderState { .Indent = indent });1168 try renderExpression(allocator, stream, tree, indent, if_node.body, space);
1025 try stack.append(RenderState { .Expression = for_node.body });
1026 try stack.append(RenderState.PrintIndent);
1027 try stack.append(RenderState { .Indent = indent + indent_delta });
1028 try stack.append(RenderState { .Text = "\n" });
1029 }1169 }
1030
1031 if (for_node.payload) |payload| {
1032 try stack.append(RenderState { .Expression = payload });
1033 try stack.append(RenderState { .Text = " " });
1034 }
1035
1036 try stack.append(RenderState { .Text = ")" });
1037 try stack.append(RenderState { .Expression = for_node.array_expr });
1038 try stack.append(RenderState { .Text = "(" });
1039 },1170 },
1040 ast.Node.Id.If => {1171 else => {
1041 const if_node = @fieldParentPtr(ast.Node.If, "base", base);1172 if (if_node.@"else") |@"else"| {
1042 try stream.print("{} ", tree.tokenSlice(if_node.if_token));1173 try renderExpression(allocator, stream, tree, indent, if_node.body, Space.Space);
10431174 try renderToken(tree, stream, @"else".else_token, indent, Space.Space);
1044 switch (if_node.body.id) {1175
1045 ast.Node.Id.Block, ast.Node.Id.If,1176 if (@"else".payload) |payload| {
1046 ast.Node.Id.For, ast.Node.Id.While,1177 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
1047 ast.Node.Id.Switch => {
1048 if (if_node.@"else") |@"else"| {
1049 try stack.append(RenderState { .Expression = &@"else".base });
1050
1051 if (if_node.body.id == ast.Node.Id.Block) {
1052 try stack.append(RenderState { .Text = " " });
1053 } else {
1054 try stack.append(RenderState.PrintIndent);
1055 try stack.append(RenderState { .Text = "\n" });
1056 }
1057 }
1058 },
1059 else => {
1060 if (if_node.@"else") |@"else"| {
1061 try stack.append(RenderState { .Expression = @"else".body });
1062
1063 if (@"else".payload) |payload| {
1064 try stack.append(RenderState { .Text = " " });
1065 try stack.append(RenderState { .Expression = payload });
1066 }
1067
1068 try stack.append(RenderState { .Text = " " });
1069 try stack.append(RenderState { .Text = tree.tokenSlice(@"else".else_token) });
1070 try stack.append(RenderState { .Text = " " });
1071 }
1072 }1178 }
1179
1180 try renderExpression(allocator, stream, tree, indent, @"else".body, space);
1181 } else {
1182 try renderExpression(allocator, stream, tree, indent, if_node.body, space);
1073 }1183 }
1184 },
1185 }
1186 },
10741187
1075 try stack.append(RenderState { .Expression = if_node.body });1188 ast.Node.Id.Asm => {
1189 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
10761190
1077 if (if_node.payload) |payload| {1191 try renderToken(tree, stream, asm_node.asm_token, indent, Space.Space); // asm
1078 try stack.append(RenderState { .Text = " " });
1079 try stack.append(RenderState { .Expression = payload });
1080 }
10811192
1082 try stack.append(RenderState { .NonBreakToken = if_node.condition.lastToken() + 1 });1193 if (asm_node.volatile_token) |volatile_token| {
1083 try stack.append(RenderState { .Expression = if_node.condition });1194 try renderToken(tree, stream, volatile_token, indent, Space.Space); // volatile
1084 try stack.append(RenderState { .Text = "(" });1195 try renderToken(tree, stream, tree.nextToken(volatile_token), indent, Space.None); // (
1085 },1196 } else {
1086 ast.Node.Id.Asm => {1197 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, Space.None); // (
1087 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);1198 }
1088 try stream.print("{} ", tree.tokenSlice(asm_node.asm_token));
10891199
1090 if (asm_node.volatile_token) |volatile_token| {1200 try renderExpression(allocator, stream, tree, indent, asm_node.template, Space.Newline);
1091 try stream.print("{} ", tree.tokenSlice(volatile_token));1201 const indent_once = indent + indent_delta;
1092 }1202 try stream.writeByteNTimes(' ', indent_once);
1203 try stream.print(": ");
1204 const indent_extra = indent_once + 2;
10931205
1094 try stack.append(RenderState { .Indent = indent });1206 {
1095 try stack.append(RenderState { .Text = ")" });1207 var it = asm_node.outputs.iterator(0);
1096 {1208 while (it.next()) |asm_output| {
1097 var i = asm_node.clobbers.len;1209 const node = &(asm_output.*).base;
1098 while (i != 0) {1210 try renderExpression(allocator, stream, tree, indent_extra, node, Space.None);
1099 i -= 1;1211
1100 try stack.append(RenderState { .Expression = *asm_node.clobbers.at(i) });1212 if (it.peek()) |next_asm_output| {
11011213 const next_node = &(next_asm_output.*).base;
1102 if (i != 0) {1214
1103 try stack.append(RenderState { .Text = ", " });1215 const comma = tree.prevToken(next_asm_output.*.firstToken());
1104 }1216 try renderToken(tree, stream, comma, indent_extra, Space.Newline); // ,
1105 }1217 try renderExtraNewline(tree, stream, next_node);
1218
1219 try stream.writeByteNTimes(' ', indent_extra);
1106 }1220 }
1107 try stack.append(RenderState { .Text = ": " });1221 }
1108 try stack.append(RenderState.PrintIndent);1222 }
1109 try stack.append(RenderState { .Indent = indent + indent_delta });1223
1110 try stack.append(RenderState { .Text = "\n" });1224 try stream.write("\n");
1111 {1225 try stream.writeByteNTimes(' ', indent_once);
1112 var i = asm_node.inputs.len;1226 try stream.write(": ");
1113 while (i != 0) {1227
1114 i -= 1;1228 {
1115 const node = *asm_node.inputs.at(i);1229 var it = asm_node.inputs.iterator(0);
1116 try stack.append(RenderState { .Expression = &node.base});1230 while (it.next()) |asm_input| {
11171231 const node = &(asm_input.*).base;
1118 if (i != 0) {1232 try renderExpression(allocator, stream, tree, indent_extra, node, Space.None);
1119 try stack.append(RenderState.PrintIndent);1233
1120 try stack.append(RenderState {1234 if (it.peek()) |next_asm_input| {
1121 .Text = blk: {1235 const next_node = &(next_asm_input.*).base;
1122 const prev_node = *asm_node.inputs.at(i - 1);1236
1123 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;1237 const comma = tree.prevToken(next_asm_input.*.firstToken());
1124 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());1238 try renderToken(tree, stream, comma, indent_extra, Space.Newline); // ,
1125 if (loc.line >= 2) {1239 try renderExtraNewline(tree, stream, next_node);
1126 break :blk "\n\n";1240
1127 }1241 try stream.writeByteNTimes(' ', indent_extra);
1128 break :blk "\n";
1129 },
1130 });
1131 try stack.append(RenderState { .Text = "," });
1132 }
1133 }
1134 }1242 }
1135 try stack.append(RenderState { .Indent = indent + indent_delta + 2});1243 }
1136 try stack.append(RenderState { .Text = ": "});1244 }
1137 try stack.append(RenderState.PrintIndent);1245
1138 try stack.append(RenderState { .Indent = indent + indent_delta});1246 try stream.write("\n");
1139 try stack.append(RenderState { .Text = "\n" });1247 try stream.writeByteNTimes(' ', indent_once);
1140 {1248 try stream.write(": ");
1141 var i = asm_node.outputs.len;1249
1142 while (i != 0) {1250 {
1143 i -= 1;1251 var it = asm_node.clobbers.iterator(0);
1144 const node = *asm_node.outputs.at(i);1252 while (it.next()) |node| {
1145 try stack.append(RenderState { .Expression = &node.base});1253 try renderExpression(allocator, stream, tree, indent_once, node.*, Space.None);
11461254
1147 if (i != 0) {1255 if (it.peek() != null) {
1148 try stack.append(RenderState.PrintIndent);1256 try stream.write(", ");
1149 try stack.append(RenderState {
1150 .Text = blk: {
1151 const prev_node = *asm_node.outputs.at(i - 1);
1152 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
1153 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
1154 if (loc.line >= 2) {
1155 break :blk "\n\n";
1156 }
1157 break :blk "\n";
1158 },
1159 });
1160 try stack.append(RenderState { .Text = "," });
1161 }
1162 }
1163 }1257 }
1164 try stack.append(RenderState { .Indent = indent + indent_delta + 2});1258 }
1165 try stack.append(RenderState { .Text = ": "});1259 }
1166 try stack.append(RenderState.PrintIndent);1260
1167 try stack.append(RenderState { .Indent = indent + indent_delta});1261 try renderToken(tree, stream, asm_node.rparen, indent, space);
1168 try stack.append(RenderState { .Text = "\n" });1262 },
1169 try stack.append(RenderState { .Expression = asm_node.template });1263
1170 try stack.append(RenderState { .Text = "(" });1264 ast.Node.Id.AsmInput => {
1171 },1265 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
1172 ast.Node.Id.AsmInput => {1266
1173 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);1267 try stream.write("[");
11741268 try renderExpression(allocator, stream, tree, indent, asm_input.symbolic_name, Space.None);
1175 try stack.append(RenderState { .Text = ")"});1269 try stream.write("] ");
1176 try stack.append(RenderState { .Expression = asm_input.expr});1270 try renderExpression(allocator, stream, tree, indent, asm_input.constraint, Space.None);
1177 try stack.append(RenderState { .Text = " ("});1271 try stream.write(" (");
1178 try stack.append(RenderState { .Expression = asm_input.constraint });1272 try renderExpression(allocator, stream, tree, indent, asm_input.expr, Space.None);
1179 try stack.append(RenderState { .Text = "] "});1273 try renderToken(tree, stream, asm_input.lastToken(), indent, space); // )
1180 try stack.append(RenderState { .Expression = asm_input.symbolic_name });1274 },
1181 try stack.append(RenderState { .Text = "["});1275
1276 ast.Node.Id.AsmOutput => {
1277 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
1278
1279 try stream.write("[");
1280 try renderExpression(allocator, stream, tree, indent, asm_output.symbolic_name, Space.None);
1281 try stream.write("] ");
1282 try renderExpression(allocator, stream, tree, indent, asm_output.constraint, Space.None);
1283 try stream.write(" (");
1284
1285 switch (asm_output.kind) {
1286 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
1287 try renderExpression(allocator, stream, tree, indent, &variable_name.base, Space.None);
1182 },1288 },
1183 ast.Node.Id.AsmOutput => {1289 ast.Node.AsmOutput.Kind.Return => |return_type| {
1184 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);1290 try stream.write("-> ");
11851291 try renderExpression(allocator, stream, tree, indent, return_type, Space.None);
1186 try stack.append(RenderState { .Text = ")"});
1187 switch (asm_output.kind) {
1188 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
1189 try stack.append(RenderState { .Expression = &variable_name.base});
1190 },
1191 ast.Node.AsmOutput.Kind.Return => |return_type| {
1192 try stack.append(RenderState { .Expression = return_type});
1193 try stack.append(RenderState { .Text = "-> "});
1194 },
1195 }
1196 try stack.append(RenderState { .Text = " ("});
1197 try stack.append(RenderState { .Expression = asm_output.constraint });
1198 try stack.append(RenderState { .Text = "] "});
1199 try stack.append(RenderState { .Expression = asm_output.symbolic_name });
1200 try stack.append(RenderState { .Text = "["});
1201 },1292 },
1293 }
12021294
1203 ast.Node.Id.StructField,1295 try renderToken(tree, stream, asm_output.lastToken(), indent, space); // )
1204 ast.Node.Id.UnionTag,1296 },
1205 ast.Node.Id.EnumTag,1297
1206 ast.Node.Id.ErrorTag,1298 ast.Node.Id.StructField,
1207 ast.Node.Id.Root,1299 ast.Node.Id.UnionTag,
1208 ast.Node.Id.VarDecl,1300 ast.Node.Id.EnumTag,
1209 ast.Node.Id.Use,1301 ast.Node.Id.Root,
1210 ast.Node.Id.TestDecl,1302 ast.Node.Id.VarDecl,
1211 ast.Node.Id.ParamDecl => unreachable,1303 ast.Node.Id.Use,
1212 },1304 ast.Node.Id.TestDecl,
1213 RenderState.Statement => |base| {1305 ast.Node.Id.ParamDecl => unreachable,
1214 switch (base.id) {1306 }
1215 ast.Node.Id.VarDecl => {1307}
1216 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);1308
1217 try stack.append(RenderState { .VarDecl = var_decl});1309fn renderVarDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize,
1218 },1310 var_decl: &ast.Node.VarDecl) (@typeOf(stream).Child.Error || Error)!void
1219 else => {1311{
1220 try stack.append(RenderState { .MaybeSemiColon = base });1312 if (var_decl.visib_token) |visib_token| {
1221 try stack.append(RenderState { .Expression = base });1313 try renderToken(tree, stream, visib_token, indent, Space.Space); // pub
1222 },1314 }
1223 }1315
1224 },1316 if (var_decl.extern_export_token) |extern_export_token| {
1225 RenderState.Indent => |new_indent| indent = new_indent,1317 try renderToken(tree, stream, extern_export_token, indent, Space.Space); // extern
1226 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),1318
1227 RenderState.Token => |token_index| try renderToken(tree, stream, token_index, indent, true),1319 if (var_decl.lib_name) |lib_name| {
1228 RenderState.NonBreakToken => |token_index| try renderToken(tree, stream, token_index, indent, false),1320 try renderExpression(allocator, stream, tree, indent, lib_name, Space.Space); // "lib"
1229 RenderState.MaybeSemiColon => |base| {
1230 if (base.requireSemiColon()) {
1231 const semicolon_index = base.lastToken() + 1;
1232 assert(tree.tokens.at(semicolon_index).id == Token.Id.Semicolon);
1233 try renderToken(tree, stream, semicolon_index, indent, true);
1234 }
1235 },
1236 }1321 }
1237 }1322 }
1323
1324 if (var_decl.comptime_token) |comptime_token| {
1325 try renderToken(tree, stream, comptime_token, indent, Space.Space); // comptime
1326 }
1327
1328 try renderToken(tree, stream, var_decl.mut_token, indent, Space.Space); // var
1329
1330 const name_space = if (var_decl.type_node == null and (var_decl.align_node != null or
1331 var_decl.init_node != null)) Space.Space else Space.None;
1332 try renderToken(tree, stream, var_decl.name_token, indent, name_space);
1333
1334 if (var_decl.type_node) |type_node| {
1335 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, Space.Space);
1336 const s = if (var_decl.align_node != null or var_decl.init_node != null) Space.Space else Space.None;
1337 try renderExpression(allocator, stream, tree, indent, type_node, s);
1338 }
1339
1340 if (var_decl.align_node) |align_node| {
1341 const lparen = tree.prevToken(align_node.firstToken());
1342 const align_kw = tree.prevToken(lparen);
1343 const rparen = tree.nextToken(align_node.lastToken());
1344 try renderToken(tree, stream, align_kw, indent, Space.None); // align
1345 try renderToken(tree, stream, lparen, indent, Space.None); // (
1346 try renderExpression(allocator, stream, tree, indent, align_node, Space.None);
1347 const s = if (var_decl.init_node != null) Space.Space else Space.None;
1348 try renderToken(tree, stream, rparen, indent, s); // )
1349 }
1350
1351 if (var_decl.init_node) |init_node| {
1352 const s = if (init_node.id == ast.Node.Id.MultilineStringLiteral) Space.None else Space.Space;
1353 try renderToken(tree, stream, var_decl.eq_token, indent, s); // =
1354 try renderExpression(allocator, stream, tree, indent, init_node, Space.None);
1355 }
1356
1357 try renderToken(tree, stream, var_decl.semicolon_token, indent, Space.Newline);
1358}
1359
1360fn renderParamDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
1361 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
1362
1363 if (param_decl.comptime_token) |comptime_token| {
1364 try renderToken(tree, stream, comptime_token, indent, Space.Space);
1365 }
1366 if (param_decl.noalias_token) |noalias_token| {
1367 try renderToken(tree, stream, noalias_token, indent, Space.Space);
1368 }
1369 if (param_decl.name_token) |name_token| {
1370 try renderToken(tree, stream, name_token, indent, Space.None);
1371 try renderToken(tree, stream, tree.nextToken(name_token), indent, Space.Space); // :
1372 }
1373 if (param_decl.var_args_token) |var_args_token| {
1374 try renderToken(tree, stream, var_args_token, indent, Space.None);
1375 } else {
1376 try renderExpression(allocator, stream, tree, indent, param_decl.type_node, Space.None);
1377 }
1238}1378}
12391379
1240fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, line_break: bool) !void {1380fn renderStatement(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
1241 const token = tree.tokens.at(token_index);1381 switch (base.id) {
1382 ast.Node.Id.VarDecl => {
1383 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
1384 try renderVarDecl(allocator, stream, tree, indent, var_decl);
1385 },
1386 else => {
1387 if (base.requireSemiColon()) {
1388 try renderExpression(allocator, stream, tree, indent, base, Space.None);
1389
1390 const semicolon_index = tree.nextToken(base.lastToken());
1391 assert(tree.tokens.at(semicolon_index).id == Token.Id.Semicolon);
1392 try renderToken(tree, stream, semicolon_index, indent, Space.Newline);
1393 } else {
1394 try renderExpression(allocator, stream, tree, indent, base, Space.Newline);
1395 }
1396 },
1397 }
1398}
1399
1400const Space = enum {
1401 None,
1402 Newline,
1403 Space,
1404 NoNewline,
1405 NoIndent,
1406 NoComment,
1407};
1408
1409fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, space: Space) (@typeOf(stream).Child.Error || Error)!void {
1410 var token = tree.tokens.at(token_index);
1242 try stream.write(tree.tokenSlicePtr(token));1411 try stream.write(tree.tokenSlicePtr(token));
12431412
1244 const next_token = tree.tokens.at(token_index + 1);1413 if (space == Space.NoComment) return;
1245 if (next_token.id == Token.Id.LineComment) {1414
1246 const loc = tree.tokenLocationPtr(token.end, next_token);1415 var next_token = tree.tokens.at(token_index + 1);
1247 if (loc.line == 0) {1416 if (next_token.id != Token.Id.LineComment) {
1248 try stream.print(" {}", tree.tokenSlicePtr(next_token));1417 switch (space) {
1249 if (!line_break) {1418 Space.None, Space.NoNewline, Space.NoIndent => return,
1250 try stream.write("\n");1419 Space.Newline => return stream.write("\n"),
1251 try stream.writeByteNTimes(' ', indent + indent_delta);1420 Space.Space => return stream.writeByte(' '),
1252 return;1421 Space.NoComment => unreachable,
1422 }
1423 }
1424
1425 var loc = tree.tokenLocationPtr(token.end, next_token);
1426 var offset: usize = 1;
1427 if (loc.line == 0) {
1428 try stream.print(" {}", tree.tokenSlicePtr(next_token));
1429 offset = 2;
1430 token = next_token;
1431 next_token = tree.tokens.at(token_index + offset);
1432 if (next_token.id != Token.Id.LineComment) {
1433 switch (space) {
1434 Space.None, Space.Space => {
1435 try stream.writeByte('\n');
1436 const after_comment_token = tree.tokens.at(token_index + offset);
1437 const next_line_indent = switch (after_comment_token.id) {
1438 Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent,
1439 else => indent + indent_delta,
1440 };
1441 try stream.writeByteNTimes(' ', next_line_indent);
1442 },
1443 Space.Newline, Space.NoIndent => try stream.write("\n"),
1444 Space.NoNewline => {},
1445 Space.NoComment => unreachable,
1253 }1446 }
1447 return;
1254 }1448 }
1449 loc = tree.tokenLocationPtr(token.end, next_token);
1255 }1450 }
12561451
1257 if (!line_break) {1452 while (true) {
1258 try stream.writeByte(' ');1453 assert(loc.line != 0);
1454 const newline_count = if (loc.line == 1) u8(1) else u8(2);
1455 try stream.writeByteNTimes('\n', newline_count);
1456 try stream.writeByteNTimes(' ', indent);
1457 try stream.write(tree.tokenSlicePtr(next_token));
1458
1459 offset += 1;
1460 token = next_token;
1461 next_token = tree.tokens.at(token_index + offset);
1462 if (next_token.id != Token.Id.LineComment) {
1463 switch (space) {
1464 Space.Newline, Space.NoIndent => try stream.writeByte('\n'),
1465 Space.None, Space.Space => {
1466 try stream.writeByte('\n');
1467
1468 const after_comment_token = tree.tokens.at(token_index + offset);
1469 const next_line_indent = switch (after_comment_token.id) {
1470 Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent,
1471 else => indent,
1472 };
1473 try stream.writeByteNTimes(' ', next_line_indent);
1474 },
1475 Space.NoNewline => {},
1476 Space.NoComment => unreachable,
1477 }
1478 return;
1479 }
1480 loc = tree.tokenLocationPtr(token.end, next_token);
1259 }1481 }
1260}1482}
12611483
1262fn renderComments(tree: &ast.Tree, stream: var, node: var, indent: usize) !void {1484fn renderDocComments(tree: &ast.Tree, stream: var, node: var, indent: usize) (@typeOf(stream).Child.Error || Error)!void {
1263 const comment = node.doc_comments ?? return;1485 const comment = node.doc_comments ?? return;
1264 var it = comment.lines.iterator(0);1486 var it = comment.lines.iterator(0);
1265 while (it.next()) |line_token_index| {1487 while (it.next()) |line_token_index| {
1266 try stream.print("{}\n", tree.tokenSlice(*line_token_index));1488 try renderToken(tree, stream, line_token_index.*, indent, Space.Newline);
1267 try stream.writeByteNTimes(' ', indent);1489 try stream.writeByteNTimes(' ', indent);
1268 }1490 }
1269}1491}
12701492
1493fn renderTrailingComma(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node,
1494 space: Space) (@typeOf(stream).Child.Error || Error)!void
1495{
1496 const end_token = base.lastToken() + 1;
1497 switch (tree.tokens.at(end_token).id) {
1498 Token.Id.Comma => {
1499 try renderExpression(allocator, stream, tree, indent, base, Space.None);
1500 try renderToken(tree, stream, end_token, indent, space); // ,
1501 },
1502 Token.Id.LineComment => {
1503 try renderExpression(allocator, stream, tree, indent, base, Space.NoComment);
1504 try stream.write(", ");
1505 try renderToken(tree, stream, end_token, indent, space);
1506 },
1507 else => {
1508 try renderExpression(allocator, stream, tree, indent, base, Space.None);
1509 try stream.write(",\n");
1510 assert(space == Space.Newline);
1511 },
1512 }
1513}
std/zig/tokenizer.zig+103-6
...@@ -6,12 +6,12 @@ pub const Token = struct {...@@ -6,12 +6,12 @@ pub const Token = struct {
6 start: usize,6 start: usize,
7 end: usize,7 end: usize,
88
9 const Keyword = struct {9 pub const Keyword = struct {
10 bytes: []const u8,10 bytes: []const u8,
11 id: Id,11 id: Id,
12 };12 };
1313
14 const keywords = []Keyword {14 pub const keywords = []Keyword {
15 Keyword{.bytes="align", .id = Id.Keyword_align},15 Keyword{.bytes="align", .id = Id.Keyword_align},
16 Keyword{.bytes="and", .id = Id.Keyword_and},16 Keyword{.bytes="and", .id = Id.Keyword_and},
17 Keyword{.bytes="asm", .id = Id.Keyword_asm},17 Keyword{.bytes="asm", .id = Id.Keyword_asm},
...@@ -62,6 +62,7 @@ pub const Token = struct {...@@ -62,6 +62,7 @@ pub const Token = struct {
62 Keyword{.bytes="while", .id = Id.Keyword_while},62 Keyword{.bytes="while", .id = Id.Keyword_while},
63 };63 };
6464
65 // TODO perfect hash at comptime
65 fn getKeyword(bytes: []const u8) ?Id {66 fn getKeyword(bytes: []const u8) ?Id {
66 for (keywords) |kw| {67 for (keywords) |kw| {
67 if (mem.eql(u8, kw.bytes, bytes)) {68 if (mem.eql(u8, kw.bytes, bytes)) {
...@@ -219,6 +220,8 @@ pub const Tokenizer = struct {...@@ -219,6 +220,8 @@ pub const Tokenizer = struct {
219 MultilineStringLiteralLineBackslash,220 MultilineStringLiteralLineBackslash,
220 CharLiteral,221 CharLiteral,
221 CharLiteralBackslash,222 CharLiteralBackslash,
223 CharLiteralEscape1,
224 CharLiteralEscape2,
222 CharLiteralEnd,225 CharLiteralEnd,
223 Backslash,226 Backslash,
224 Equal,227 Equal,
...@@ -236,10 +239,15 @@ pub const Tokenizer = struct {...@@ -236,10 +239,15 @@ pub const Tokenizer = struct {
236 Zero,239 Zero,
237 IntegerLiteral,240 IntegerLiteral,
238 IntegerLiteralWithRadix,241 IntegerLiteralWithRadix,
242 IntegerLiteralWithRadixHex,
239 NumberDot,243 NumberDot,
244 NumberDotHex,
240 FloatFraction,245 FloatFraction,
246 FloatFractionHex,
241 FloatExponentUnsigned,247 FloatExponentUnsigned,
248 FloatExponentUnsignedHex,
242 FloatExponentNumber,249 FloatExponentNumber,
250 FloatExponentNumberHex,
243 Ampersand,251 Ampersand,
244 Caret,252 Caret,
245 Percent,253 Percent,
...@@ -606,11 +614,34 @@ pub const Tokenizer = struct {...@@ -606,11 +614,34 @@ pub const Tokenizer = struct {
606 result.id = Token.Id.Invalid;614 result.id = Token.Id.Invalid;
607 break;615 break;
608 },616 },
617 'x' => {
618 state = State.CharLiteralEscape1;
619 },
609 else => {620 else => {
610 state = State.CharLiteralEnd;621 state = State.CharLiteralEnd;
611 },622 },
612 },623 },
613624
625 State.CharLiteralEscape1 => switch (c) {
626 '0'...'9', 'a'...'z', 'A'...'F' => {
627 state = State.CharLiteralEscape2;
628 },
629 else => {
630 result.id = Token.Id.Invalid;
631 break;
632 },
633 },
634
635 State.CharLiteralEscape2 => switch (c) {
636 '0'...'9', 'a'...'z', 'A'...'F' => {
637 state = State.CharLiteralEnd;
638 },
639 else => {
640 result.id = Token.Id.Invalid;
641 break;
642 },
643 },
644
614 State.CharLiteralEnd => switch (c) {645 State.CharLiteralEnd => switch (c) {
615 '\'' => {646 '\'' => {
616 result.id = Token.Id.CharLiteral;647 result.id = Token.Id.CharLiteral;
...@@ -839,9 +870,12 @@ pub const Tokenizer = struct {...@@ -839,9 +870,12 @@ pub const Tokenizer = struct {
839 else => self.checkLiteralCharacter(),870 else => self.checkLiteralCharacter(),
840 },871 },
841 State.Zero => switch (c) {872 State.Zero => switch (c) {
842 'b', 'o', 'x' => {873 'b', 'o' => {
843 state = State.IntegerLiteralWithRadix;874 state = State.IntegerLiteralWithRadix;
844 },875 },
876 'x' => {
877 state = State.IntegerLiteralWithRadixHex;
878 },
845 else => {879 else => {
846 // reinterpret as a normal number880 // reinterpret as a normal number
847 self.index -= 1;881 self.index -= 1;
...@@ -862,8 +896,15 @@ pub const Tokenizer = struct {...@@ -862,8 +896,15 @@ pub const Tokenizer = struct {
862 '.' => {896 '.' => {
863 state = State.NumberDot;897 state = State.NumberDot;
864 },898 },
899 '0'...'9' => {},
900 else => break,
901 },
902 State.IntegerLiteralWithRadixHex => switch (c) {
903 '.' => {
904 state = State.NumberDotHex;
905 },
865 'p', 'P' => {906 'p', 'P' => {
866 state = State.FloatExponentUnsigned;907 state = State.FloatExponentUnsignedHex;
867 },908 },
868 '0'...'9', 'a'...'f', 'A'...'F' => {},909 '0'...'9', 'a'...'f', 'A'...'F' => {},
869 else => break,910 else => break,
...@@ -880,13 +921,32 @@ pub const Tokenizer = struct {...@@ -880,13 +921,32 @@ pub const Tokenizer = struct {
880 state = State.FloatFraction;921 state = State.FloatFraction;
881 },922 },
882 },923 },
924 State.NumberDotHex => switch (c) {
925 '.' => {
926 self.index -= 1;
927 state = State.Start;
928 break;
929 },
930 else => {
931 self.index -= 1;
932 result.id = Token.Id.FloatLiteral;
933 state = State.FloatFractionHex;
934 },
935 },
883 State.FloatFraction => switch (c) {936 State.FloatFraction => switch (c) {
884 'p', 'P', 'e', 'E' => {937 'e', 'E' => {
885 state = State.FloatExponentUnsigned;938 state = State.FloatExponentUnsigned;
886 },939 },
887 '0'...'9' => {},940 '0'...'9' => {},
888 else => break,941 else => break,
889 },942 },
943 State.FloatFractionHex => switch (c) {
944 'p', 'P' => {
945 state = State.FloatExponentUnsignedHex;
946 },
947 '0'...'9', 'a'...'f', 'A'...'F' => {},
948 else => break,
949 },
890 State.FloatExponentUnsigned => switch (c) {950 State.FloatExponentUnsigned => switch (c) {
891 '+', '-' => {951 '+', '-' => {
892 state = State.FloatExponentNumber;952 state = State.FloatExponentNumber;
...@@ -897,7 +957,21 @@ pub const Tokenizer = struct {...@@ -897,7 +957,21 @@ pub const Tokenizer = struct {
897 state = State.FloatExponentNumber;957 state = State.FloatExponentNumber;
898 }958 }
899 },959 },
960 State.FloatExponentUnsignedHex => switch (c) {
961 '+', '-' => {
962 state = State.FloatExponentNumberHex;
963 },
964 else => {
965 // reinterpret as a normal exponent number
966 self.index -= 1;
967 state = State.FloatExponentNumberHex;
968 }
969 },
900 State.FloatExponentNumber => switch (c) {970 State.FloatExponentNumber => switch (c) {
971 '0'...'9' => {},
972 else => break,
973 },
974 State.FloatExponentNumberHex => switch (c) {
901 '0'...'9', 'a'...'f', 'A'...'F' => {},975 '0'...'9', 'a'...'f', 'A'...'F' => {},
902 else => break,976 else => break,
903 },977 },
...@@ -908,8 +982,11 @@ pub const Tokenizer = struct {...@@ -908,8 +982,11 @@ pub const Tokenizer = struct {
908 State.C,982 State.C,
909 State.IntegerLiteral,983 State.IntegerLiteral,
910 State.IntegerLiteralWithRadix,984 State.IntegerLiteralWithRadix,
985 State.IntegerLiteralWithRadixHex,
911 State.FloatFraction,986 State.FloatFraction,
987 State.FloatFractionHex,
912 State.FloatExponentNumber,988 State.FloatExponentNumber,
989 State.FloatExponentNumberHex,
913 State.StringLiteral, // find this error later990 State.StringLiteral, // find this error later
914 State.MultilineStringLiteralLine,991 State.MultilineStringLiteralLine,
915 State.Builtin => {},992 State.Builtin => {},
...@@ -928,12 +1005,16 @@ pub const Tokenizer = struct {...@@ -928,12 +1005,16 @@ pub const Tokenizer = struct {
928 },1005 },
9291006
930 State.NumberDot,1007 State.NumberDot,
1008 State.NumberDotHex,
931 State.FloatExponentUnsigned,1009 State.FloatExponentUnsigned,
1010 State.FloatExponentUnsignedHex,
932 State.SawAtSign,1011 State.SawAtSign,
933 State.Backslash,1012 State.Backslash,
934 State.MultilineStringLiteralLineBackslash,1013 State.MultilineStringLiteralLineBackslash,
935 State.CharLiteral,1014 State.CharLiteral,
936 State.CharLiteralBackslash,1015 State.CharLiteralBackslash,
1016 State.CharLiteralEscape1,
1017 State.CharLiteralEscape2,
937 State.CharLiteralEnd,1018 State.CharLiteralEnd,
938 State.StringLiteralBackslash => {1019 State.StringLiteralBackslash => {
939 result.id = Token.Id.Invalid;1020 result.id = Token.Id.Invalid;
...@@ -1073,7 +1154,14 @@ test "tokenizer" {...@@ -1073,7 +1154,14 @@ test "tokenizer" {
1073 });1154 });
1074}1155}
10751156
1076test "tokenizer - float literal" {1157test "tokenizer - char literal with hex escape" {
1158 testTokenize( \\'\x1b'
1159 , []Token.Id {
1160 Token.Id.CharLiteral,
1161 });
1162}
1163
1164test "tokenizer - float literal e exponent" {
1077 testTokenize("a = 4.94065645841246544177e-324;\n", []Token.Id {1165 testTokenize("a = 4.94065645841246544177e-324;\n", []Token.Id {
1078 Token.Id.Identifier,1166 Token.Id.Identifier,
1079 Token.Id.Equal,1167 Token.Id.Equal,
...@@ -1082,6 +1170,15 @@ test "tokenizer - float literal" {...@@ -1082,6 +1170,15 @@ test "tokenizer - float literal" {
1082 });1170 });
1083}1171}
10841172
1173test "tokenizer - float literal p exponent" {
1174 testTokenize("a = 0x1.a827999fcef32p+1022;\n", []Token.Id {
1175 Token.Id.Identifier,
1176 Token.Id.Equal,
1177 Token.Id.FloatLiteral,
1178 Token.Id.Semicolon,
1179 });
1180}
1181
1085test "tokenizer - chars" {1182test "tokenizer - chars" {
1086 testTokenize("'c'", []Token.Id {Token.Id.CharLiteral});1183 testTokenize("'c'", []Token.Id {Token.Id.CharLiteral});
1087}1184}
test/behavior.zig+4-2
...@@ -23,6 +23,7 @@ comptime {...@@ -23,6 +23,7 @@ comptime {
23 _ = @import("cases/eval.zig");23 _ = @import("cases/eval.zig");
24 _ = @import("cases/field_parent_ptr.zig");24 _ = @import("cases/field_parent_ptr.zig");
25 _ = @import("cases/fn.zig");25 _ = @import("cases/fn.zig");
26 _ = @import("cases/fn_in_struct_in_comptime.zig");
26 _ = @import("cases/for.zig");27 _ = @import("cases/for.zig");
27 _ = @import("cases/generics.zig");28 _ = @import("cases/generics.zig");
28 _ = @import("cases/if.zig");29 _ = @import("cases/if.zig");
...@@ -32,11 +33,12 @@ comptime {...@@ -32,11 +33,12 @@ comptime {
32 _ = @import("cases/math.zig");33 _ = @import("cases/math.zig");
33 _ = @import("cases/misc.zig");34 _ = @import("cases/misc.zig");
34 _ = @import("cases/namespace_depends_on_compile_var/index.zig");35 _ = @import("cases/namespace_depends_on_compile_var/index.zig");
36 _ = @import("cases/new_stack_call.zig");
35 _ = @import("cases/null.zig");37 _ = @import("cases/null.zig");
38 _ = @import("cases/pointers.zig");
36 _ = @import("cases/pub_enum/index.zig");39 _ = @import("cases/pub_enum/index.zig");
37 _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");40 _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
38 _ = @import("cases/reflection.zig");41 _ = @import("cases/reflection.zig");
39 _ = @import("cases/type_info.zig");
40 _ = @import("cases/sizeof_and_typeof.zig");42 _ = @import("cases/sizeof_and_typeof.zig");
41 _ = @import("cases/slice.zig");43 _ = @import("cases/slice.zig");
42 _ = @import("cases/struct.zig");44 _ = @import("cases/struct.zig");
...@@ -48,10 +50,10 @@ comptime {...@@ -48,10 +50,10 @@ comptime {
48 _ = @import("cases/syntax.zig");50 _ = @import("cases/syntax.zig");
49 _ = @import("cases/this.zig");51 _ = @import("cases/this.zig");
50 _ = @import("cases/try.zig");52 _ = @import("cases/try.zig");
53 _ = @import("cases/type_info.zig");
51 _ = @import("cases/undefined.zig");54 _ = @import("cases/undefined.zig");
52 _ = @import("cases/union.zig");55 _ = @import("cases/union.zig");
53 _ = @import("cases/var_args.zig");56 _ = @import("cases/var_args.zig");
54 _ = @import("cases/void.zig");57 _ = @import("cases/void.zig");
55 _ = @import("cases/while.zig");58 _ = @import("cases/while.zig");
56 _ = @import("cases/fn_in_struct_in_comptime.zig");
57}59}
test/build_examples.zig+1-1
...@@ -9,7 +9,7 @@ pub fn addCases(cases: &tests.BuildExamplesContext) void {...@@ -9,7 +9,7 @@ pub fn addCases(cases: &tests.BuildExamplesContext) void {
9 cases.add("example/guess_number/main.zig");9 cases.add("example/guess_number/main.zig");
10 if (!is_windows) {10 if (!is_windows) {
11 // TODO get this test passing on windows11 // TODO get this test passing on windows
12 // See https://github.com/zig-lang/zig/issues/53812 // See https://github.com/ziglang/zig/issues/538
13 cases.addBuildFile("example/shared_library/build.zig");13 cases.addBuildFile("example/shared_library/build.zig");
14 cases.addBuildFile("example/mix_o_files/build.zig");14 cases.addBuildFile("example/mix_o_files/build.zig");
15 }15 }
test/cases/align.zig+60-26
...@@ -10,7 +10,9 @@ test "global variable alignment" {...@@ -10,7 +10,9 @@ test "global variable alignment" {
10 assert(@typeOf(slice) == []align(4) u8);10 assert(@typeOf(slice) == []align(4) u8);
11}11}
1212
13fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }13fn derp() align(@sizeOf(usize) * 2) i32 {
14 return 1234;
15}
14fn noop1() align(1) void {}16fn noop1() align(1) void {}
15fn noop4() align(4) void {}17fn noop4() align(4) void {}
1618
...@@ -22,7 +24,6 @@ test "function alignment" {...@@ -22,7 +24,6 @@ test "function alignment" {
22 noop4();24 noop4();
23}25}
2426
25
26var baz: packed struct {27var baz: packed struct {
27 a: u32,28 a: u32,
28 b: u32,29 b: u32,
...@@ -32,7 +33,6 @@ test "packed struct alignment" {...@@ -32,7 +33,6 @@ test "packed struct alignment" {
32 assert(@typeOf(&baz.b) == &align(1) u32);33 assert(@typeOf(&baz.b) == &align(1) u32);
33}34}
3435
35
36const blah: packed struct {36const blah: packed struct {
37 a: u3,37 a: u3,
38 b: u3,38 b: u3,
...@@ -53,29 +53,43 @@ test "implicitly decreasing pointer alignment" {...@@ -53,29 +53,43 @@ test "implicitly decreasing pointer alignment" {
53 assert(addUnaligned(&a, &b) == 7);53 assert(addUnaligned(&a, &b) == 7);
54}54}
5555
56fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) u32 { return *a + *b; }56fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) u32 {
57 return a.* + b.*;
58}
5759
58test "implicitly decreasing slice alignment" {60test "implicitly decreasing slice alignment" {
59 const a: u32 align(4) = 3;61 const a: u32 align(4) = 3;
60 const b: u32 align(8) = 4;62 const b: u32 align(8) = 4;
61 assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7);63 assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7);
62}64}
63fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { return a[0] + b[0]; }65fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
66 return a[0] + b[0];
67}
6468
65test "specifying alignment allows pointer cast" {69test "specifying alignment allows pointer cast" {
66 testBytesAlign(0x33);70 testBytesAlign(0x33);
67}71}
68fn testBytesAlign(b: u8) void {72fn testBytesAlign(b: u8) void {
69 var bytes align(4) = []u8{b, b, b, b};73 var bytes align(4) = []u8 {
74 b,
75 b,
76 b,
77 b,
78 };
70 const ptr = @ptrCast(&u32, &bytes[0]);79 const ptr = @ptrCast(&u32, &bytes[0]);
71 assert(*ptr == 0x33333333);80 assert(ptr.* == 0x33333333);
72}81}
7382
74test "specifying alignment allows slice cast" {83test "specifying alignment allows slice cast" {
75 testBytesAlignSlice(0x33);84 testBytesAlignSlice(0x33);
76}85}
77fn testBytesAlignSlice(b: u8) void {86fn testBytesAlignSlice(b: u8) void {
78 var bytes align(4) = []u8{b, b, b, b};87 var bytes align(4) = []u8 {
88 b,
89 b,
90 b,
91 b,
92 };
79 const slice = ([]u32)(bytes[0..]);93 const slice = ([]u32)(bytes[0..]);
80 assert(slice[0] == 0x33333333);94 assert(slice[0] == 0x33333333);
81}95}
...@@ -89,11 +103,14 @@ fn expectsOnly1(x: &align(1) u32) void {...@@ -89,11 +103,14 @@ fn expectsOnly1(x: &align(1) u32) void {
89 expects4(@alignCast(4, x));103 expects4(@alignCast(4, x));
90}104}
91fn expects4(x: &align(4) u32) void {105fn expects4(x: &align(4) u32) void {
92 *x += 1;106 x.* += 1;
93}107}
94108
95test "@alignCast slices" {109test "@alignCast slices" {
96 var array align(4) = []u32{1, 1};110 var array align(4) = []u32 {
111 1,
112 1,
113 };
97 const slice = array[0..];114 const slice = array[0..];
98 sliceExpectsOnly1(slice);115 sliceExpectsOnly1(slice);
99 assert(slice[0] == 2);116 assert(slice[0] == 2);
...@@ -105,31 +122,34 @@ fn sliceExpects4(slice: []align(4) u32) void {...@@ -105,31 +122,34 @@ fn sliceExpects4(slice: []align(4) u32) void {
105 slice[0] += 1;122 slice[0] += 1;
106}123}
107124
108
109test "implicitly decreasing fn alignment" {125test "implicitly decreasing fn alignment" {
110 testImplicitlyDecreaseFnAlign(alignedSmall, 1234);126 testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
111 testImplicitlyDecreaseFnAlign(alignedBig, 5678);127 testImplicitlyDecreaseFnAlign(alignedBig, 5678);
112}128}
113129
114fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void {130fn testImplicitlyDecreaseFnAlign(ptr: fn() align(1) i32, answer: i32) void {
115 assert(ptr() == answer);131 assert(ptr() == answer);
116}132}
117133
118fn alignedSmall() align(8) i32 { return 1234; }134fn alignedSmall() align(8) i32 {
119fn alignedBig() align(16) i32 { return 5678; }135 return 1234;
120136}
137fn alignedBig() align(16) i32 {
138 return 5678;
139}
121140
122test "@alignCast functions" {141test "@alignCast functions" {
123 assert(fnExpectsOnly1(simple4) == 0x19);142 assert(fnExpectsOnly1(simple4) == 0x19);
124}143}
125fn fnExpectsOnly1(ptr: fn()align(1) i32) i32 {144fn fnExpectsOnly1(ptr: fn() align(1) i32) i32 {
126 return fnExpects4(@alignCast(4, ptr));145 return fnExpects4(@alignCast(4, ptr));
127}146}
128fn fnExpects4(ptr: fn()align(4) i32) i32 {147fn fnExpects4(ptr: fn() align(4) i32) i32 {
129 return ptr();148 return ptr();
130}149}
131fn simple4() align(4) i32 { return 0x19; }150fn simple4() align(4) i32 {
132151 return 0x19;
152}
133153
134test "generic function with align param" {154test "generic function with align param" {
135 assert(whyWouldYouEverDoThis(1) == 0x1);155 assert(whyWouldYouEverDoThis(1) == 0x1);
...@@ -137,8 +157,9 @@ test "generic function with align param" {...@@ -137,8 +157,9 @@ test "generic function with align param" {
137 assert(whyWouldYouEverDoThis(8) == 0x1);157 assert(whyWouldYouEverDoThis(8) == 0x1);
138}158}
139159
140fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { return 0x1; }160fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
141161 return 0x1;
162}
142163
143test "@ptrCast preserves alignment of bigger source" {164test "@ptrCast preserves alignment of bigger source" {
144 var x: u32 align(16) = 1234;165 var x: u32 align(16) = 1234;
...@@ -146,24 +167,38 @@ test "@ptrCast preserves alignment of bigger source" {...@@ -146,24 +167,38 @@ test "@ptrCast preserves alignment of bigger source" {
146 assert(@typeOf(ptr) == &align(16) u8);167 assert(@typeOf(ptr) == &align(16) u8);
147}168}
148169
149
150test "compile-time known array index has best alignment possible" {170test "compile-time known array index has best alignment possible" {
151 // take full advantage of over-alignment171 // take full advantage of over-alignment
152 var array align(4) = []u8 {1, 2, 3, 4};172 var array align(4) = []u8 {
173 1,
174 2,
175 3,
176 4,
177 };
153 assert(@typeOf(&array[0]) == &align(4) u8);178 assert(@typeOf(&array[0]) == &align(4) u8);
154 assert(@typeOf(&array[1]) == &u8);179 assert(@typeOf(&array[1]) == &u8);
155 assert(@typeOf(&array[2]) == &align(2) u8);180 assert(@typeOf(&array[2]) == &align(2) u8);
156 assert(@typeOf(&array[3]) == &u8);181 assert(@typeOf(&array[3]) == &u8);
157182
158 // because align is too small but we still figure out to use 2183 // because align is too small but we still figure out to use 2
159 var bigger align(2) = []u64{1, 2, 3, 4};184 var bigger align(2) = []u64 {
185 1,
186 2,
187 3,
188 4,
189 };
160 assert(@typeOf(&bigger[0]) == &align(2) u64);190 assert(@typeOf(&bigger[0]) == &align(2) u64);
161 assert(@typeOf(&bigger[1]) == &align(2) u64);191 assert(@typeOf(&bigger[1]) == &align(2) u64);
162 assert(@typeOf(&bigger[2]) == &align(2) u64);192 assert(@typeOf(&bigger[2]) == &align(2) u64);
163 assert(@typeOf(&bigger[3]) == &align(2) u64);193 assert(@typeOf(&bigger[3]) == &align(2) u64);
164194
165 // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2195 // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
166 var smaller align(2) = []u32{1, 2, 3, 4};196 var smaller align(2) = []u32 {
197 1,
198 2,
199 3,
200 4,
201 };
167 testIndex(&smaller[0], 0, &align(2) u32);202 testIndex(&smaller[0], 0, &align(2) u32);
168 testIndex(&smaller[0], 1, &align(2) u32);203 testIndex(&smaller[0], 1, &align(2) u32);
169 testIndex(&smaller[0], 2, &align(2) u32);204 testIndex(&smaller[0], 2, &align(2) u32);
...@@ -182,7 +217,6 @@ fn testIndex2(ptr: &align(4) u8, index: usize, comptime T: type) void {...@@ -182,7 +217,6 @@ fn testIndex2(ptr: &align(4) u8, index: usize, comptime T: type) void {
182 assert(@typeOf(&ptr[index]) == T);217 assert(@typeOf(&ptr[index]) == T);
183}218}
184219
185
186test "alignstack" {220test "alignstack" {
187 assert(fnWithAlignedStack() == 1234);221 assert(fnWithAlignedStack() == 1234);
188}222}
test/cases/alignof.zig+5-1
...@@ -1,7 +1,11 @@...@@ -1,7 +1,11 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4const Foo = struct { x: u32, y: u32, z: u32, };4const Foo = struct {
5 x: u32,
6 y: u32,
7 z: u32,
8};
59
6test "@alignOf(T) before referencing T" {10test "@alignOf(T) before referencing T" {
7 comptime assert(@alignOf(Foo) != @maxValue(usize));11 comptime assert(@alignOf(Foo) != @maxValue(usize));
test/cases/array.zig+31-10
...@@ -2,9 +2,9 @@ const assert = @import("std").debug.assert;...@@ -2,9 +2,9 @@ const assert = @import("std").debug.assert;
2const mem = @import("std").mem;2const mem = @import("std").mem;
33
4test "arrays" {4test "arrays" {
5 var array : [5]u32 = undefined;5 var array: [5]u32 = undefined;
66
7 var i : u32 = 0;7 var i: u32 = 0;
8 while (i < 5) {8 while (i < 5) {
9 array[i] = i + 1;9 array[i] = i + 1;
10 i = array[i];10 i = array[i];
...@@ -34,24 +34,41 @@ test "void arrays" {...@@ -34,24 +34,41 @@ test "void arrays" {
34}34}
3535
36test "array literal" {36test "array literal" {
37 const hex_mult = []u16{4096, 256, 16, 1};37 const hex_mult = []u16 {
38 4096,
39 256,
40 16,
41 1,
42 };
3843
39 assert(hex_mult.len == 4);44 assert(hex_mult.len == 4);
40 assert(hex_mult[1] == 256);45 assert(hex_mult[1] == 256);
41}46}
4247
43test "array dot len const expr" {48test "array dot len const expr" {
44 assert(comptime x: {break :x some_array.len == 4;});49 assert(comptime x: {
50 break :x some_array.len == 4;
51 });
45}52}
4653
47const ArrayDotLenConstExpr = struct {54const ArrayDotLenConstExpr = struct {
48 y: [some_array.len]u8,55 y: [some_array.len]u8,
49};56};
50const some_array = []u8 {0, 1, 2, 3};57const some_array = []u8 {
5158 0,
59 1,
60 2,
61 3,
62};
5263
53test "nested arrays" {64test "nested arrays" {
54 const array_of_strings = [][]const u8 {"hello", "this", "is", "my", "thing"};65 const array_of_strings = [][]const u8 {
66 "hello",
67 "this",
68 "is",
69 "my",
70 "thing",
71 };
55 for (array_of_strings) |s, i| {72 for (array_of_strings) |s, i| {
56 if (i == 0) assert(mem.eql(u8, s, "hello"));73 if (i == 0) assert(mem.eql(u8, s, "hello"));
57 if (i == 1) assert(mem.eql(u8, s, "this"));74 if (i == 1) assert(mem.eql(u8, s, "this"));
...@@ -61,7 +78,6 @@ test "nested arrays" {...@@ -61,7 +78,6 @@ test "nested arrays" {
61 }78 }
62}79}
6380
64
65var s_array: [8]Sub = undefined;81var s_array: [8]Sub = undefined;
66const Sub = struct {82const Sub = struct {
67 b: u8,83 b: u8,
...@@ -70,7 +86,9 @@ const Str = struct {...@@ -70,7 +86,9 @@ const Str = struct {
70 a: []Sub,86 a: []Sub,
71};87};
72test "set global var array via slice embedded in struct" {88test "set global var array via slice embedded in struct" {
73 var s = Str { .a = s_array[0..]};89 var s = Str {
90 .a = s_array[0..],
91 };
7492
75 s.a[0].b = 1;93 s.a[0].b = 1;
76 s.a[1].b = 2;94 s.a[1].b = 2;
...@@ -82,7 +100,10 @@ test "set global var array via slice embedded in struct" {...@@ -82,7 +100,10 @@ test "set global var array via slice embedded in struct" {
82}100}
83101
84test "array literal with specified size" {102test "array literal with specified size" {
85 var array = [2]u8{1, 2};103 var array = [2]u8 {
104 1,
105 2,
106 };
86 assert(array[0] == 1);107 assert(array[0] == 1);
87 assert(array[1] == 2);108 assert(array[1] == 2);
88}109}
test/cases/bitcast.zig+6-2
...@@ -10,5 +10,9 @@ fn testBitCast_i32_u32() void {...@@ -10,5 +10,9 @@ fn testBitCast_i32_u32() void {
10 assert(conv2(@maxValue(u32)) == -1);10 assert(conv2(@maxValue(u32)) == -1);
11}11}
1212
13fn conv(x: i32) u32 { return @bitCast(u32, x); }13fn conv(x: i32) u32 {
14fn conv2(x: u32) i32 { return @bitCast(i32, x); }14 return @bitCast(u32, x);
15}
16fn conv2(x: u32) i32 {
17 return @bitCast(i32, x);
18}
test/cases/bugs/394.zig+14-3
...@@ -1,9 +1,20 @@...@@ -1,9 +1,20 @@
1const E = union(enum) { A: [9]u8, B: u64, };1const E = union(enum) {
2const S = struct { x: u8, y: E, };2 A: [9]u8,
3 B: u64,
4};
5const S = struct {
6 x: u8,
7 y: E,
8};
39
4const assert = @import("std").debug.assert;10const assert = @import("std").debug.assert;
511
6test "bug 394 fixed" {12test "bug 394 fixed" {
7 const x = S { .x = 3, .y = E {.B = 1 } };13 const x = S {
14 .x = 3,
15 .y = E {
16 .B = 1,
17 },
18 };
8 assert(x.x == 3);19 assert(x.x == 3);
9}20}
test/cases/bugs/655.zig+1-1
...@@ -8,5 +8,5 @@ test "function with &const parameter with type dereferenced by namespace" {...@@ -8,5 +8,5 @@ test "function with &const parameter with type dereferenced by namespace" {
8}8}
99
10fn foo(x: &const other_file.Integer) void {10fn foo(x: &const other_file.Integer) void {
11 std.debug.assert(*x == 1234);11 std.debug.assert(x.* == 1234);
12}12}
test/cases/bugs/656.zig+7-4
...@@ -14,12 +14,15 @@ test "nullable if after an if in a switch prong of a switch with 2 prongs in an...@@ -14,12 +14,15 @@ test "nullable if after an if in a switch prong of a switch with 2 prongs in an
14}14}
1515
16fn foo(a: bool, b: bool) void {16fn foo(a: bool, b: bool) void {
17 var prefix_op = PrefixOp { .AddrOf = Value { .align_expr = 1234 } };17 var prefix_op = PrefixOp {
18 if (a) {18 .AddrOf = Value {
19 } else {19 .align_expr = 1234,
20 },
21 };
22 if (a) {} else {
20 switch (prefix_op) {23 switch (prefix_op) {
21 PrefixOp.AddrOf => |addr_of_info| {24 PrefixOp.AddrOf => |addr_of_info| {
22 if (b) { }25 if (b) {}
23 if (addr_of_info.align_expr) |align_expr| {26 if (addr_of_info.align_expr) |align_expr| {
24 assert(align_expr == 1234);27 assert(align_expr == 1234);
25 }28 }
test/cases/bugs/828.zig+5-5
...@@ -1,10 +1,10 @@...@@ -1,10 +1,10 @@
1const CountBy = struct {1const CountBy = struct {
2 a: usize,2 a: usize,
3 3
4 const One = CountBy {4 const One = CountBy {
5 .a = 1,5 .a = 1,
6 };6 };
7 7
8 pub fn counter(self: &const CountBy) Counter {8 pub fn counter(self: &const CountBy) Counter {
9 return Counter {9 return Counter {
10 .i = 0,10 .i = 0,
...@@ -14,7 +14,7 @@ const CountBy = struct {...@@ -14,7 +14,7 @@ const CountBy = struct {
1414
15const Counter = struct {15const Counter = struct {
16 i: usize,16 i: usize,
17 17
18 pub fn count(self: &Counter) bool {18 pub fn count(self: &Counter) bool {
19 self.i += 1;19 self.i += 1;
20 return self.i <= 10;20 return self.i <= 10;
...@@ -24,8 +24,8 @@ const Counter = struct {...@@ -24,8 +24,8 @@ const Counter = struct {
24fn constCount(comptime cb: &const CountBy, comptime unused: u32) void {24fn constCount(comptime cb: &const CountBy, comptime unused: u32) void {
25 comptime {25 comptime {
26 var cnt = cb.counter();26 var cnt = cb.counter();
27 if(cnt.i != 0) @compileError("Counter instance reused!");27 if (cnt.i != 0) @compileError("Counter instance reused!");
28 while(cnt.count()){}28 while (cnt.count()) {}
29 }29 }
30}30}
3131
test/cases/bugs/920.zig+12-7
...@@ -12,8 +12,7 @@ const ZigTable = struct {...@@ -12,8 +12,7 @@ const ZigTable = struct {
12 zero_case: fn(&Random, f64) f64,12 zero_case: fn(&Random, f64) f64,
13};13};
1414
15fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn(f64) f64,15fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn(f64) f64, comptime f_inv: fn(f64) f64, comptime zero_case: fn(&Random, f64) f64) ZigTable {
16 comptime f_inv: fn(f64) f64, comptime zero_case: fn(&Random, f64) f64) ZigTable {
17 var tables: ZigTable = undefined;16 var tables: ZigTable = undefined;
1817
19 tables.is_symmetric = is_symmetric;18 tables.is_symmetric = is_symmetric;
...@@ -26,12 +25,12 @@ fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, co...@@ -26,12 +25,12 @@ fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, co
2625
27 for (tables.x[2..256]) |*entry, i| {26 for (tables.x[2..256]) |*entry, i| {
28 const last = tables.x[2 + i - 1];27 const last = tables.x[2 + i - 1];
29 *entry = f_inv(v / last + f(last));28 entry.* = f_inv(v / last + f(last));
30 }29 }
31 tables.x[256] = 0;30 tables.x[256] = 0;
3231
33 for (tables.f[0..]) |*entry, i| {32 for (tables.f[0..]) |*entry, i| {
34 *entry = f(tables.x[i]);33 entry.* = f(tables.x[i]);
35 }34 }
3635
37 return tables;36 return tables;
...@@ -40,9 +39,15 @@ fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, co...@@ -40,9 +39,15 @@ fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, co
40const norm_r = 3.6541528853610088;39const norm_r = 3.6541528853610088;
41const norm_v = 0.00492867323399;40const norm_v = 0.00492867323399;
4241
43fn norm_f(x: f64) f64 { return math.exp(-x * x / 2.0); }42fn norm_f(x: f64) f64 {
44fn norm_f_inv(y: f64) f64 { return math.sqrt(-2.0 * math.ln(y)); }43 return math.exp(-x * x / 2.0);
45fn norm_zero_case(random: &Random, u: f64) f64 { return 0.0; }44}
45fn norm_f_inv(y: f64) f64 {
46 return math.sqrt(-2.0 * math.ln(y));
47}
48fn norm_zero_case(random: &Random, u: f64) f64 {
49 return 0.0;
50}
4651
47const NormalDist = blk: {52const NormalDist = blk: {
48 @setEvalBranchQuota(30000);53 @setEvalBranchQuota(30000);
test/cases/cast.zig+42-28
...@@ -17,7 +17,7 @@ test "pointer reinterpret const float to int" {...@@ -17,7 +17,7 @@ test "pointer reinterpret const float to int" {
17 const float: f64 = 5.99999999999994648725e-01;17 const float: f64 = 5.99999999999994648725e-01;
18 const float_ptr = &float;18 const float_ptr = &float;
19 const int_ptr = @ptrCast(&const i32, float_ptr);19 const int_ptr = @ptrCast(&const i32, float_ptr);
20 const int_val = *int_ptr;20 const int_val = int_ptr.*;
21 assert(int_val == 858993411);21 assert(int_val == 858993411);
22}22}
2323
...@@ -29,25 +29,31 @@ test "implicitly cast a pointer to a const pointer of it" {...@@ -29,25 +29,31 @@ test "implicitly cast a pointer to a const pointer of it" {
29}29}
3030
31fn funcWithConstPtrPtr(x: &const &i32) void {31fn funcWithConstPtrPtr(x: &const &i32) void {
32 **x += 1;32 x.*.* += 1;
33}33}
3434
35test "implicitly cast a container to a const pointer of it" {35test "implicitly cast a container to a const pointer of it" {
36 const z = Struct(void) { .x = void{} };36 const z = Struct(void) {
37 .x = void{},
38 };
37 assert(0 == @sizeOf(@typeOf(z)));39 assert(0 == @sizeOf(@typeOf(z)));
38 assert(void{} == Struct(void).pointer(z).x);40 assert(void{} == Struct(void).pointer(z).x);
39 assert(void{} == Struct(void).pointer(&z).x);41 assert(void{} == Struct(void).pointer(&z).x);
40 assert(void{} == Struct(void).maybePointer(z).x);42 assert(void{} == Struct(void).maybePointer(z).x);
41 assert(void{} == Struct(void).maybePointer(&z).x);43 assert(void{} == Struct(void).maybePointer(&z).x);
42 assert(void{} == Struct(void).maybePointer(null).x);44 assert(void{} == Struct(void).maybePointer(null).x);
43 const s = Struct(u8) { .x = 42 };45 const s = Struct(u8) {
46 .x = 42,
47 };
44 assert(0 != @sizeOf(@typeOf(s)));48 assert(0 != @sizeOf(@typeOf(s)));
45 assert(42 == Struct(u8).pointer(s).x);49 assert(42 == Struct(u8).pointer(s).x);
46 assert(42 == Struct(u8).pointer(&s).x);50 assert(42 == Struct(u8).pointer(&s).x);
47 assert(42 == Struct(u8).maybePointer(s).x);51 assert(42 == Struct(u8).maybePointer(s).x);
48 assert(42 == Struct(u8).maybePointer(&s).x);52 assert(42 == Struct(u8).maybePointer(&s).x);
49 assert(0 == Struct(u8).maybePointer(null).x);53 assert(0 == Struct(u8).maybePointer(null).x);
50 const u = Union { .x = 42 };54 const u = Union {
55 .x = 42,
56 };
51 assert(42 == Union.pointer(u).x);57 assert(42 == Union.pointer(u).x);
52 assert(42 == Union.pointer(&u).x);58 assert(42 == Union.pointer(&u).x);
53 assert(42 == Union.maybePointer(u).x);59 assert(42 == Union.maybePointer(u).x);
...@@ -67,12 +73,14 @@ fn Struct(comptime T: type) type {...@@ -67,12 +73,14 @@ fn Struct(comptime T: type) type {
67 x: T,73 x: T,
6874
69 fn pointer(self: &const Self) Self {75 fn pointer(self: &const Self) Self {
70 return *self;76 return self.*;
71 }77 }
7278
73 fn maybePointer(self: ?&const Self) Self {79 fn maybePointer(self: ?&const Self) Self {
74 const none = Self { .x = if (T == void) void{} else 0 };80 const none = Self {
75 return *(self ?? &none);81 .x = if (T == void) void{} else 0,
82 };
83 return (self ?? &none).*;
76 }84 }
77 };85 };
78}86}
...@@ -81,12 +89,14 @@ const Union = union {...@@ -81,12 +89,14 @@ const Union = union {
81 x: u8,89 x: u8,
8290
83 fn pointer(self: &const Union) Union {91 fn pointer(self: &const Union) Union {
84 return *self;92 return self.*;
85 }93 }
8694
87 fn maybePointer(self: ?&const Union) Union {95 fn maybePointer(self: ?&const Union) Union {
88 const none = Union { .x = 0 };96 const none = Union {
89 return *(self ?? &none);97 .x = 0,
98 };
99 return (self ?? &none).*;
90 }100 }
91};101};
92102
...@@ -95,11 +105,11 @@ const Enum = enum {...@@ -95,11 +105,11 @@ const Enum = enum {
95 Some,105 Some,
96106
97 fn pointer(self: &const Enum) Enum {107 fn pointer(self: &const Enum) Enum {
98 return *self;108 return self.*;
99 }109 }
100110
101 fn maybePointer(self: ?&const Enum) Enum {111 fn maybePointer(self: ?&const Enum) Enum {
102 return *(self ?? &Enum.None);112 return (self ?? &Enum.None).*;
103 }113 }
104};114};
105115
...@@ -108,19 +118,21 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" {...@@ -108,19 +118,21 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" {
108 const Self = this;118 const Self = this;
109 x: u8,119 x: u8,
110 fn constConst(p: &const &const Self) u8 {120 fn constConst(p: &const &const Self) u8 {
111 return (*p).x;121 return (p.*).x;
112 }122 }
113 fn maybeConstConst(p: ?&const &const Self) u8 {123 fn maybeConstConst(p: ?&const &const Self) u8 {
114 return (*??p).x;124 return ((??p).*).x;
115 }125 }
116 fn constConstConst(p: &const &const &const Self) u8 {126 fn constConstConst(p: &const &const &const Self) u8 {
117 return (**p).x;127 return (p.*.*).x;
118 }128 }
119 fn maybeConstConstConst(p: ?&const &const &const Self) u8 {129 fn maybeConstConstConst(p: ?&const &const &const Self) u8 {
120 return (**??p).x;130 return ((??p).*.*).x;
121 }131 }
122 };132 };
123 const s = S { .x = 42 };133 const s = S {
134 .x = 42,
135 };
124 const p = &s;136 const p = &s;
125 const q = &p;137 const q = &p;
126 const r = &q;138 const r = &q;
...@@ -154,7 +166,6 @@ fn boolToStr(b: bool) []const u8 {...@@ -154,7 +166,6 @@ fn boolToStr(b: bool) []const u8 {
154 return if (b) "true" else "false";166 return if (b) "true" else "false";
155}167}
156168
157
158test "peer resolve array and const slice" {169test "peer resolve array and const slice" {
159 testPeerResolveArrayConstSlice(true);170 testPeerResolveArrayConstSlice(true);
160 comptime testPeerResolveArrayConstSlice(true);171 comptime testPeerResolveArrayConstSlice(true);
...@@ -168,12 +179,12 @@ fn testPeerResolveArrayConstSlice(b: bool) void {...@@ -168,12 +179,12 @@ fn testPeerResolveArrayConstSlice(b: bool) void {
168179
169test "integer literal to &const int" {180test "integer literal to &const int" {
170 const x: &const i32 = 3;181 const x: &const i32 = 3;
171 assert(*x == 3);182 assert(x.* == 3);
172}183}
173184
174test "string literal to &const []const u8" {185test "string literal to &const []const u8" {
175 const x: &const []const u8 = "hello";186 const x: &const []const u8 = "hello";
176 assert(mem.eql(u8, *x, "hello"));187 assert(mem.eql(u8, x.*, "hello"));
177}188}
178189
179test "implicitly cast from T to error!?T" {190test "implicitly cast from T to error!?T" {
...@@ -191,7 +202,9 @@ fn castToMaybeTypeError(z: i32) void {...@@ -191,7 +202,9 @@ fn castToMaybeTypeError(z: i32) void {
191 const f = z;202 const f = z;
192 const g: error!?i32 = f;203 const g: error!?i32 = f;
193204
194 const a = A{ .a = z };205 const a = A {
206 .a = z,
207 };
195 const b: error!?A = a;208 const b: error!?A = a;
196 assert((??(b catch unreachable)).a == 1);209 assert((??(b catch unreachable)).a == 1);
197}210}
...@@ -205,7 +218,6 @@ fn implicitIntLitToMaybe() void {...@@ -205,7 +218,6 @@ fn implicitIntLitToMaybe() void {
205 const g: error!?i32 = 1;218 const g: error!?i32 = 1;
206}219}
207220
208
209test "return null from fn() error!?&T" {221test "return null from fn() error!?&T" {
210 const a = returnNullFromMaybeTypeErrorRef();222 const a = returnNullFromMaybeTypeErrorRef();
211 const b = returnNullLitFromMaybeTypeErrorRef();223 const b = returnNullLitFromMaybeTypeErrorRef();
...@@ -235,7 +247,6 @@ fn peerTypeTAndMaybeT(c: bool, b: bool) ?usize {...@@ -235,7 +247,6 @@ fn peerTypeTAndMaybeT(c: bool, b: bool) ?usize {
235 return usize(3);247 return usize(3);
236}248}
237249
238
239test "peer type resolution: [0]u8 and []const u8" {250test "peer type resolution: [0]u8 and []const u8" {
240 assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);251 assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
241 assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);252 assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
...@@ -246,7 +257,7 @@ test "peer type resolution: [0]u8 and []const u8" {...@@ -246,7 +257,7 @@ test "peer type resolution: [0]u8 and []const u8" {
246}257}
247fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {258fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
248 if (a) {259 if (a) {
249 return []const u8 {};260 return []const u8{};
250 }261 }
251262
252 return slice[0..1];263 return slice[0..1];
...@@ -261,7 +272,6 @@ fn castToMaybeSlice() ?[]const u8 {...@@ -261,7 +272,6 @@ fn castToMaybeSlice() ?[]const u8 {
261 return "hi";272 return "hi";
262}273}
263274
264
265test "implicitly cast from [0]T to error![]T" {275test "implicitly cast from [0]T to error![]T" {
266 testCastZeroArrayToErrSliceMut();276 testCastZeroArrayToErrSliceMut();
267 comptime testCastZeroArrayToErrSliceMut();277 comptime testCastZeroArrayToErrSliceMut();
...@@ -329,7 +339,6 @@ fn foo(args: ...) void {...@@ -329,7 +339,6 @@ fn foo(args: ...) void {
329 assert(@typeOf(args[0]) == &const [5]u8);339 assert(@typeOf(args[0]) == &const [5]u8);
330}340}
331341
332
333test "peer type resolution: error and [N]T" {342test "peer type resolution: error and [N]T" {
334 // TODO: implicit error!T to error!U where T can implicitly cast to U343 // TODO: implicit error!T to error!U where T can implicitly cast to U
335 //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));344 //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
...@@ -378,7 +387,12 @@ fn cast128Float(x: u128) f128 {...@@ -378,7 +387,12 @@ fn cast128Float(x: u128) f128 {
378}387}
379388
380test "const slice widen cast" {389test "const slice widen cast" {
381 const bytes align(4) = []u8{0x12, 0x12, 0x12, 0x12};390 const bytes align(4) = []u8 {
391 0x12,
392 0x12,
393 0x12,
394 0x12,
395 };
382396
383 const u32_value = ([]const u32)(bytes[0..])[0];397 const u32_value = ([]const u32)(bytes[0..])[0];
384 assert(u32_value == 0x12121212);398 assert(u32_value == 0x12121212);
test/cases/coroutines.zig+9-9
...@@ -36,7 +36,7 @@ async fn testAsyncSeq() void {...@@ -36,7 +36,7 @@ async fn testAsyncSeq() void {
36 suspend;36 suspend;
37 seq('d');37 seq('d');
38}38}
39var points = []u8{0} ** "abcdefg".len;39var points = []u8 {0} ** "abcdefg".len;
40var index: usize = 0;40var index: usize = 0;
4141
42fn seq(c: u8) void {42fn seq(c: u8) void {
...@@ -94,7 +94,7 @@ async fn await_another() i32 {...@@ -94,7 +94,7 @@ async fn await_another() i32 {
94 return 1234;94 return 1234;
95}95}
9696
97var await_points = []u8{0} ** "abcdefghi".len;97var await_points = []u8 {0} ** "abcdefghi".len;
98var await_seq_index: usize = 0;98var await_seq_index: usize = 0;
9999
100fn await_seq(c: u8) void {100fn await_seq(c: u8) void {
...@@ -102,7 +102,6 @@ fn await_seq(c: u8) void {...@@ -102,7 +102,6 @@ fn await_seq(c: u8) void {
102 await_seq_index += 1;102 await_seq_index += 1;
103}103}
104104
105
106var early_final_result: i32 = 0;105var early_final_result: i32 = 0;
107106
108test "coroutine await early return" {107test "coroutine await early return" {
...@@ -126,7 +125,7 @@ async fn early_another() i32 {...@@ -126,7 +125,7 @@ async fn early_another() i32 {
126 return 1234;125 return 1234;
127}126}
128127
129var early_points = []u8{0} ** "abcdef".len;128var early_points = []u8 {0} ** "abcdef".len;
130var early_seq_index: usize = 0;129var early_seq_index: usize = 0;
131130
132fn early_seq(c: u8) void {131fn early_seq(c: u8) void {
...@@ -175,8 +174,8 @@ test "async fn pointer in a struct field" {...@@ -175,8 +174,8 @@ test "async fn pointer in a struct field" {
175}174}
176175
177async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {176async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {
178 defer *y += 2;177 defer y.* += 2;
179 *y += 1;178 y.* += 1;
180 suspend;179 suspend;
181}180}
182181
...@@ -205,7 +204,8 @@ test "error return trace across suspend points - async return" {...@@ -205,7 +204,8 @@ test "error return trace across suspend points - async return" {
205 cancel p2;204 cancel p2;
206}205}
207206
208fn nonFailing() promise->error!void {207// TODO https://github.com/ziglang/zig/issues/760
208fn nonFailing() (promise->error!void) {
209 return async<std.debug.global_allocator> suspendThenFail() catch unreachable;209 return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
210}210}
211211
...@@ -239,7 +239,7 @@ async fn testBreakFromSuspend(my_result: &i32) void {...@@ -239,7 +239,7 @@ async fn testBreakFromSuspend(my_result: &i32) void {
239 s: suspend |p| {239 s: suspend |p| {
240 break :s;240 break :s;
241 }241 }
242 *my_result += 1;242 my_result.* += 1;
243 suspend;243 suspend;
244 *my_result += 1;244 my_result.* += 1;
245}245}
test/cases/defer.zig+12-3
...@@ -5,9 +5,18 @@ var index: usize = undefined;...@@ -5,9 +5,18 @@ var index: usize = undefined;
55
6fn runSomeErrorDefers(x: bool) !bool {6fn runSomeErrorDefers(x: bool) !bool {
7 index = 0;7 index = 0;
8 defer {result[index] = 'a'; index += 1;}8 defer {
9 errdefer {result[index] = 'b'; index += 1;}9 result[index] = 'a';
10 defer {result[index] = 'c'; index += 1;}10 index += 1;
11 }
12 errdefer {
13 result[index] = 'b';
14 index += 1;
15 }
16 defer {
17 result[index] = 'c';
18 index += 1;
19 }
11 return if (x) x else error.FalseNotAllowed;20 return if (x) x else error.FalseNotAllowed;
12}21}
1322
test/cases/enum.zig+548-58
...@@ -2,8 +2,15 @@ const assert = @import("std").debug.assert;...@@ -2,8 +2,15 @@ const assert = @import("std").debug.assert;
2const mem = @import("std").mem;2const mem = @import("std").mem;
33
4test "enum type" {4test "enum type" {
5 const foo1 = Foo{ .One = 13};5 const foo1 = Foo {
6 const foo2 = Foo{. Two = Point { .x = 1234, .y = 5678, }};6 .One = 13,
7 };
8 const foo2 = Foo {
9 .Two = Point {
10 .x = 1234,
11 .y = 5678,
12 },
13 };
7 const bar = Bar.B;14 const bar = Bar.B;
815
9 assert(bar == Bar.B);16 assert(bar == Bar.B);
...@@ -41,26 +48,31 @@ const Bar = enum {...@@ -41,26 +48,31 @@ const Bar = enum {
41};48};
4249
43fn returnAnInt(x: i32) Foo {50fn returnAnInt(x: i32) Foo {
44 return Foo { .One = x };51 return Foo {
52 .One = x,
53 };
45}54}
4655
47
48test "constant enum with payload" {56test "constant enum with payload" {
49 var empty = AnEnumWithPayload {.Empty = {}};57 var empty = AnEnumWithPayload {
50 var full = AnEnumWithPayload {.Full = 13};58 .Empty = {},
59 };
60 var full = AnEnumWithPayload {
61 .Full = 13,
62 };
51 shouldBeEmpty(empty);63 shouldBeEmpty(empty);
52 shouldBeNotEmpty(full);64 shouldBeNotEmpty(full);
53}65}
5466
55fn shouldBeEmpty(x: &const AnEnumWithPayload) void {67fn shouldBeEmpty(x: &const AnEnumWithPayload) void {
56 switch (*x) {68 switch (x.*) {
57 AnEnumWithPayload.Empty => {},69 AnEnumWithPayload.Empty => {},
58 else => unreachable,70 else => unreachable,
59 }71 }
60}72}
6173
62fn shouldBeNotEmpty(x: &const AnEnumWithPayload) void {74fn shouldBeNotEmpty(x: &const AnEnumWithPayload) void {
63 switch (*x) {75 switch (x.*) {
64 AnEnumWithPayload.Empty => unreachable,76 AnEnumWithPayload.Empty => unreachable,
65 else => {},77 else => {},
66 }78 }
...@@ -71,8 +83,6 @@ const AnEnumWithPayload = union(enum) {...@@ -71,8 +83,6 @@ const AnEnumWithPayload = union(enum) {
71 Full: i32,83 Full: i32,
72};84};
7385
74
75
76const Number = enum {86const Number = enum {
77 Zero,87 Zero,
78 One,88 One,
...@@ -93,7 +103,6 @@ fn shouldEqual(n: Number, expected: u3) void {...@@ -93,7 +103,6 @@ fn shouldEqual(n: Number, expected: u3) void {
93 assert(u3(n) == expected);103 assert(u3(n) == expected);
94}104}
95105
96
97test "int to enum" {106test "int to enum" {
98 testIntToEnumEval(3);107 testIntToEnumEval(3);
99}108}
...@@ -108,7 +117,6 @@ const IntToEnumNumber = enum {...@@ -108,7 +117,6 @@ const IntToEnumNumber = enum {
108 Four,117 Four,
109};118};
110119
111
112test "@tagName" {120test "@tagName" {
113 assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));121 assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
114 comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));122 comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
...@@ -124,7 +132,6 @@ const BareNumber = enum {...@@ -124,7 +132,6 @@ const BareNumber = enum {
124 Three,132 Three,
125};133};
126134
127
128test "enum alignment" {135test "enum alignment" {
129 comptime {136 comptime {
130 assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));137 assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
...@@ -137,47 +144,529 @@ const AlignTestEnum = union(enum) {...@@ -137,47 +144,529 @@ const AlignTestEnum = union(enum) {
137 B: u64,144 B: u64,
138};145};
139146
140const ValueCount1 = enum { I0 };147const ValueCount1 = enum {
141const ValueCount2 = enum { I0, I1 };148 I0,
149};
150const ValueCount2 = enum {
151 I0,
152 I1,
153};
142const ValueCount256 = enum {154const ValueCount256 = enum {
143 I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15,155 I0,
144 I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31,156 I1,
145 I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47,157 I2,
146 I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63,158 I3,
147 I64, I65, I66, I67, I68, I69, I70, I71, I72, I73, I74, I75, I76, I77, I78, I79,159 I4,
148 I80, I81, I82, I83, I84, I85, I86, I87, I88, I89, I90, I91, I92, I93, I94, I95,160 I5,
149 I96, I97, I98, I99, I100, I101, I102, I103, I104, I105, I106, I107, I108, I109,161 I6,
150 I110, I111, I112, I113, I114, I115, I116, I117, I118, I119, I120, I121, I122, I123,162 I7,
151 I124, I125, I126, I127, I128, I129, I130, I131, I132, I133, I134, I135, I136, I137,163 I8,
152 I138, I139, I140, I141, I142, I143, I144, I145, I146, I147, I148, I149, I150, I151,164 I9,
153 I152, I153, I154, I155, I156, I157, I158, I159, I160, I161, I162, I163, I164, I165,165 I10,
154 I166, I167, I168, I169, I170, I171, I172, I173, I174, I175, I176, I177, I178, I179,166 I11,
155 I180, I181, I182, I183, I184, I185, I186, I187, I188, I189, I190, I191, I192, I193,167 I12,
156 I194, I195, I196, I197, I198, I199, I200, I201, I202, I203, I204, I205, I206, I207,168 I13,
157 I208, I209, I210, I211, I212, I213, I214, I215, I216, I217, I218, I219, I220, I221,169 I14,
158 I222, I223, I224, I225, I226, I227, I228, I229, I230, I231, I232, I233, I234, I235,170 I15,
159 I236, I237, I238, I239, I240, I241, I242, I243, I244, I245, I246, I247, I248, I249,171 I16,
160 I250, I251, I252, I253, I254, I255172 I17,
173 I18,
174 I19,
175 I20,
176 I21,
177 I22,
178 I23,
179 I24,
180 I25,
181 I26,
182 I27,
183 I28,
184 I29,
185 I30,
186 I31,
187 I32,
188 I33,
189 I34,
190 I35,
191 I36,
192 I37,
193 I38,
194 I39,
195 I40,
196 I41,
197 I42,
198 I43,
199 I44,
200 I45,
201 I46,
202 I47,
203 I48,
204 I49,
205 I50,
206 I51,
207 I52,
208 I53,
209 I54,
210 I55,
211 I56,
212 I57,
213 I58,
214 I59,
215 I60,
216 I61,
217 I62,
218 I63,
219 I64,
220 I65,
221 I66,
222 I67,
223 I68,
224 I69,
225 I70,
226 I71,
227 I72,
228 I73,
229 I74,
230 I75,
231 I76,
232 I77,
233 I78,
234 I79,
235 I80,
236 I81,
237 I82,
238 I83,
239 I84,
240 I85,
241 I86,
242 I87,
243 I88,
244 I89,
245 I90,
246 I91,
247 I92,
248 I93,
249 I94,
250 I95,
251 I96,
252 I97,
253 I98,
254 I99,
255 I100,
256 I101,
257 I102,
258 I103,
259 I104,
260 I105,
261 I106,
262 I107,
263 I108,
264 I109,
265 I110,
266 I111,
267 I112,
268 I113,
269 I114,
270 I115,
271 I116,
272 I117,
273 I118,
274 I119,
275 I120,
276 I121,
277 I122,
278 I123,
279 I124,
280 I125,
281 I126,
282 I127,
283 I128,
284 I129,
285 I130,
286 I131,
287 I132,
288 I133,
289 I134,
290 I135,
291 I136,
292 I137,
293 I138,
294 I139,
295 I140,
296 I141,
297 I142,
298 I143,
299 I144,
300 I145,
301 I146,
302 I147,
303 I148,
304 I149,
305 I150,
306 I151,
307 I152,
308 I153,
309 I154,
310 I155,
311 I156,
312 I157,
313 I158,
314 I159,
315 I160,
316 I161,
317 I162,
318 I163,
319 I164,
320 I165,
321 I166,
322 I167,
323 I168,
324 I169,
325 I170,
326 I171,
327 I172,
328 I173,
329 I174,
330 I175,
331 I176,
332 I177,
333 I178,
334 I179,
335 I180,
336 I181,
337 I182,
338 I183,
339 I184,
340 I185,
341 I186,
342 I187,
343 I188,
344 I189,
345 I190,
346 I191,
347 I192,
348 I193,
349 I194,
350 I195,
351 I196,
352 I197,
353 I198,
354 I199,
355 I200,
356 I201,
357 I202,
358 I203,
359 I204,
360 I205,
361 I206,
362 I207,
363 I208,
364 I209,
365 I210,
366 I211,
367 I212,
368 I213,
369 I214,
370 I215,
371 I216,
372 I217,
373 I218,
374 I219,
375 I220,
376 I221,
377 I222,
378 I223,
379 I224,
380 I225,
381 I226,
382 I227,
383 I228,
384 I229,
385 I230,
386 I231,
387 I232,
388 I233,
389 I234,
390 I235,
391 I236,
392 I237,
393 I238,
394 I239,
395 I240,
396 I241,
397 I242,
398 I243,
399 I244,
400 I245,
401 I246,
402 I247,
403 I248,
404 I249,
405 I250,
406 I251,
407 I252,
408 I253,
409 I254,
410 I255,
161};411};
162const ValueCount257 = enum {412const ValueCount257 = enum {
163 I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15,413 I0,
164 I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31,414 I1,
165 I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47,415 I2,
166 I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63,416 I3,
167 I64, I65, I66, I67, I68, I69, I70, I71, I72, I73, I74, I75, I76, I77, I78, I79,417 I4,
168 I80, I81, I82, I83, I84, I85, I86, I87, I88, I89, I90, I91, I92, I93, I94, I95,418 I5,
169 I96, I97, I98, I99, I100, I101, I102, I103, I104, I105, I106, I107, I108, I109,419 I6,
170 I110, I111, I112, I113, I114, I115, I116, I117, I118, I119, I120, I121, I122, I123,420 I7,
171 I124, I125, I126, I127, I128, I129, I130, I131, I132, I133, I134, I135, I136, I137,421 I8,
172 I138, I139, I140, I141, I142, I143, I144, I145, I146, I147, I148, I149, I150, I151,422 I9,
173 I152, I153, I154, I155, I156, I157, I158, I159, I160, I161, I162, I163, I164, I165,423 I10,
174 I166, I167, I168, I169, I170, I171, I172, I173, I174, I175, I176, I177, I178, I179,424 I11,
175 I180, I181, I182, I183, I184, I185, I186, I187, I188, I189, I190, I191, I192, I193,425 I12,
176 I194, I195, I196, I197, I198, I199, I200, I201, I202, I203, I204, I205, I206, I207,426 I13,
177 I208, I209, I210, I211, I212, I213, I214, I215, I216, I217, I218, I219, I220, I221,427 I14,
178 I222, I223, I224, I225, I226, I227, I228, I229, I230, I231, I232, I233, I234, I235,428 I15,
179 I236, I237, I238, I239, I240, I241, I242, I243, I244, I245, I246, I247, I248, I249,429 I16,
180 I250, I251, I252, I253, I254, I255, I256430 I17,
431 I18,
432 I19,
433 I20,
434 I21,
435 I22,
436 I23,
437 I24,
438 I25,
439 I26,
440 I27,
441 I28,
442 I29,
443 I30,
444 I31,
445 I32,
446 I33,
447 I34,
448 I35,
449 I36,
450 I37,
451 I38,
452 I39,
453 I40,
454 I41,
455 I42,
456 I43,
457 I44,
458 I45,
459 I46,
460 I47,
461 I48,
462 I49,
463 I50,
464 I51,
465 I52,
466 I53,
467 I54,
468 I55,
469 I56,
470 I57,
471 I58,
472 I59,
473 I60,
474 I61,
475 I62,
476 I63,
477 I64,
478 I65,
479 I66,
480 I67,
481 I68,
482 I69,
483 I70,
484 I71,
485 I72,
486 I73,
487 I74,
488 I75,
489 I76,
490 I77,
491 I78,
492 I79,
493 I80,
494 I81,
495 I82,
496 I83,
497 I84,
498 I85,
499 I86,
500 I87,
501 I88,
502 I89,
503 I90,
504 I91,
505 I92,
506 I93,
507 I94,
508 I95,
509 I96,
510 I97,
511 I98,
512 I99,
513 I100,
514 I101,
515 I102,
516 I103,
517 I104,
518 I105,
519 I106,
520 I107,
521 I108,
522 I109,
523 I110,
524 I111,
525 I112,
526 I113,
527 I114,
528 I115,
529 I116,
530 I117,
531 I118,
532 I119,
533 I120,
534 I121,
535 I122,
536 I123,
537 I124,
538 I125,
539 I126,
540 I127,
541 I128,
542 I129,
543 I130,
544 I131,
545 I132,
546 I133,
547 I134,
548 I135,
549 I136,
550 I137,
551 I138,
552 I139,
553 I140,
554 I141,
555 I142,
556 I143,
557 I144,
558 I145,
559 I146,
560 I147,
561 I148,
562 I149,
563 I150,
564 I151,
565 I152,
566 I153,
567 I154,
568 I155,
569 I156,
570 I157,
571 I158,
572 I159,
573 I160,
574 I161,
575 I162,
576 I163,
577 I164,
578 I165,
579 I166,
580 I167,
581 I168,
582 I169,
583 I170,
584 I171,
585 I172,
586 I173,
587 I174,
588 I175,
589 I176,
590 I177,
591 I178,
592 I179,
593 I180,
594 I181,
595 I182,
596 I183,
597 I184,
598 I185,
599 I186,
600 I187,
601 I188,
602 I189,
603 I190,
604 I191,
605 I192,
606 I193,
607 I194,
608 I195,
609 I196,
610 I197,
611 I198,
612 I199,
613 I200,
614 I201,
615 I202,
616 I203,
617 I204,
618 I205,
619 I206,
620 I207,
621 I208,
622 I209,
623 I210,
624 I211,
625 I212,
626 I213,
627 I214,
628 I215,
629 I216,
630 I217,
631 I218,
632 I219,
633 I220,
634 I221,
635 I222,
636 I223,
637 I224,
638 I225,
639 I226,
640 I227,
641 I228,
642 I229,
643 I230,
644 I231,
645 I232,
646 I233,
647 I234,
648 I235,
649 I236,
650 I237,
651 I238,
652 I239,
653 I240,
654 I241,
655 I242,
656 I243,
657 I244,
658 I245,
659 I246,
660 I247,
661 I248,
662 I249,
663 I250,
664 I251,
665 I252,
666 I253,
667 I254,
668 I255,
669 I256,
181};670};
182671
183test "enum sizes" {672test "enum sizes" {
...@@ -189,11 +678,11 @@ test "enum sizes" {...@@ -189,11 +678,11 @@ test "enum sizes" {
189 }678 }
190}679}
191680
192const Small2 = enum (u2) {681const Small2 = enum(u2) {
193 One,682 One,
194 Two,683 Two,
195};684};
196const Small = enum (u2) {685const Small = enum(u2) {
197 One,686 One,
198 Two,687 Two,
199 Three,688 Three,
...@@ -213,8 +702,7 @@ test "set enum tag type" {...@@ -213,8 +702,7 @@ test "set enum tag type" {
213 }702 }
214}703}
215704
216705const A = enum(u3) {
217const A = enum (u3) {
218 One,706 One,
219 Two,707 Two,
220 Three,708 Three,
...@@ -225,7 +713,7 @@ const A = enum (u3) {...@@ -225,7 +713,7 @@ const A = enum (u3) {
225 Four2,713 Four2,
226};714};
227715
228const B = enum (u3) {716const B = enum(u3) {
229 One3,717 One3,
230 Two3,718 Two3,
231 Three3,719 Three3,
...@@ -236,7 +724,7 @@ const B = enum (u3) {...@@ -236,7 +724,7 @@ const B = enum (u3) {
236 Four23,724 Four23,
237};725};
238726
239const C = enum (u2) {727const C = enum(u2) {
240 One4,728 One4,
241 Two4,729 Two4,
242 Three4,730 Three4,
...@@ -389,7 +877,9 @@ test "enum with tag values don't require parens" {...@@ -389,7 +877,9 @@ test "enum with tag values don't require parens" {
389}877}
390878
391test "enum with 1 field but explicit tag type should still have the tag type" {879test "enum with 1 field but explicit tag type should still have the tag type" {
392 const Enum = enum(u8) { B = 2 };880 const Enum = enum(u8) {
881 B = 2,
882 };
393 comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));883 comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
394}884}
395885
test/cases/enum_with_members.zig+7-3
...@@ -7,7 +7,7 @@ const ET = union(enum) {...@@ -7,7 +7,7 @@ const ET = union(enum) {
7 UINT: u32,7 UINT: u32,
88
9 pub fn print(a: &const ET, buf: []u8) error!usize {9 pub fn print(a: &const ET, buf: []u8) error!usize {
10 return switch (*a) {10 return switch (a.*) {
11 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),11 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
12 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),12 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
13 };13 };
...@@ -15,8 +15,12 @@ const ET = union(enum) {...@@ -15,8 +15,12 @@ const ET = union(enum) {
15};15};
1616
17test "enum with members" {17test "enum with members" {
18 const a = ET { .SINT = -42 };18 const a = ET {
19 const b = ET { .UINT = 42 };19 .SINT = -42,
20 };
21 const b = ET {
22 .UINT = 42,
23 };
20 var buf: [20]u8 = undefined;24 var buf: [20]u8 = undefined;
2125
22 assert((a.print(buf[0..]) catch unreachable) == 3);26 assert((a.print(buf[0..]) catch unreachable) == 3);
test/cases/error.zig+30-26
...@@ -30,14 +30,12 @@ test "@errorName" {...@@ -30,14 +30,12 @@ test "@errorName" {
30 assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));30 assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
31}31}
3232
33
34test "error values" {33test "error values" {
35 const a = i32(error.err1);34 const a = i32(error.err1);
36 const b = i32(error.err2);35 const b = i32(error.err2);
37 assert(a != b);36 assert(a != b);
38}37}
3938
40
41test "redefinition of error values allowed" {39test "redefinition of error values allowed" {
42 shouldBeNotEqual(error.AnError, error.SecondError);40 shouldBeNotEqual(error.AnError, error.SecondError);
43}41}
...@@ -45,7 +43,6 @@ fn shouldBeNotEqual(a: error, b: error) void {...@@ -45,7 +43,6 @@ fn shouldBeNotEqual(a: error, b: error) void {
45 if (a == b) unreachable;43 if (a == b) unreachable;
46}44}
4745
48
49test "error binary operator" {46test "error binary operator" {
50 const a = errBinaryOperatorG(true) catch 3;47 const a = errBinaryOperatorG(true) catch 3;
51 const b = errBinaryOperatorG(false) catch 3;48 const b = errBinaryOperatorG(false) catch 3;
...@@ -56,20 +53,20 @@ fn errBinaryOperatorG(x: bool) error!isize {...@@ -56,20 +53,20 @@ fn errBinaryOperatorG(x: bool) error!isize {
56 return if (x) error.ItBroke else isize(10);53 return if (x) error.ItBroke else isize(10);
57}54}
5855
59
60test "unwrap simple value from error" {56test "unwrap simple value from error" {
61 const i = unwrapSimpleValueFromErrorDo() catch unreachable;57 const i = unwrapSimpleValueFromErrorDo() catch unreachable;
62 assert(i == 13);58 assert(i == 13);
63}59}
64fn unwrapSimpleValueFromErrorDo() error!isize { return 13; }60fn unwrapSimpleValueFromErrorDo() error!isize {
6561 return 13;
62}
6663
67test "error return in assignment" {64test "error return in assignment" {
68 doErrReturnInAssignment() catch unreachable;65 doErrReturnInAssignment() catch unreachable;
69}66}
7067
71fn doErrReturnInAssignment() error!void {68fn doErrReturnInAssignment() error!void {
72 var x : i32 = undefined;69 var x: i32 = undefined;
73 x = try makeANonErr();70 x = try makeANonErr();
74}71}
7572
...@@ -95,7 +92,10 @@ test "error set type " {...@@ -95,7 +92,10 @@ test "error set type " {
95 comptime testErrorSetType();92 comptime testErrorSetType();
96}93}
9794
98const MyErrSet = error {OutOfMemory, FileNotFound};95const MyErrSet = error {
96 OutOfMemory,
97 FileNotFound,
98};
9999
100fn testErrorSetType() void {100fn testErrorSetType() void {
101 assert(@memberCount(MyErrSet) == 2);101 assert(@memberCount(MyErrSet) == 2);
...@@ -109,14 +109,19 @@ fn testErrorSetType() void {...@@ -109,14 +109,19 @@ fn testErrorSetType() void {
109 }109 }
110}110}
111111
112
113test "explicit error set cast" {112test "explicit error set cast" {
114 testExplicitErrorSetCast(Set1.A);113 testExplicitErrorSetCast(Set1.A);
115 comptime testExplicitErrorSetCast(Set1.A);114 comptime testExplicitErrorSetCast(Set1.A);
116}115}
117116
118const Set1 = error{A, B};117const Set1 = error {
119const Set2 = error{A, C};118 A,
119 B,
120};
121const Set2 = error {
122 A,
123 C,
124};
120125
121fn testExplicitErrorSetCast(set1: Set1) void {126fn testExplicitErrorSetCast(set1: Set1) void {
122 var x = Set2(set1);127 var x = Set2(set1);
...@@ -129,7 +134,8 @@ test "comptime test error for empty error set" {...@@ -129,7 +134,8 @@ test "comptime test error for empty error set" {
129 comptime testComptimeTestErrorEmptySet(1234);134 comptime testComptimeTestErrorEmptySet(1234);
130}135}
131136
132const EmptyErrorSet = error {};137const EmptyErrorSet = error {
138};
133139
134fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {140fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
135 if (x) |v| assert(v == 1234) else |err| @compileError("bad");141 if (x) |v| assert(v == 1234) else |err| @compileError("bad");
...@@ -145,7 +151,9 @@ test "comptime err to int of error set with only 1 possible value" {...@@ -145,7 +151,9 @@ test "comptime err to int of error set with only 1 possible value" {
145 testErrToIntWithOnePossibleValue(error.A, u32(error.A));151 testErrToIntWithOnePossibleValue(error.A, u32(error.A));
146 comptime testErrToIntWithOnePossibleValue(error.A, u32(error.A));152 comptime testErrToIntWithOnePossibleValue(error.A, u32(error.A));
147}153}
148fn testErrToIntWithOnePossibleValue(x: error{A}, comptime value: u32) void {154fn testErrToIntWithOnePossibleValue(x: error {
155 A,
156}, comptime value: u32) void {
149 if (u32(x) != value) {157 if (u32(x) != value) {
150 @compileError("bad");158 @compileError("bad");
151 }159 }
...@@ -176,7 +184,6 @@ fn quux_1() !i32 {...@@ -176,7 +184,6 @@ fn quux_1() !i32 {
176 return error.C;184 return error.C;
177}185}
178186
179
180test "error: fn returning empty error set can be passed as fn returning any error" {187test "error: fn returning empty error set can be passed as fn returning any error" {
181 entry();188 entry();
182 comptime entry();189 comptime entry();
...@@ -186,24 +193,24 @@ fn entry() void {...@@ -186,24 +193,24 @@ fn entry() void {
186 foo2(bar2);193 foo2(bar2);
187}194}
188195
189fn foo2(f: fn()error!void) void {196fn foo2(f: fn() error!void) void {
190 const x = f();197 const x = f();
191}198}
192199
193fn bar2() (error{}!void) { }200fn bar2() (error {
194201}!void) {}
195202
196test "error: Zero sized error set returned with value payload crash" {203test "error: Zero sized error set returned with value payload crash" {
197 _ = foo3(0);204 _ = foo3(0);
198 _ = comptime foo3(0);205 _ = comptime foo3(0);
199}206}
200207
201const Error = error{};208const Error = error {
209};
202fn foo3(b: usize) Error!usize {210fn foo3(b: usize) Error!usize {
203 return b;211 return b;
204}212}
205213
206
207test "error: Infer error set from literals" {214test "error: Infer error set from literals" {
208 _ = nullLiteral("n") catch |err| handleErrors(err);215 _ = nullLiteral("n") catch |err| handleErrors(err);
209 _ = floatLiteral("n") catch |err| handleErrors(err);216 _ = floatLiteral("n") catch |err| handleErrors(err);
...@@ -215,29 +222,26 @@ test "error: Infer error set from literals" {...@@ -215,29 +222,26 @@ test "error: Infer error set from literals" {
215222
216fn handleErrors(err: var) noreturn {223fn handleErrors(err: var) noreturn {
217 switch (err) {224 switch (err) {
218 error.T => {}225 error.T => {},
219 }226 }
220227
221 unreachable;228 unreachable;
222}229}
223230
224fn nullLiteral(str: []const u8) !?i64 {231fn nullLiteral(str: []const u8) !?i64 {
225 if (str[0] == 'n')232 if (str[0] == 'n') return null;
226 return null;
227233
228 return error.T;234 return error.T;
229}235}
230236
231fn floatLiteral(str: []const u8) !?f64 {237fn floatLiteral(str: []const u8) !?f64 {
232 if (str[0] == 'n')238 if (str[0] == 'n') return 1.0;
233 return 1.0;
234239
235 return error.T;240 return error.T;
236}241}
237242
238fn intLiteral(str: []const u8) !?i64 {243fn intLiteral(str: []const u8) !?i64 {
239 if (str[0] == 'n')244 if (str[0] == 'n') return 1;
240 return 1;
241245
242 return error.T;246 return error.T;
243}247}
test/cases/eval.zig+105-55
...@@ -11,8 +11,6 @@ fn fibonacci(x: i32) i32 {...@@ -11,8 +11,6 @@ fn fibonacci(x: i32) i32 {
11 return fibonacci(x - 1) + fibonacci(x - 2);11 return fibonacci(x - 1) + fibonacci(x - 2);
12}12}
1313
14
15
16fn unwrapAndAddOne(blah: ?i32) i32 {14fn unwrapAndAddOne(blah: ?i32) i32 {
17 return ??blah + 1;15 return ??blah + 1;
18}16}
...@@ -40,13 +38,13 @@ test "inline variable gets result of const if" {...@@ -40,13 +38,13 @@ test "inline variable gets result of const if" {
40 assert(gimme1or2(false) == 2);38 assert(gimme1or2(false) == 2);
41}39}
4240
43
44test "static function evaluation" {41test "static function evaluation" {
45 assert(statically_added_number == 3);42 assert(statically_added_number == 3);
46}43}
47const statically_added_number = staticAdd(1, 2);44const statically_added_number = staticAdd(1, 2);
48fn staticAdd(a: i32, b: i32) i32 { return a + b; }45fn staticAdd(a: i32, b: i32) i32 {
4946 return a + b;
47}
5048
51test "const expr eval on single expr blocks" {49test "const expr eval on single expr blocks" {
52 assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3);50 assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
...@@ -64,9 +62,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {...@@ -64,9 +62,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
64 return result;62 return result;
65}63}
6664
67
68
69
70test "statically initialized list" {65test "statically initialized list" {
71 assert(static_point_list[0].x == 1);66 assert(static_point_list[0].x == 1);
72 assert(static_point_list[0].y == 2);67 assert(static_point_list[0].y == 2);
...@@ -77,7 +72,10 @@ const Point = struct {...@@ -77,7 +72,10 @@ const Point = struct {
77 x: i32,72 x: i32,
78 y: i32,73 y: i32,
79};74};
80const static_point_list = []Point { makePoint(1, 2), makePoint(3, 4) };75const static_point_list = []Point {
76 makePoint(1, 2),
77 makePoint(3, 4),
78};
81fn makePoint(x: i32, y: i32) Point {79fn makePoint(x: i32, y: i32) Point {
82 return Point {80 return Point {
83 .x = x,81 .x = x,
...@@ -85,7 +83,6 @@ fn makePoint(x: i32, y: i32) Point {...@@ -85,7 +83,6 @@ fn makePoint(x: i32, y: i32) Point {
85 };83 };
86}84}
8785
88
89test "static eval list init" {86test "static eval list init" {
90 assert(static_vec3.data[2] == 1.0);87 assert(static_vec3.data[2] == 1.0);
91 assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0);88 assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
...@@ -96,17 +93,19 @@ pub const Vec3 = struct {...@@ -96,17 +93,19 @@ pub const Vec3 = struct {
96};93};
97pub fn vec3(x: f32, y: f32, z: f32) Vec3 {94pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
98 return Vec3 {95 return Vec3 {
99 .data = []f32 { x, y, z, },96 .data = []f32 {
97 x,
98 y,
99 z,
100 },
100 };101 };
101}102}
102103
103
104test "constant expressions" {104test "constant expressions" {
105 var array : [array_size]u8 = undefined;105 var array: [array_size]u8 = undefined;
106 assert(@sizeOf(@typeOf(array)) == 20);106 assert(@sizeOf(@typeOf(array)) == 20);
107}107}
108const array_size : u8 = 20;108const array_size: u8 = 20;
109
110109
111test "constant struct with negation" {110test "constant struct with negation" {
112 assert(vertices[0].x == -0.6);111 assert(vertices[0].x == -0.6);
...@@ -119,12 +118,29 @@ const Vertex = struct {...@@ -119,12 +118,29 @@ const Vertex = struct {
119 b: f32,118 b: f32,
120};119};
121const vertices = []Vertex {120const vertices = []Vertex {
122 Vertex { .x = -0.6, .y = -0.4, .r = 1.0, .g = 0.0, .b = 0.0 },121 Vertex {
123 Vertex { .x = 0.6, .y = -0.4, .r = 0.0, .g = 1.0, .b = 0.0 },122 .x = -0.6,
124 Vertex { .x = 0.0, .y = 0.6, .r = 0.0, .g = 0.0, .b = 1.0 },123 .y = -0.4,
124 .r = 1.0,
125 .g = 0.0,
126 .b = 0.0,
127 },
128 Vertex {
129 .x = 0.6,
130 .y = -0.4,
131 .r = 0.0,
132 .g = 1.0,
133 .b = 0.0,
134 },
135 Vertex {
136 .x = 0.0,
137 .y = 0.6,
138 .r = 0.0,
139 .g = 0.0,
140 .b = 1.0,
141 },
125};142};
126143
127
128test "statically initialized struct" {144test "statically initialized struct" {
129 st_init_str_foo.x += 1;145 st_init_str_foo.x += 1;
130 assert(st_init_str_foo.x == 14);146 assert(st_init_str_foo.x == 14);
...@@ -133,15 +149,21 @@ const StInitStrFoo = struct {...@@ -133,15 +149,21 @@ const StInitStrFoo = struct {
133 x: i32,149 x: i32,
134 y: bool,150 y: bool,
135};151};
136var st_init_str_foo = StInitStrFoo { .x = 13, .y = true, };152var st_init_str_foo = StInitStrFoo {
137153 .x = 13,
154 .y = true,
155};
138156
139test "statically initalized array literal" {157test "statically initalized array literal" {
140 const y : [4]u8 = st_init_arr_lit_x;158 const y: [4]u8 = st_init_arr_lit_x;
141 assert(y[3] == 4);159 assert(y[3] == 4);
142}160}
143const st_init_arr_lit_x = []u8{1,2,3,4};161const st_init_arr_lit_x = []u8 {
144162 1,
163 2,
164 3,
165 4,
166};
145167
146test "const slice" {168test "const slice" {
147 comptime {169 comptime {
...@@ -198,14 +220,29 @@ const CmdFn = struct {...@@ -198,14 +220,29 @@ const CmdFn = struct {
198 func: fn(i32) i32,220 func: fn(i32) i32,
199};221};
200222
201const cmd_fns = []CmdFn{223const cmd_fns = []CmdFn {
202 CmdFn {.name = "one", .func = one},224 CmdFn {
203 CmdFn {.name = "two", .func = two},225 .name = "one",
204 CmdFn {.name = "three", .func = three},226 .func = one,
227 },
228 CmdFn {
229 .name = "two",
230 .func = two,
231 },
232 CmdFn {
233 .name = "three",
234 .func = three,
235 },
205};236};
206fn one(value: i32) i32 { return value + 1; }237fn one(value: i32) i32 {
207fn two(value: i32) i32 { return value + 2; }238 return value + 1;
208fn three(value: i32) i32 { return value + 3; }239}
240fn two(value: i32) i32 {
241 return value + 2;
242}
243fn three(value: i32) i32 {
244 return value + 3;
245}
209246
210fn performFn(comptime prefix_char: u8, start_value: i32) i32 {247fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
211 var result: i32 = start_value;248 var result: i32 = start_value;
...@@ -229,7 +266,7 @@ test "eval @setRuntimeSafety at compile-time" {...@@ -229,7 +266,7 @@ test "eval @setRuntimeSafety at compile-time" {
229 assert(result == 1234);266 assert(result == 1234);
230}267}
231268
232fn fnWithSetRuntimeSafety() i32{269fn fnWithSetRuntimeSafety() i32 {
233 @setRuntimeSafety(true);270 @setRuntimeSafety(true);
234 return 1234;271 return 1234;
235}272}
...@@ -244,7 +281,6 @@ fn fnWithFloatMode() f32 {...@@ -244,7 +281,6 @@ fn fnWithFloatMode() f32 {
244 return 1234.0;281 return 1234.0;
245}282}
246283
247
248const SimpleStruct = struct {284const SimpleStruct = struct {
249 field: i32,285 field: i32,
250286
...@@ -253,7 +289,9 @@ const SimpleStruct = struct {...@@ -253,7 +289,9 @@ const SimpleStruct = struct {
253 }289 }
254};290};
255291
256var simple_struct = SimpleStruct{ .field = 1234, };292var simple_struct = SimpleStruct {
293 .field = 1234,
294};
257295
258const bound_fn = simple_struct.method;296const bound_fn = simple_struct.method;
259297
...@@ -261,8 +299,6 @@ test "call method on bound fn referring to var instance" {...@@ -261,8 +299,6 @@ test "call method on bound fn referring to var instance" {
261 assert(bound_fn() == 1237);299 assert(bound_fn() == 1237);
262}300}
263301
264
265
266test "ptr to local array argument at comptime" {302test "ptr to local array argument at comptime" {
267 comptime {303 comptime {
268 var bytes: [10]u8 = undefined;304 var bytes: [10]u8 = undefined;
...@@ -277,7 +313,6 @@ fn modifySomeBytes(bytes: []u8) void {...@@ -277,7 +313,6 @@ fn modifySomeBytes(bytes: []u8) void {
277 bytes[9] = 'b';313 bytes[9] = 'b';
278}314}
279315
280
281test "comparisons 0 <= uint and 0 > uint should be comptime" {316test "comparisons 0 <= uint and 0 > uint should be comptime" {
282 testCompTimeUIntComparisons(1234);317 testCompTimeUIntComparisons(1234);
283}318}
...@@ -296,8 +331,6 @@ fn testCompTimeUIntComparisons(x: u32) void {...@@ -296,8 +331,6 @@ fn testCompTimeUIntComparisons(x: u32) void {
296 }331 }
297}332}
298333
299
300
301test "const ptr to variable data changes at runtime" {334test "const ptr to variable data changes at runtime" {
302 assert(foo_ref.name[0] == 'a');335 assert(foo_ref.name[0] == 'a');
303 foo_ref.name = "b";336 foo_ref.name = "b";
...@@ -308,11 +341,11 @@ const Foo = struct {...@@ -308,11 +341,11 @@ const Foo = struct {
308 name: []const u8,341 name: []const u8,
309};342};
310343
311var foo_contents = Foo { .name = "a", };344var foo_contents = Foo {
345 .name = "a",
346};
312const foo_ref = &foo_contents;347const foo_ref = &foo_contents;
313348
314
315
316test "create global array with for loop" {349test "create global array with for loop" {
317 assert(global_array[5] == 5 * 5);350 assert(global_array[5] == 5 * 5);
318 assert(global_array[9] == 9 * 9);351 assert(global_array[9] == 9 * 9);
...@@ -321,7 +354,7 @@ test "create global array with for loop" {...@@ -321,7 +354,7 @@ test "create global array with for loop" {
321const global_array = x: {354const global_array = x: {
322 var result: [10]usize = undefined;355 var result: [10]usize = undefined;
323 for (result) |*item, index| {356 for (result) |*item, index| {
324 *item = index * index;357 item.* = index * index;
325 }358 }
326 break :x result;359 break :x result;
327};360};
...@@ -379,7 +412,7 @@ test "f128 at compile time is lossy" {...@@ -379,7 +412,7 @@ test "f128 at compile time is lossy" {
379412
380pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {413pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
381 return struct {414 return struct {
382 pub const Node = struct { };415 pub const Node = struct {};
383 };416 };
384}417}
385418
...@@ -401,10 +434,10 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {...@@ -401,10 +434,10 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {
401 comptime var i: usize = 0;434 comptime var i: usize = 0;
402 inline while (i < 4) : (i += 1) {435 inline while (i < 4) : (i += 1) {
403 s[i] = 0;436 s[i] = 0;
404 s[i] |= u32(b[i*4+0]) << 24;437 s[i] |= u32(b[i * 4 + 0]) << 24;
405 s[i] |= u32(b[i*4+1]) << 16;438 s[i] |= u32(b[i * 4 + 1]) << 16;
406 s[i] |= u32(b[i*4+2]) << 8;439 s[i] |= u32(b[i * 4 + 2]) << 8;
407 s[i] |= u32(b[i*4+3]) << 0;440 s[i] |= u32(b[i * 4 + 3]) << 0;
408 }441 }
409}442}
410443
...@@ -413,7 +446,7 @@ test "binary math operator in partially inlined function" {...@@ -413,7 +446,7 @@ test "binary math operator in partially inlined function" {
413 var b: [16]u8 = undefined;446 var b: [16]u8 = undefined;
414447
415 for (b) |*r, i|448 for (b) |*r, i|
416 *r = u8(i + 1);449 r.* = u8(i + 1);
417450
418 copyWithPartialInline(s[0..], b[0..]);451 copyWithPartialInline(s[0..], b[0..]);
419 assert(s[0] == 0x1020304);452 assert(s[0] == 0x1020304);
...@@ -422,7 +455,6 @@ test "binary math operator in partially inlined function" {...@@ -422,7 +455,6 @@ test "binary math operator in partially inlined function" {
422 assert(s[3] == 0xd0e0f10);455 assert(s[3] == 0xd0e0f10);
423}456}
424457
425
426test "comptime function with the same args is memoized" {458test "comptime function with the same args is memoized" {
427 comptime {459 comptime {
428 assert(MakeType(i32) == MakeType(i32));460 assert(MakeType(i32) == MakeType(i32));
...@@ -447,12 +479,12 @@ test "comptime function with mutable pointer is not memoized" {...@@ -447,12 +479,12 @@ test "comptime function with mutable pointer is not memoized" {
447}479}
448480
449fn increment(value: &i32) void {481fn increment(value: &i32) void {
450 *value += 1;482 value.* += 1;
451}483}
452484
453fn generateTable(comptime T: type) [1010]T {485fn generateTable(comptime T: type) [1010]T {
454 var res : [1010]T = undefined;486 var res: [1010]T = undefined;
455 var i : usize = 0;487 var i: usize = 0;
456 while (i < 1010) : (i += 1) {488 while (i < 1010) : (i += 1) {
457 res[i] = T(i);489 res[i] = T(i);
458 }490 }
...@@ -496,9 +528,10 @@ const SingleFieldStruct = struct {...@@ -496,9 +528,10 @@ const SingleFieldStruct = struct {
496 }528 }
497};529};
498test "const ptr to comptime mutable data is not memoized" {530test "const ptr to comptime mutable data is not memoized" {
499
500 comptime {531 comptime {
501 var foo = SingleFieldStruct {.x = 1};532 var foo = SingleFieldStruct {
533 .x = 1,
534 };
502 assert(foo.read_x() == 1);535 assert(foo.read_x() == 1);
503 foo.x = 2;536 foo.x = 2;
504 assert(foo.read_x() == 2);537 assert(foo.read_x() == 2);
...@@ -536,3 +569,20 @@ test "runtime 128 bit integer division" {...@@ -536,3 +569,20 @@ test "runtime 128 bit integer division" {
536 var c = a / b;569 var c = a / b;
537 assert(c == 15231399999);570 assert(c == 15231399999);
538}571}
572
573pub const Info = struct {
574 version: u8,
575};
576
577pub const diamond_info = Info {
578 .version = 0,
579};
580
581test "comptime modification of const struct field" {
582 comptime {
583 var res = diamond_info;
584 res.version = 1;
585 assert(diamond_info.version == 0);
586 assert(res.version == 1);
587 }
588}
test/cases/fn.zig+26-18
...@@ -7,7 +7,6 @@ fn testParamsAdd(a: i32, b: i32) i32 {...@@ -7,7 +7,6 @@ fn testParamsAdd(a: i32, b: i32) i32 {
7 return a + b;7 return a + b;
8}8}
99
10
11test "local variables" {10test "local variables" {
12 testLocVars(2);11 testLocVars(2);
13}12}
...@@ -16,7 +15,6 @@ fn testLocVars(b: i32) void {...@@ -16,7 +15,6 @@ fn testLocVars(b: i32) void {
16 if (a + b != 3) unreachable;15 if (a + b != 3) unreachable;
17}16}
1817
19
20test "void parameters" {18test "void parameters" {
21 voidFun(1, void{}, 2, {});19 voidFun(1, void{}, 2, {});
22}20}
...@@ -27,9 +25,8 @@ fn voidFun(a: i32, b: void, c: i32, d: void) void {...@@ -27,9 +25,8 @@ fn voidFun(a: i32, b: void, c: i32, d: void) void {
27 return vv;25 return vv;
28}26}
2927
30
31test "mutable local variables" {28test "mutable local variables" {
32 var zero : i32 = 0;29 var zero: i32 = 0;
33 assert(zero == 0);30 assert(zero == 0);
3431
35 var i = i32(0);32 var i = i32(0);
...@@ -41,7 +38,7 @@ test "mutable local variables" {...@@ -41,7 +38,7 @@ test "mutable local variables" {
4138
42test "separate block scopes" {39test "separate block scopes" {
43 {40 {
44 const no_conflict : i32 = 5;41 const no_conflict: i32 = 5;
45 assert(no_conflict == 5);42 assert(no_conflict == 5);
46 }43 }
4744
...@@ -56,8 +53,7 @@ test "call function with empty string" {...@@ -56,8 +53,7 @@ test "call function with empty string" {
56 acceptsString("");53 acceptsString("");
57}54}
5855
59fn acceptsString(foo: []u8) void { }56fn acceptsString(foo: []u8) void {}
60
6157
62fn @"weird function name"() i32 {58fn @"weird function name"() i32 {
63 return 1234;59 return 1234;
...@@ -70,31 +66,43 @@ test "implicit cast function unreachable return" {...@@ -70,31 +66,43 @@ test "implicit cast function unreachable return" {
70 wantsFnWithVoid(fnWithUnreachable);66 wantsFnWithVoid(fnWithUnreachable);
71}67}
7268
73fn wantsFnWithVoid(f: fn() void) void { }69fn wantsFnWithVoid(f: fn() void) void {}
7470
75fn fnWithUnreachable() noreturn {71fn fnWithUnreachable() noreturn {
76 unreachable;72 unreachable;
77}73}
7874
79
80test "function pointers" {75test "function pointers" {
81 const fns = []@typeOf(fn1) { fn1, fn2, fn3, fn4, };76 const fns = []@typeOf(fn1) {
77 fn1,
78 fn2,
79 fn3,
80 fn4,
81 };
82 for (fns) |f, i| {82 for (fns) |f, i| {
83 assert(f() == u32(i) + 5);83 assert(f() == u32(i) + 5);
84 }84 }
85}85}
86fn fn1() u32 {return 5;}86fn fn1() u32 {
87fn fn2() u32 {return 6;}87 return 5;
88fn fn3() u32 {return 7;}88}
89fn fn4() u32 {return 8;}89fn fn2() u32 {
9090 return 6;
91}
92fn fn3() u32 {
93 return 7;
94}
95fn fn4() u32 {
96 return 8;
97}
9198
92test "inline function call" {99test "inline function call" {
93 assert(@inlineCall(add, 3, 9) == 12);100 assert(@inlineCall(add, 3, 9) == 12);
94}101}
95102
96fn add(a: i32, b: i32) i32 { return a + b; }103fn add(a: i32, b: i32) i32 {
97104 return a + b;
105}
98106
99test "number literal as an argument" {107test "number literal as an argument" {
100 numberLiteralArg(3);108 numberLiteralArg(3);
...@@ -110,4 +118,4 @@ test "assign inline fn to const variable" {...@@ -110,4 +118,4 @@ test "assign inline fn to const variable" {
110 a();118 a();
111}119}
112120
113inline fn inlineFn() void { }121inline fn inlineFn() void {}
test/cases/for.zig+37-7
...@@ -3,8 +3,14 @@ const assert = std.debug.assert;...@@ -3,8 +3,14 @@ const assert = std.debug.assert;
3const mem = std.mem;3const mem = std.mem;
44
5test "continue in for loop" {5test "continue in for loop" {
6 const array = []i32 {1, 2, 3, 4, 5};6 const array = []i32 {
7 var sum : i32 = 0;7 1,
8 2,
9 3,
10 4,
11 5,
12 };
13 var sum: i32 = 0;
8 for (array) |x| {14 for (array) |x| {
9 sum += x;15 sum += x;
10 if (x < 3) {16 if (x < 3) {
...@@ -24,17 +30,39 @@ test "for loop with pointer elem var" {...@@ -24,17 +30,39 @@ test "for loop with pointer elem var" {
24}30}
25fn mangleString(s: []u8) void {31fn mangleString(s: []u8) void {
26 for (s) |*c| {32 for (s) |*c| {
27 *c += 1;33 c.* += 1;
28 }34 }
29}35}
3036
31test "basic for loop" {37test "basic for loop" {
32 const expected_result = []u8{9, 8, 7, 6, 0, 1, 2, 3, 9, 8, 7, 6, 0, 1, 2, 3 };38 const expected_result = []u8 {
39 9,
40 8,
41 7,
42 6,
43 0,
44 1,
45 2,
46 3,
47 9,
48 8,
49 7,
50 6,
51 0,
52 1,
53 2,
54 3,
55 };
3356
34 var buffer: [expected_result.len]u8 = undefined;57 var buffer: [expected_result.len]u8 = undefined;
35 var buf_index: usize = 0;58 var buf_index: usize = 0;
3659
37 const array = []u8 {9, 8, 7, 6};60 const array = []u8 {
61 9,
62 8,
63 7,
64 6,
65 };
38 for (array) |item| {66 for (array) |item| {
39 buffer[buf_index] = item;67 buffer[buf_index] = item;
40 buf_index += 1;68 buf_index += 1;
...@@ -65,7 +93,8 @@ fn testBreakOuter() void {...@@ -65,7 +93,8 @@ fn testBreakOuter() void {
65 var array = "aoeu";93 var array = "aoeu";
66 var count: usize = 0;94 var count: usize = 0;
67 outer: for (array) |_| {95 outer: for (array) |_| {
68 for (array) |_2| { // TODO shouldn't get error for redeclaring "_"96 // TODO shouldn't get error for redeclaring "_"
97 for (array) |_2| {
69 count += 1;98 count += 1;
70 break :outer;99 break :outer;
71 }100 }
...@@ -82,7 +111,8 @@ fn testContinueOuter() void {...@@ -82,7 +111,8 @@ fn testContinueOuter() void {
82 var array = "aoeu";111 var array = "aoeu";
83 var counter: usize = 0;112 var counter: usize = 0;
84 outer: for (array) |_| {113 outer: for (array) |_| {
85 for (array) |_2| { // TODO shouldn't get error for redeclaring "_"114 // TODO shouldn't get error for redeclaring "_"
115 for (array) |_2| {
86 counter += 1;116 counter += 1;
87 continue :outer;117 continue :outer;
88 }118 }
test/cases/generics.zig+28-14
...@@ -37,7 +37,6 @@ test "fn with comptime args" {...@@ -37,7 +37,6 @@ test "fn with comptime args" {
37 assert(sameButWithFloats(0.43, 0.49) == 0.49);37 assert(sameButWithFloats(0.43, 0.49) == 0.49);
38}38}
3939
40
41test "var params" {40test "var params" {
42 assert(max_i32(12, 34) == 34);41 assert(max_i32(12, 34) == 34);
43 assert(max_f64(1.2, 3.4) == 3.4);42 assert(max_f64(1.2, 3.4) == 3.4);
...@@ -60,7 +59,6 @@ fn max_f64(a: f64, b: f64) f64 {...@@ -60,7 +59,6 @@ fn max_f64(a: f64, b: f64) f64 {
60 return max_var(a, b);59 return max_var(a, b);
61}60}
6261
63
64pub fn List(comptime T: type) type {62pub fn List(comptime T: type) type {
65 return SmallList(T, 8);63 return SmallList(T, 8);
66}64}
...@@ -82,10 +80,15 @@ test "function with return type type" {...@@ -82,10 +80,15 @@ test "function with return type type" {
82 assert(list2.prealloc_items.len == 8);80 assert(list2.prealloc_items.len == 8);
83}81}
8482
85
86test "generic struct" {83test "generic struct" {
87 var a1 = GenNode(i32) {.value = 13, .next = null,};84 var a1 = GenNode(i32) {
88 var b1 = GenNode(bool) {.value = true, .next = null,};85 .value = 13,
86 .next = null,
87 };
88 var b1 = GenNode(bool) {
89 .value = true,
90 .next = null,
91 };
89 assert(a1.value == 13);92 assert(a1.value == 13);
90 assert(a1.value == a1.getVal());93 assert(a1.value == a1.getVal());
91 assert(b1.getVal());94 assert(b1.getVal());
...@@ -94,7 +97,9 @@ fn GenNode(comptime T: type) type {...@@ -94,7 +97,9 @@ fn GenNode(comptime T: type) type {
94 return struct {97 return struct {
95 value: T,98 value: T,
96 next: ?&GenNode(T),99 next: ?&GenNode(T),
97 fn getVal(n: &const GenNode(T)) T { return n.value; }100 fn getVal(n: &const GenNode(T)) T {
101 return n.value;
102 }
98 };103 };
99}104}
100105
...@@ -107,7 +112,6 @@ fn GenericDataThing(comptime count: isize) type {...@@ -107,7 +112,6 @@ fn GenericDataThing(comptime count: isize) type {
107 };112 };
108}113}
109114
110
111test "use generic param in generic param" {115test "use generic param in generic param" {
112 assert(aGenericFn(i32, 3, 4) == 7);116 assert(aGenericFn(i32, 3, 4) == 7);
113}117}
...@@ -115,21 +119,31 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T {...@@ -115,21 +119,31 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
115 return a + b;119 return a + b;
116}120}
117121
118
119test "generic fn with implicit cast" {122test "generic fn with implicit cast" {
120 assert(getFirstByte(u8, []u8 {13}) == 13);123 assert(getFirstByte(u8, []u8 {13}) == 13);
121 assert(getFirstByte(u16, []u16 {0, 13}) == 0);124 assert(getFirstByte(u16, []u16 {
125 0,
126 13,
127 }) == 0);
128}
129fn getByte(ptr: ?&const u8) u8 {
130 return (??ptr).*;
122}131}
123fn getByte(ptr: ?&const u8) u8 {return *??ptr;}
124fn getFirstByte(comptime T: type, mem: []const T) u8 {132fn getFirstByte(comptime T: type, mem: []const T) u8 {
125 return getByte(@ptrCast(&const u8, &mem[0]));133 return getByte(@ptrCast(&const u8, &mem[0]));
126}134}
127135
136const foos = []fn(var) bool {
137 foo1,
138 foo2,
139};
128140
129const foos = []fn(var) bool { foo1, foo2 };141fn foo1(arg: var) bool {
130142 return arg;
131fn foo1(arg: var) bool { return arg; }143}
132fn foo2(arg: var) bool { return !arg; }144fn foo2(arg: var) bool {
145 return !arg;
146}
133147
134test "array of generic fns" {148test "array of generic fns" {
135 assert(foos[0](true));149 assert(foos[0](true));
test/cases/if.zig-1
...@@ -23,7 +23,6 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void {...@@ -23,7 +23,6 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void {
23 }23 }
24}24}
2525
26
27test "else if expression" {26test "else if expression" {
28 assert(elseIfExpressionF(1) == 1);27 assert(elseIfExpressionF(1) == 1);
29}28}
test/cases/import/a_namespace.zig+3-1
...@@ -1 +1,3 @@...@@ -1 +1,3 @@
1pub fn foo() i32 { return 1234; }1pub fn foo() i32 {
2 return 1234;
3}
test/cases/ir_block_deps.zig+3-1
...@@ -11,7 +11,9 @@ fn foo(id: u64) !i32 {...@@ -11,7 +11,9 @@ fn foo(id: u64) !i32 {
11 };11 };
12}12}
1313
14fn getErrInt() error!i32 { return 0; }14fn getErrInt() error!i32 {
15 return 0;
16}
1517
16test "ir block deps" {18test "ir block deps" {
17 assert((foo(1) catch unreachable) == 0);19 assert((foo(1) catch unreachable) == 0);
test/cases/math.zig+40-52
...@@ -28,25 +28,12 @@ fn testDivision() void {...@@ -28,25 +28,12 @@ fn testDivision() void {
28 assert(divTrunc(f32, -5.0, 3.0) == -1.0);28 assert(divTrunc(f32, -5.0, 3.0) == -1.0);
2929
30 comptime {30 comptime {
31 assert(31 assert(1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600);
32 1194735857077236777412821811143690633098347576 %32 assert(@rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600);
33 508740759824825164163191790951174292733114988 ==33 assert(1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2);
34 177254337427586449086438229241342047632117600);34 assert(@divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2);
35 assert(@rem(-1194735857077236777412821811143690633098347576,35 assert(@divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2);
36 508740759824825164163191790951174292733114988) ==36 assert(@divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2);
37 -177254337427586449086438229241342047632117600);
38 assert(1194735857077236777412821811143690633098347576 /
39 508740759824825164163191790951174292733114988 ==
40 2);
41 assert(@divTrunc(-1194735857077236777412821811143690633098347576,
42 508740759824825164163191790951174292733114988) ==
43 -2);
44 assert(@divTrunc(1194735857077236777412821811143690633098347576,
45 -508740759824825164163191790951174292733114988) ==
46 -2);
47 assert(@divTrunc(-1194735857077236777412821811143690633098347576,
48 -508740759824825164163191790951174292733114988) ==
49 2);
50 assert(4126227191251978491697987544882340798050766755606969681711 % 10 == 1);37 assert(4126227191251978491697987544882340798050766755606969681711 % 10 == 1);
51 }38 }
52}39}
...@@ -114,18 +101,28 @@ fn ctz(x: var) usize {...@@ -114,18 +101,28 @@ fn ctz(x: var) usize {
114101
115test "assignment operators" {102test "assignment operators" {
116 var i: u32 = 0;103 var i: u32 = 0;
117 i += 5; assert(i == 5);104 i += 5;
118 i -= 2; assert(i == 3);105 assert(i == 5);
119 i *= 20; assert(i == 60);106 i -= 2;
120 i /= 3; assert(i == 20);107 assert(i == 3);
121 i %= 11; assert(i == 9);108 i *= 20;
122 i <<= 1; assert(i == 18);109 assert(i == 60);
123 i >>= 2; assert(i == 4);110 i /= 3;
111 assert(i == 20);
112 i %= 11;
113 assert(i == 9);
114 i <<= 1;
115 assert(i == 18);
116 i >>= 2;
117 assert(i == 4);
124 i = 6;118 i = 6;
125 i &= 5; assert(i == 4);119 i &= 5;
126 i ^= 6; assert(i == 2);120 assert(i == 4);
121 i ^= 6;
122 assert(i == 2);
127 i = 6;123 i = 6;
128 i |= 3; assert(i == 7);124 i |= 3;
125 assert(i == 7);
129}126}
130127
131test "three expr in a row" {128test "three expr in a row" {
...@@ -138,7 +135,7 @@ fn testThreeExprInARow(f: bool, t: bool) void {...@@ -138,7 +135,7 @@ fn testThreeExprInARow(f: bool, t: bool) void {
138 assertFalse(1 | 2 | 4 != 7);135 assertFalse(1 | 2 | 4 != 7);
139 assertFalse(3 ^ 6 ^ 8 != 13);136 assertFalse(3 ^ 6 ^ 8 != 13);
140 assertFalse(7 & 14 & 28 != 4);137 assertFalse(7 & 14 & 28 != 4);
141 assertFalse(9 << 1 << 2 != 9 << 3);138 assertFalse(9 << 1 << 2 != 9 << 3);
142 assertFalse(90 >> 1 >> 2 != 90 >> 3);139 assertFalse(90 >> 1 >> 2 != 90 >> 3);
143 assertFalse(100 - 1 + 1000 != 1099);140 assertFalse(100 - 1 + 1000 != 1099);
144 assertFalse(5 * 4 / 2 % 3 != 1);141 assertFalse(5 * 4 / 2 % 3 != 1);
...@@ -150,7 +147,6 @@ fn assertFalse(b: bool) void {...@@ -150,7 +147,6 @@ fn assertFalse(b: bool) void {
150 assert(!b);147 assert(!b);
151}148}
152149
153
154test "const number literal" {150test "const number literal" {
155 const one = 1;151 const one = 1;
156 const eleven = ten + one;152 const eleven = ten + one;
...@@ -159,8 +155,6 @@ test "const number literal" {...@@ -159,8 +155,6 @@ test "const number literal" {
159}155}
160const ten = 10;156const ten = 10;
161157
162
163
164test "unsigned wrapping" {158test "unsigned wrapping" {
165 testUnsignedWrappingEval(@maxValue(u32));159 testUnsignedWrappingEval(@maxValue(u32));
166 comptime testUnsignedWrappingEval(@maxValue(u32));160 comptime testUnsignedWrappingEval(@maxValue(u32));
...@@ -214,8 +208,12 @@ const DivResult = struct {...@@ -214,8 +208,12 @@ const DivResult = struct {
214};208};
215209
216test "binary not" {210test "binary not" {
217 assert(comptime x: {break :x ~u16(0b1010101010101010) == 0b0101010101010101;});211 assert(comptime x: {
218 assert(comptime x: {break :x ~u64(2147483647) == 18446744071562067968;});212 break :x ~u16(0b1010101010101010) == 0b0101010101010101;
213 });
214 assert(comptime x: {
215 break :x ~u64(2147483647) == 18446744071562067968;
216 });
219 testBinaryNot(0b1010101010101010);217 testBinaryNot(0b1010101010101010);
220}218}
221219
...@@ -319,27 +317,15 @@ fn testShrExact(x: u8) void {...@@ -319,27 +317,15 @@ fn testShrExact(x: u8) void {
319317
320test "big number addition" {318test "big number addition" {
321 comptime {319 comptime {
322 assert(320 assert(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
323 35361831660712422535336160538497375248 +321 assert(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
324 101752735581729509668353361206450473702 ==
325 137114567242441932203689521744947848950);
326 assert(
327 594491908217841670578297176641415611445982232488944558774612 +
328 390603545391089362063884922208143568023166603618446395589768 ==
329 985095453608931032642182098849559179469148836107390954364380);
330 }322 }
331}323}
332324
333test "big number multiplication" {325test "big number multiplication" {
334 comptime {326 comptime {
335 assert(327 assert(45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567);
336 45960427431263824329884196484953148229 *328 assert(594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016);
337 128339149605334697009938835852565949723 ==
338 5898522172026096622534201617172456926982464453350084962781392314016180490567);
339 assert(
340 594491908217841670578297176641415611445982232488944558774612 *
341 390603545391089362063884922208143568023166603618446395589768 ==
342 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016);
343 }329 }
344}330}
345331
...@@ -405,7 +391,9 @@ test "f128" {...@@ -405,7 +391,9 @@ test "f128" {
405 comptime test_f128();391 comptime test_f128();
406}392}
407393
408fn make_f128(x: f128) f128 { return x; }394fn make_f128(x: f128) f128 {
395 return x;
396}
409397
410fn test_f128() void {398fn test_f128() void {
411 assert(@sizeOf(f128) == 16);399 assert(@sizeOf(f128) == 16);
test/cases/misc.zig+139-88
...@@ -4,6 +4,7 @@ const cstr = @import("std").cstr;...@@ -4,6 +4,7 @@ const cstr = @import("std").cstr;
4const builtin = @import("builtin");4const builtin = @import("builtin");
55
6// normal comment6// normal comment
7
7/// this is a documentation comment8/// this is a documentation comment
8/// doc comment line 29/// doc comment line 2
9fn emptyFunctionWithComments() void {}10fn emptyFunctionWithComments() void {}
...@@ -16,8 +17,7 @@ comptime {...@@ -16,8 +17,7 @@ comptime {
16 @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);17 @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal);
17}18}
1819
19extern fn disabledExternFn() void {20extern fn disabledExternFn() void {}
20}
2121
22test "call disabled extern fn" {22test "call disabled extern fn" {
23 disabledExternFn();23 disabledExternFn();
...@@ -110,17 +110,29 @@ fn testShortCircuit(f: bool, t: bool) void {...@@ -110,17 +110,29 @@ fn testShortCircuit(f: bool, t: bool) void {
110 var hit_3 = f;110 var hit_3 = f;
111 var hit_4 = f;111 var hit_4 = f;
112112
113 if (t or x: {assert(f); break :x f;}) {113 if (t or x: {
114 assert(f);
115 break :x f;
116 }) {
114 hit_1 = t;117 hit_1 = t;
115 }118 }
116 if (f or x: { hit_2 = t; break :x f; }) {119 if (f or x: {
120 hit_2 = t;
121 break :x f;
122 }) {
117 assert(f);123 assert(f);
118 }124 }
119125
120 if (t and x: { hit_3 = t; break :x f; }) {126 if (t and x: {
127 hit_3 = t;
128 break :x f;
129 }) {
121 assert(f);130 assert(f);
122 }131 }
123 if (f and x: {assert(f); break :x f;}) {132 if (f and x: {
133 assert(f);
134 break :x f;
135 }) {
124 assert(f);136 assert(f);
125 } else {137 } else {
126 hit_4 = t;138 hit_4 = t;
...@@ -146,8 +158,8 @@ test "return string from function" {...@@ -146,8 +158,8 @@ test "return string from function" {
146 assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));158 assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
147}159}
148160
149const g1 : i32 = 1233 + 1;161const g1: i32 = 1233 + 1;
150var g2 : i32 = 0;162var g2: i32 = 0;
151163
152test "global variables" {164test "global variables" {
153 assert(g2 == 0);165 assert(g2 == 0);
...@@ -155,10 +167,9 @@ test "global variables" {...@@ -155,10 +167,9 @@ test "global variables" {
155 assert(g2 == 1234);167 assert(g2 == 1234);
156}168}
157169
158
159test "memcpy and memset intrinsics" {170test "memcpy and memset intrinsics" {
160 var foo : [20]u8 = undefined;171 var foo: [20]u8 = undefined;
161 var bar : [20]u8 = undefined;172 var bar: [20]u8 = undefined;
162173
163 @memset(&foo[0], 'A', foo.len);174 @memset(&foo[0], 'A', foo.len);
164 @memcpy(&bar[0], &foo[0], bar.len);175 @memcpy(&bar[0], &foo[0], bar.len);
...@@ -167,12 +178,14 @@ test "memcpy and memset intrinsics" {...@@ -167,12 +178,14 @@ test "memcpy and memset intrinsics" {
167}178}
168179
169test "builtin static eval" {180test "builtin static eval" {
170 const x : i32 = comptime x: {break :x 1 + 2 + 3;};181 const x: i32 = comptime x: {
182 break :x 1 + 2 + 3;
183 };
171 assert(x == comptime 6);184 assert(x == comptime 6);
172}185}
173186
174test "slicing" {187test "slicing" {
175 var array : [20]i32 = undefined;188 var array: [20]i32 = undefined;
176189
177 array[5] = 1234;190 array[5] = 1234;
178191
...@@ -187,15 +200,15 @@ test "slicing" {...@@ -187,15 +200,15 @@ test "slicing" {
187 if (slice_rest.len != 10) unreachable;200 if (slice_rest.len != 10) unreachable;
188}201}
189202
190
191test "constant equal function pointers" {203test "constant equal function pointers" {
192 const alias = emptyFn;204 const alias = emptyFn;
193 assert(comptime x: {break :x emptyFn == alias;});205 assert(comptime x: {
206 break :x emptyFn == alias;
207 });
194}208}
195209
196fn emptyFn() void {}210fn emptyFn() void {}
197211
198
199test "hex escape" {212test "hex escape" {
200 assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));213 assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
201}214}
...@@ -219,7 +232,7 @@ test "string escapes" {...@@ -219,7 +232,7 @@ test "string escapes" {
219}232}
220233
221test "multiline string" {234test "multiline string" {
222 const s1 =235 const s1 =
223 \\one236 \\one
224 \\two)237 \\two)
225 \\three238 \\three
...@@ -229,7 +242,7 @@ test "multiline string" {...@@ -229,7 +242,7 @@ test "multiline string" {
229}242}
230243
231test "multiline C string" {244test "multiline C string" {
232 const s1 =245 const s1 =
233 c\\one246 c\\one
234 c\\two)247 c\\two)
235 c\\three248 c\\three
...@@ -238,18 +251,16 @@ test "multiline C string" {...@@ -238,18 +251,16 @@ test "multiline C string" {
238 assert(cstr.cmp(s1, s2) == 0);251 assert(cstr.cmp(s1, s2) == 0);
239}252}
240253
241
242test "type equality" {254test "type equality" {
243 assert(&const u8 != &u8);255 assert(&const u8 != &u8);
244}256}
245257
246
247const global_a: i32 = 1234;258const global_a: i32 = 1234;
248const global_b: &const i32 = &global_a;259const global_b: &const i32 = &global_a;
249const global_c: &const f32 = @ptrCast(&const f32, global_b);260const global_c: &const f32 = @ptrCast(&const f32, global_b);
250test "compile time global reinterpret" {261test "compile time global reinterpret" {
251 const d = @ptrCast(&const i32, global_c);262 const d = @ptrCast(&const i32, global_c);
252 assert(*d == 1234);263 assert(d.* == 1234);
253}264}
254265
255test "explicit cast maybe pointers" {266test "explicit cast maybe pointers" {
...@@ -261,12 +272,11 @@ test "generic malloc free" {...@@ -261,12 +272,11 @@ test "generic malloc free" {
261 const a = memAlloc(u8, 10) catch unreachable;272 const a = memAlloc(u8, 10) catch unreachable;
262 memFree(u8, a);273 memFree(u8, a);
263}274}
264var some_mem : [100]u8 = undefined;275var some_mem: [100]u8 = undefined;
265fn memAlloc(comptime T: type, n: usize) error![]T {276fn memAlloc(comptime T: type, n: usize) error![]T {
266 return @ptrCast(&T, &some_mem[0])[0..n];277 return @ptrCast(&T, &some_mem[0])[0..n];
267}278}
268fn memFree(comptime T: type, memory: []T) void { }279fn memFree(comptime T: type, memory: []T) void {}
269
270280
271test "cast undefined" {281test "cast undefined" {
272 const array: [100]u8 = undefined;282 const array: [100]u8 = undefined;
...@@ -275,32 +285,35 @@ test "cast undefined" {...@@ -275,32 +285,35 @@ test "cast undefined" {
275}285}
276fn testCastUndefined(x: []const u8) void {}286fn testCastUndefined(x: []const u8) void {}
277287
278
279test "cast small unsigned to larger signed" {288test "cast small unsigned to larger signed" {
280 assert(castSmallUnsignedToLargerSigned1(200) == i16(200));289 assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
281 assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));290 assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
282}291}
283fn castSmallUnsignedToLargerSigned1(x: u8) i16 { return x; }292fn castSmallUnsignedToLargerSigned1(x: u8) i16 {
284fn castSmallUnsignedToLargerSigned2(x: u16) i64 { return x; }293 return x;
285294}
295fn castSmallUnsignedToLargerSigned2(x: u16) i64 {
296 return x;
297}
286298
287test "implicit cast after unreachable" {299test "implicit cast after unreachable" {
288 assert(outer() == 1234);300 assert(outer() == 1234);
289}301}
290fn inner() i32 { return 1234; }302fn inner() i32 {
303 return 1234;
304}
291fn outer() i64 {305fn outer() i64 {
292 return inner();306 return inner();
293}307}
294308
295
296test "pointer dereferencing" {309test "pointer dereferencing" {
297 var x = i32(3);310 var x = i32(3);
298 const y = &x;311 const y = &x;
299312
300 *y += 1;313 y.* += 1;
301314
302 assert(x == 4);315 assert(x == 4);
303 assert(*y == 4);316 assert(y.* == 4);
304}317}
305318
306test "call result of if else expression" {319test "call result of if else expression" {
...@@ -310,9 +323,12 @@ test "call result of if else expression" {...@@ -310,9 +323,12 @@ test "call result of if else expression" {
310fn f2(x: bool) []const u8 {323fn f2(x: bool) []const u8 {
311 return (if (x) fA else fB)();324 return (if (x) fA else fB)();
312}325}
313fn fA() []const u8 { return "a"; }326fn fA() []const u8 {
314fn fB() []const u8 { return "b"; }327 return "a";
315328}
329fn fB() []const u8 {
330 return "b";
331}
316332
317test "const expression eval handling of variables" {333test "const expression eval handling of variables" {
318 var x = true;334 var x = true;
...@@ -321,8 +337,6 @@ test "const expression eval handling of variables" {...@@ -321,8 +337,6 @@ test "const expression eval handling of variables" {
321 }337 }
322}338}
323339
324
325
326test "constant enum initialization with differing sizes" {340test "constant enum initialization with differing sizes" {
327 test3_1(test3_foo);341 test3_1(test3_foo);
328 test3_2(test3_bar);342 test3_2(test3_bar);
...@@ -336,10 +350,17 @@ const Test3Point = struct {...@@ -336,10 +350,17 @@ const Test3Point = struct {
336 x: i32,350 x: i32,
337 y: i32,351 y: i32,
338};352};
339const test3_foo = Test3Foo { .Three = Test3Point {.x = 3, .y = 4}};353const test3_foo = Test3Foo {
340const test3_bar = Test3Foo { .Two = 13};354 .Three = Test3Point {
355 .x = 3,
356 .y = 4,
357 },
358};
359const test3_bar = Test3Foo {
360 .Two = 13,
361};
341fn test3_1(f: &const Test3Foo) void {362fn test3_1(f: &const Test3Foo) void {
342 switch (*f) {363 switch (f.*) {
343 Test3Foo.Three => |pt| {364 Test3Foo.Three => |pt| {
344 assert(pt.x == 3);365 assert(pt.x == 3);
345 assert(pt.y == 4);366 assert(pt.y == 4);
...@@ -348,7 +369,7 @@ fn test3_1(f: &const Test3Foo) void {...@@ -348,7 +369,7 @@ fn test3_1(f: &const Test3Foo) void {
348 }369 }
349}370}
350fn test3_2(f: &const Test3Foo) void {371fn test3_2(f: &const Test3Foo) void {
351 switch (*f) {372 switch (f.*) {
352 Test3Foo.Two => |x| {373 Test3Foo.Two => |x| {
353 assert(x == 13);374 assert(x == 13);
354 },375 },
...@@ -356,23 +377,19 @@ fn test3_2(f: &const Test3Foo) void {...@@ -356,23 +377,19 @@ fn test3_2(f: &const Test3Foo) void {
356 }377 }
357}378}
358379
359
360test "character literals" {380test "character literals" {
361 assert('\'' == single_quote);381 assert('\'' == single_quote);
362}382}
363const single_quote = '\'';383const single_quote = '\'';
364384
365
366
367test "take address of parameter" {385test "take address of parameter" {
368 testTakeAddressOfParameter(12.34);386 testTakeAddressOfParameter(12.34);
369}387}
370fn testTakeAddressOfParameter(f: f32) void {388fn testTakeAddressOfParameter(f: f32) void {
371 const f_ptr = &f;389 const f_ptr = &f;
372 assert(*f_ptr == 12.34);390 assert(f_ptr.* == 12.34);
373}391}
374392
375
376test "pointer comparison" {393test "pointer comparison" {
377 const a = ([]const u8)("a");394 const a = ([]const u8)("a");
378 const b = &a;395 const b = &a;
...@@ -382,23 +399,30 @@ fn ptrEql(a: &const []const u8, b: &const []const u8) bool {...@@ -382,23 +399,30 @@ fn ptrEql(a: &const []const u8, b: &const []const u8) bool {
382 return a == b;399 return a == b;
383}400}
384401
385
386test "C string concatenation" {402test "C string concatenation" {
387 const a = c"OK" ++ c" IT " ++ c"WORKED";403 const a = c"OK" ++ c" IT " ++ c"WORKED";
388 const b = c"OK IT WORKED";404 const b = c"OK IT WORKED";
389405
390 const len = cstr.len(b);406 const len = cstr.len(b);
391 const len_with_null = len + 1;407 const len_with_null = len + 1;
392 {var i: u32 = 0; while (i < len_with_null) : (i += 1) {408 {
393 assert(a[i] == b[i]);409 var i: u32 = 0;
394 }}410 while (i < len_with_null) : (i += 1) {
411 assert(a[i] == b[i]);
412 }
413 }
395 assert(a[len] == 0);414 assert(a[len] == 0);
396 assert(b[len] == 0);415 assert(b[len] == 0);
397}416}
398417
399test "cast slice to u8 slice" {418test "cast slice to u8 slice" {
400 assert(@sizeOf(i32) == 4);419 assert(@sizeOf(i32) == 4);
401 var big_thing_array = []i32{1, 2, 3, 4};420 var big_thing_array = []i32 {
421 1,
422 2,
423 3,
424 4,
425 };
402 const big_thing_slice: []i32 = big_thing_array[0..];426 const big_thing_slice: []i32 = big_thing_array[0..];
403 const bytes = ([]u8)(big_thing_slice);427 const bytes = ([]u8)(big_thing_slice);
404 assert(bytes.len == 4 * 4);428 assert(bytes.len == 4 * 4);
...@@ -421,25 +445,22 @@ test "pointer to void return type" {...@@ -421,25 +445,22 @@ test "pointer to void return type" {
421}445}
422fn testPointerToVoidReturnType() error!void {446fn testPointerToVoidReturnType() error!void {
423 const a = testPointerToVoidReturnType2();447 const a = testPointerToVoidReturnType2();
424 return *a;448 return a.*;
425}449}
426const test_pointer_to_void_return_type_x = void{};450const test_pointer_to_void_return_type_x = void{};
427fn testPointerToVoidReturnType2() &const void {451fn testPointerToVoidReturnType2() &const void {
428 return &test_pointer_to_void_return_type_x;452 return &test_pointer_to_void_return_type_x;
429}453}
430454
431
432test "non const ptr to aliased type" {455test "non const ptr to aliased type" {
433 const int = i32;456 const int = i32;
434 assert(?&int == ?&i32);457 assert(?&int == ?&i32);
435}458}
436459
437
438
439test "array 2D const double ptr" {460test "array 2D const double ptr" {
440 const rect_2d_vertexes = [][1]f32 {461 const rect_2d_vertexes = [][1]f32 {
441 []f32{1.0},462 []f32 {1.0},
442 []f32{2.0},463 []f32 {2.0},
443 };464 };
444 testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);465 testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
445}466}
...@@ -450,10 +471,21 @@ fn testArray2DConstDoublePtr(ptr: &const f32) void {...@@ -450,10 +471,21 @@ fn testArray2DConstDoublePtr(ptr: &const f32) void {
450}471}
451472
452const Tid = builtin.TypeId;473const Tid = builtin.TypeId;
453const AStruct = struct { x: i32, };474const AStruct = struct {
454const AnEnum = enum { One, Two, };475 x: i32,
455const AUnionEnum = union(enum) { One: i32, Two: void, };476};
456const AUnion = union { One: void, Two: void };477const AnEnum = enum {
478 One,
479 Two,
480};
481const AUnionEnum = union(enum) {
482 One: i32,
483 Two: void,
484};
485const AUnion = union {
486 One: void,
487 Two: void,
488};
457489
458test "@typeId" {490test "@typeId" {
459 comptime {491 comptime {
...@@ -481,9 +513,11 @@ test "@typeId" {...@@ -481,9 +513,11 @@ test "@typeId" {
481 assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);513 assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
482 assert(@typeId(AUnionEnum) == Tid.Union);514 assert(@typeId(AUnionEnum) == Tid.Union);
483 assert(@typeId(AUnion) == Tid.Union);515 assert(@typeId(AUnion) == Tid.Union);
484 assert(@typeId(fn()void) == Tid.Fn);516 assert(@typeId(fn() void) == Tid.Fn);
485 assert(@typeId(@typeOf(builtin)) == Tid.Namespace);517 assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
486 assert(@typeId(@typeOf(x: {break :x this;})) == Tid.Block);518 assert(@typeId(@typeOf(x: {
519 break :x this;
520 })) == Tid.Block);
487 // TODO bound fn521 // TODO bound fn
488 // TODO arg tuple522 // TODO arg tuple
489 // TODO opaque523 // TODO opaque
...@@ -499,8 +533,7 @@ test "@canImplicitCast" {...@@ -499,8 +533,7 @@ test "@canImplicitCast" {
499}533}
500534
501test "@typeName" {535test "@typeName" {
502 const Struct = struct {536 const Struct = struct {};
503 };
504 const Union = union {537 const Union = union {
505 unused: u8,538 unused: u8,
506 };539 };
...@@ -510,7 +543,7 @@ test "@typeName" {...@@ -510,7 +543,7 @@ test "@typeName" {
510 comptime {543 comptime {
511 assert(mem.eql(u8, @typeName(i64), "i64"));544 assert(mem.eql(u8, @typeName(i64), "i64"));
512 assert(mem.eql(u8, @typeName(&usize), "&usize"));545 assert(mem.eql(u8, @typeName(&usize), "&usize"));
513 // https://github.com/zig-lang/zig/issues/675546 // https://github.com/ziglang/zig/issues/675
514 assert(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));547 assert(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));
515 assert(mem.eql(u8, @typeName(Struct), "Struct"));548 assert(mem.eql(u8, @typeName(Struct), "Struct"));
516 assert(mem.eql(u8, @typeName(Union), "Union"));549 assert(mem.eql(u8, @typeName(Union), "Union"));
...@@ -525,14 +558,19 @@ fn TypeFromFn(comptime T: type) type {...@@ -525,14 +558,19 @@ fn TypeFromFn(comptime T: type) type {
525test "volatile load and store" {558test "volatile load and store" {
526 var number: i32 = 1234;559 var number: i32 = 1234;
527 const ptr = (&volatile i32)(&number);560 const ptr = (&volatile i32)(&number);
528 *ptr += 1;561 ptr.* += 1;
529 assert(*ptr == 1235);562 assert(ptr.* == 1235);
530}563}
531564
532test "slice string literal has type []const u8" {565test "slice string literal has type []const u8" {
533 comptime {566 comptime {
534 assert(@typeOf("aoeu"[0..]) == []const u8);567 assert(@typeOf("aoeu"[0..]) == []const u8);
535 const array = []i32{1, 2, 3, 4};568 const array = []i32 {
569 1,
570 2,
571 3,
572 4,
573 };
536 assert(@typeOf(array[0..]) == []const i32);574 assert(@typeOf(array[0..]) == []const i32);
537 }575 }
538}576}
...@@ -544,12 +582,15 @@ const GDTEntry = struct {...@@ -544,12 +582,15 @@ const GDTEntry = struct {
544 field: i32,582 field: i32,
545};583};
546var gdt = []GDTEntry {584var gdt = []GDTEntry {
547 GDTEntry {.field = 1},585 GDTEntry {
548 GDTEntry {.field = 2},586 .field = 1,
587 },
588 GDTEntry {
589 .field = 2,
590 },
549};591};
550var global_ptr = &gdt[0];592var global_ptr = &gdt[0];
551593
552
553// can't really run this test but we can make sure it has no compile error594// can't really run this test but we can make sure it has no compile error
554// and generates code595// and generates code
555const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000];596const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000];
...@@ -584,7 +625,7 @@ test "comptime if inside runtime while which unconditionally breaks" {...@@ -584,7 +625,7 @@ test "comptime if inside runtime while which unconditionally breaks" {
584}625}
585fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {626fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {
586 while (cond) {627 while (cond) {
587 if (false) { }628 if (false) {}
588 break;629 break;
589 }630 }
590}631}
...@@ -607,7 +648,9 @@ fn testStructInFn() void {...@@ -607,7 +648,9 @@ fn testStructInFn() void {
607 kind: BlockKind,648 kind: BlockKind,
608 };649 };
609650
610 var block = Block { .kind = 1234 };651 var block = Block {
652 .kind = 1234,
653 };
611654
612 block.kind += 1;655 block.kind += 1;
613656
...@@ -617,7 +660,9 @@ fn testStructInFn() void {...@@ -617,7 +660,9 @@ fn testStructInFn() void {
617fn fnThatClosesOverLocalConst() type {660fn fnThatClosesOverLocalConst() type {
618 const c = 1;661 const c = 1;
619 return struct {662 return struct {
620 fn g() i32 { return c; }663 fn g() i32 {
664 return c;
665 }
621 };666 };
622}667}
623668
...@@ -635,22 +680,29 @@ fn thisIsAColdFn() void {...@@ -635,22 +680,29 @@ fn thisIsAColdFn() void {
635 @setCold(true);680 @setCold(true);
636}681}
637682
638683const PackedStruct = packed struct {
639const PackedStruct = packed struct { a: u8, b: u8, };684 a: u8,
640const PackedUnion = packed union { a: u8, b: u32, };685 b: u8,
641const PackedEnum = packed enum { A, B, };686};
687const PackedUnion = packed union {
688 a: u8,
689 b: u32,
690};
691const PackedEnum = packed enum {
692 A,
693 B,
694};
642695
643test "packed struct, enum, union parameters in extern function" {696test "packed struct, enum, union parameters in extern function" {
644 testPackedStuff(697 testPackedStuff(PackedStruct {
645 PackedStruct{.a = 1, .b = 2},698 .a = 1,
646 PackedUnion{.a = 1},699 .b = 2,
647 PackedEnum.A,700 }, PackedUnion {
648 );701 .a = 1,
649}702 }, PackedEnum.A);
650
651export fn testPackedStuff(a: &const PackedStruct, b: &const PackedUnion, c: PackedEnum) void {
652}703}
653704
705export fn testPackedStuff(a: &const PackedStruct, b: &const PackedUnion, c: PackedEnum) void {}
654706
655test "slicing zero length array" {707test "slicing zero length array" {
656 const s1 = ""[0..];708 const s1 = ""[0..];
...@@ -661,7 +713,6 @@ test "slicing zero length array" {...@@ -661,7 +713,6 @@ test "slicing zero length array" {
661 assert(mem.eql(u32, s2, []u32{}));713 assert(mem.eql(u32, s2, []u32{}));
662}714}
663715
664
665const addr1 = @ptrCast(&const u8, emptyFn);716const addr1 = @ptrCast(&const u8, emptyFn);
666test "comptime cast fn to ptr" {717test "comptime cast fn to ptr" {
667 const addr2 = @ptrCast(&const u8, emptyFn);718 const addr2 = @ptrCast(&const u8, emptyFn);
test/cases/namespace_depends_on_compile_var/index.zig+1-1
...@@ -8,7 +8,7 @@ test "namespace depends on compile var" {...@@ -8,7 +8,7 @@ test "namespace depends on compile var" {
8 assert(!some_namespace.a_bool);8 assert(!some_namespace.a_bool);
9 }9 }
10}10}
11const some_namespace = switch(builtin.os) {11const some_namespace = switch (builtin.os) {
12 builtin.Os.linux => @import("a.zig"),12 builtin.Os.linux => @import("a.zig"),
13 else => @import("b.zig"),13 else => @import("b.zig"),
14};14};
test/cases/new_stack_call.zig created+26
...@@ -0,0 +1,26 @@
1const std = @import("std");
2const assert = std.debug.assert;
3
4var new_stack_bytes: [1024]u8 = undefined;
5
6test "calling a function with a new stack" {
7 const arg = 1234;
8
9 const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
10 const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
11 _ = targetFunction(arg);
12
13 assert(arg == 1234);
14 assert(a < b);
15}
16
17fn targetFunction(x: i32) usize {
18 assert(x == 1234);
19
20 var local_variable: i32 = 42;
21 const ptr = &local_variable;
22 ptr.* += 1;
23
24 assert(local_variable == 43);
25 return @ptrToInt(ptr);
26}
test/cases/null.zig+12-15
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
22
3test "nullable type" {3test "nullable type" {
4 const x : ?bool = true;4 const x: ?bool = true;
55
6 if (x) |y| {6 if (x) |y| {
7 if (y) {7 if (y) {
...@@ -13,13 +13,13 @@ test "nullable type" {...@@ -13,13 +13,13 @@ test "nullable type" {
13 unreachable;13 unreachable;
14 }14 }
1515
16 const next_x : ?i32 = null;16 const next_x: ?i32 = null;
1717
18 const z = next_x ?? 1234;18 const z = next_x ?? 1234;
1919
20 assert(z == 1234);20 assert(z == 1234);
2121
22 const final_x : ?i32 = 13;22 const final_x: ?i32 = 13;
2323
24 const num = final_x ?? unreachable;24 const num = final_x ?? unreachable;
2525
...@@ -30,19 +30,17 @@ test "test maybe object and get a pointer to the inner value" {...@@ -30,19 +30,17 @@ test "test maybe object and get a pointer to the inner value" {
30 var maybe_bool: ?bool = true;30 var maybe_bool: ?bool = true;
3131
32 if (maybe_bool) |*b| {32 if (maybe_bool) |*b| {
33 *b = false;33 b.* = false;
34 }34 }
3535
36 assert(??maybe_bool == false);36 assert(??maybe_bool == false);
37}37}
3838
39
40test "rhs maybe unwrap return" {39test "rhs maybe unwrap return" {
41 const x: ?bool = true;40 const x: ?bool = true;
42 const y = x ?? return;41 const y = x ?? return;
43}42}
4443
45
46test "maybe return" {44test "maybe return" {
47 maybeReturnImpl();45 maybeReturnImpl();
48 comptime maybeReturnImpl();46 comptime maybeReturnImpl();
...@@ -50,8 +48,7 @@ test "maybe return" {...@@ -50,8 +48,7 @@ test "maybe return" {
5048
51fn maybeReturnImpl() void {49fn maybeReturnImpl() void {
52 assert(??foo(1235));50 assert(??foo(1235));
53 if (foo(null) != null)51 if (foo(null) != null) unreachable;
54 unreachable;
55 assert(!??foo(1234));52 assert(!??foo(1234));
56}53}
5754
...@@ -60,12 +57,16 @@ fn foo(x: ?i32) ?bool {...@@ -60,12 +57,16 @@ fn foo(x: ?i32) ?bool {
60 return value > 1234;57 return value > 1234;
61}58}
6259
63
64test "if var maybe pointer" {60test "if var maybe pointer" {
65 assert(shouldBeAPlus1(Particle {.a = 14, .b = 1, .c = 1, .d = 1}) == 15);61 assert(shouldBeAPlus1(Particle {
62 .a = 14,
63 .b = 1,
64 .c = 1,
65 .d = 1,
66 }) == 15);
66}67}
67fn shouldBeAPlus1(p: &const Particle) u64 {68fn shouldBeAPlus1(p: &const Particle) u64 {
68 var maybe_particle: ?Particle = *p;69 var maybe_particle: ?Particle = p.*;
69 if (maybe_particle) |*particle| {70 if (maybe_particle) |*particle| {
70 particle.a += 1;71 particle.a += 1;
71 }72 }
...@@ -81,7 +82,6 @@ const Particle = struct {...@@ -81,7 +82,6 @@ const Particle = struct {
81 d: u64,82 d: u64,
82};83};
8384
84
85test "null literal outside function" {85test "null literal outside function" {
86 const is_null = here_is_a_null_literal.context == null;86 const is_null = here_is_a_null_literal.context == null;
87 assert(is_null);87 assert(is_null);
...@@ -96,7 +96,6 @@ const here_is_a_null_literal = SillyStruct {...@@ -96,7 +96,6 @@ const here_is_a_null_literal = SillyStruct {
96 .context = null,96 .context = null,
97};97};
9898
99
100test "test null runtime" {99test "test null runtime" {
101 testTestNullRuntime(null);100 testTestNullRuntime(null);
102}101}
...@@ -123,8 +122,6 @@ fn bar(x: ?void) ?void {...@@ -123,8 +122,6 @@ fn bar(x: ?void) ?void {
123 }122 }
124}123}
125124
126
127
128const StructWithNullable = struct {125const StructWithNullable = struct {
129 field: ?i32,126 field: ?i32,
130};127};
test/cases/pointers.zig created+14
...@@ -0,0 +1,14 @@
1const std = @import("std");
2const assert = std.debug.assert;
3
4test "dereference pointer" {
5 comptime testDerefPtr();
6 testDerefPtr();
7}
8
9fn testDerefPtr() void {
10 var x: i32 = 1234;
11 var y = &x;
12 y.* += 1;
13 assert(x == 1235);
14}
test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig+1-1
...@@ -23,7 +23,7 @@ fn foo(c: bool, k: Num, c2: bool, b: []const u8) void {...@@ -23,7 +23,7 @@ fn foo(c: bool, k: Num, c2: bool, b: []const u8) void {
23 if (c) {23 if (c) {
24 const output_path = b;24 const output_path = b;
2525
26 if (c2) { }26 if (c2) {}
2727
28 a(output_path);28 a(output_path);
29 }29 }
test/cases/reflection.zig+3-2
...@@ -23,7 +23,9 @@ test "reflection: function return type, var args, and param types" {...@@ -23,7 +23,9 @@ test "reflection: function return type, var args, and param types" {
23 }23 }
24}24}
2525
26fn dummy(a: bool, b: i32, c: f32) i32 { return 1234; }26fn dummy(a: bool, b: i32, c: f32) i32 {
27 return 1234;
28}
27fn dummy_varargs(args: ...) void {}29fn dummy_varargs(args: ...) void {}
2830
29test "reflection: struct member types and names" {31test "reflection: struct member types and names" {
...@@ -54,7 +56,6 @@ test "reflection: enum member types and names" {...@@ -54,7 +56,6 @@ test "reflection: enum member types and names" {
54 assert(mem.eql(u8, @memberName(Bar, 2), "Three"));56 assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
55 assert(mem.eql(u8, @memberName(Bar, 3), "Four"));57 assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
56 }58 }
57
58}59}
5960
60test "reflection: @field" {61test "reflection: @field" {
test/cases/slice.zig+6-2
...@@ -18,7 +18,11 @@ test "slice child property" {...@@ -18,7 +18,11 @@ test "slice child property" {
18}18}
1919
20test "runtime safety lets us slice from len..len" {20test "runtime safety lets us slice from len..len" {
21 var an_array = []u8{1, 2, 3};21 var an_array = []u8 {
22 1,
23 2,
24 3,
25 };
22 assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));26 assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
23}27}
2428
...@@ -27,7 +31,7 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {...@@ -27,7 +31,7 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
27}31}
2832
29test "implicitly cast array of size 0 to slice" {33test "implicitly cast array of size 0 to slice" {
30 var msg = []u8 {};34 var msg = []u8{};
31 assertLenIsZero(msg);35 assertLenIsZero(msg);
32}36}
3337
test/cases/struct.zig+48-35
...@@ -2,9 +2,11 @@ const assert = @import("std").debug.assert;...@@ -2,9 +2,11 @@ const assert = @import("std").debug.assert;
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4const StructWithNoFields = struct {4const StructWithNoFields = struct {
5 fn add(a: i32, b: i32) i32 { return a + b; }5 fn add(a: i32, b: i32) i32 {
6 return a + b;
7 }
6};8};
7const empty_global_instance = StructWithNoFields {};9const empty_global_instance = StructWithNoFields{};
810
9test "call struct static method" {11test "call struct static method" {
10 const result = StructWithNoFields.add(3, 4);12 const result = StructWithNoFields.add(3, 4);
...@@ -34,12 +36,11 @@ test "void struct fields" {...@@ -34,12 +36,11 @@ test "void struct fields" {
34 assert(@sizeOf(VoidStructFieldsFoo) == 4);36 assert(@sizeOf(VoidStructFieldsFoo) == 4);
35}37}
36const VoidStructFieldsFoo = struct {38const VoidStructFieldsFoo = struct {
37 a : void,39 a: void,
38 b : i32,40 b: i32,
39 c : void,41 c: void,
40};42};
4143
42
43test "structs" {44test "structs" {
44 var foo: StructFoo = undefined;45 var foo: StructFoo = undefined;
45 @memset(@ptrCast(&u8, &foo), 0, @sizeOf(StructFoo));46 @memset(@ptrCast(&u8, &foo), 0, @sizeOf(StructFoo));
...@@ -50,9 +51,9 @@ test "structs" {...@@ -50,9 +51,9 @@ test "structs" {
50 assert(foo.c == 100);51 assert(foo.c == 100);
51}52}
52const StructFoo = struct {53const StructFoo = struct {
53 a : i32,54 a: i32,
54 b : bool,55 b: bool,
55 c : f32,56 c: f32,
56};57};
57fn testFoo(foo: &const StructFoo) void {58fn testFoo(foo: &const StructFoo) void {
58 assert(foo.b);59 assert(foo.b);
...@@ -61,7 +62,6 @@ fn testMutation(foo: &StructFoo) void {...@@ -61,7 +62,6 @@ fn testMutation(foo: &StructFoo) void {
61 foo.c = 100;62 foo.c = 100;
62}63}
6364
64
65const Node = struct {65const Node = struct {
66 val: Val,66 val: Val,
67 next: &Node,67 next: &Node,
...@@ -72,10 +72,10 @@ const Val = struct {...@@ -72,10 +72,10 @@ const Val = struct {
72};72};
7373
74test "struct point to self" {74test "struct point to self" {
75 var root : Node = undefined;75 var root: Node = undefined;
76 root.val.x = 1;76 root.val.x = 1;
7777
78 var node : Node = undefined;78 var node: Node = undefined;
79 node.next = &root;79 node.next = &root;
80 node.val.x = 2;80 node.val.x = 2;
8181
...@@ -85,8 +85,8 @@ test "struct point to self" {...@@ -85,8 +85,8 @@ test "struct point to self" {
85}85}
8686
87test "struct byval assign" {87test "struct byval assign" {
88 var foo1 : StructFoo = undefined;88 var foo1: StructFoo = undefined;
89 var foo2 : StructFoo = undefined;89 var foo2: StructFoo = undefined;
9090
91 foo1.a = 1234;91 foo1.a = 1234;
92 foo2.a = 0;92 foo2.a = 0;
...@@ -96,46 +96,57 @@ test "struct byval assign" {...@@ -96,46 +96,57 @@ test "struct byval assign" {
96}96}
9797
98fn structInitializer() void {98fn structInitializer() void {
99 const val = Val { .x = 42 };99 const val = Val {
100 .x = 42,
101 };
100 assert(val.x == 42);102 assert(val.x == 42);
101}103}
102104
103
104test "fn call of struct field" {105test "fn call of struct field" {
105 assert(callStructField(Foo {.ptr = aFunc,}) == 13);106 assert(callStructField(Foo {
107 .ptr = aFunc,
108 }) == 13);
106}109}
107110
108const Foo = struct {111const Foo = struct {
109 ptr: fn() i32,112 ptr: fn() i32,
110};113};
111114
112fn aFunc() i32 { return 13; }115fn aFunc() i32 {
116 return 13;
117}
113118
114fn callStructField(foo: &const Foo) i32 {119fn callStructField(foo: &const Foo) i32 {
115 return foo.ptr();120 return foo.ptr();
116}121}
117122
118
119test "store member function in variable" {123test "store member function in variable" {
120 const instance = MemberFnTestFoo { .x = 1234, };124 const instance = MemberFnTestFoo {
125 .x = 1234,
126 };
121 const memberFn = MemberFnTestFoo.member;127 const memberFn = MemberFnTestFoo.member;
122 const result = memberFn(instance);128 const result = memberFn(instance);
123 assert(result == 1234);129 assert(result == 1234);
124}130}
125const MemberFnTestFoo = struct {131const MemberFnTestFoo = struct {
126 x: i32,132 x: i32,
127 fn member(foo: &const MemberFnTestFoo) i32 { return foo.x; }133 fn member(foo: &const MemberFnTestFoo) i32 {
134 return foo.x;
135 }
128};136};
129137
130
131test "call member function directly" {138test "call member function directly" {
132 const instance = MemberFnTestFoo { .x = 1234, };139 const instance = MemberFnTestFoo {
140 .x = 1234,
141 };
133 const result = MemberFnTestFoo.member(instance);142 const result = MemberFnTestFoo.member(instance);
134 assert(result == 1234);143 assert(result == 1234);
135}144}
136145
137test "member functions" {146test "member functions" {
138 const r = MemberFnRand {.seed = 1234};147 const r = MemberFnRand {
148 .seed = 1234,
149 };
139 assert(r.getSeed() == 1234);150 assert(r.getSeed() == 1234);
140}151}
141const MemberFnRand = struct {152const MemberFnRand = struct {
...@@ -170,17 +181,16 @@ const EmptyStruct = struct {...@@ -170,17 +181,16 @@ const EmptyStruct = struct {
170 }181 }
171};182};
172183
173
174test "return empty struct from fn" {184test "return empty struct from fn" {
175 _ = testReturnEmptyStructFromFn();185 _ = testReturnEmptyStructFromFn();
176}186}
177const EmptyStruct2 = struct {};187const EmptyStruct2 = struct {};
178fn testReturnEmptyStructFromFn() EmptyStruct2 {188fn testReturnEmptyStructFromFn() EmptyStruct2 {
179 return EmptyStruct2 {};189 return EmptyStruct2{};
180}190}
181191
182test "pass slice of empty struct to fn" {192test "pass slice of empty struct to fn" {
183 assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1);193 assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2 {EmptyStruct2{}}) == 1);
184}194}
185fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {195fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
186 return slice.len;196 return slice.len;
...@@ -201,7 +211,6 @@ test "packed struct" {...@@ -201,7 +211,6 @@ test "packed struct" {
201 assert(four == 4);211 assert(four == 4);
202}212}
203213
204
205const BitField1 = packed struct {214const BitField1 = packed struct {
206 a: u3,215 a: u3,
207 b: u3,216 b: u3,
...@@ -301,7 +310,7 @@ test "packed array 24bits" {...@@ -301,7 +310,7 @@ test "packed array 24bits" {
301 assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);310 assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);
302 }311 }
303312
304 var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);313 var bytes = []u8 {0} ** (@sizeOf(FooArray24Bits) + 1);
305 bytes[bytes.len - 1] = 0xaa;314 bytes[bytes.len - 1] = 0xaa;
306 const ptr = &([]FooArray24Bits)(bytes[0..bytes.len - 1])[0];315 const ptr = &([]FooArray24Bits)(bytes[0..bytes.len - 1])[0];
307 assert(ptr.a == 0);316 assert(ptr.a == 0);
...@@ -351,7 +360,7 @@ test "aligned array of packed struct" {...@@ -351,7 +360,7 @@ test "aligned array of packed struct" {
351 assert(@sizeOf(FooArrayOfAligned) == 2 * 2);360 assert(@sizeOf(FooArrayOfAligned) == 2 * 2);
352 }361 }
353362
354 var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);363 var bytes = []u8 {0xbb} ** @sizeOf(FooArrayOfAligned);
355 const ptr = &([]FooArrayOfAligned)(bytes[0..bytes.len])[0];364 const ptr = &([]FooArrayOfAligned)(bytes[0..bytes.len])[0];
356365
357 assert(ptr.a[0].a == 0xbb);366 assert(ptr.a[0].a == 0xbb);
...@@ -360,11 +369,15 @@ test "aligned array of packed struct" {...@@ -360,11 +369,15 @@ test "aligned array of packed struct" {
360 assert(ptr.a[1].b == 0xbb);369 assert(ptr.a[1].b == 0xbb);
361}370}
362371
363
364
365test "runtime struct initialization of bitfield" {372test "runtime struct initialization of bitfield" {
366 const s1 = Nibbles { .x = x1, .y = x1 };373 const s1 = Nibbles {
367 const s2 = Nibbles { .x = u4(x2), .y = u4(x2) };374 .x = x1,
375 .y = x1,
376 };
377 const s2 = Nibbles {
378 .x = u4(x2),
379 .y = u4(x2),
380 };
368381
369 assert(s1.x == x1);382 assert(s1.x == x1);
370 assert(s1.y == x1);383 assert(s1.y == x1);
...@@ -394,7 +407,7 @@ test "native bit field understands endianness" {...@@ -394,7 +407,7 @@ test "native bit field understands endianness" {
394 var all: u64 = 0x7765443322221111;407 var all: u64 = 0x7765443322221111;
395 var bytes: [8]u8 = undefined;408 var bytes: [8]u8 = undefined;
396 @memcpy(&bytes[0], @ptrCast(&u8, &all), 8);409 @memcpy(&bytes[0], @ptrCast(&u8, &all), 8);
397 var bitfields = *@ptrCast(&Bitfields, &bytes[0]);410 var bitfields = @ptrCast(&Bitfields, &bytes[0]).*;
398411
399 assert(bitfields.f1 == 0x1111);412 assert(bitfields.f1 == 0x1111);
400 assert(bitfields.f2 == 0x2222);413 assert(bitfields.f2 == 0x2222);
test/cases/struct_contains_null_ptr_itself.zig-1
...@@ -19,4 +19,3 @@ pub const Node = struct {...@@ -19,4 +19,3 @@ pub const Node = struct {
19pub const NodeLineComment = struct {19pub const NodeLineComment = struct {
20 base: Node,20 base: Node,
21};21};
22
test/cases/struct_contains_slice_of_itself.zig+1-1
...@@ -6,7 +6,7 @@ const Node = struct {...@@ -6,7 +6,7 @@ const Node = struct {
6};6};
77
8test "struct contains slice of itself" {8test "struct contains slice of itself" {
9 var other_nodes = []Node{9 var other_nodes = []Node {
10 Node {10 Node {
11 .payload = 31,11 .payload = 31,
12 .children = []Node{},12 .children = []Node{},
test/cases/switch.zig+33-16
...@@ -6,7 +6,10 @@ test "switch with numbers" {...@@ -6,7 +6,10 @@ test "switch with numbers" {
66
7fn testSwitchWithNumbers(x: u32) void {7fn testSwitchWithNumbers(x: u32) void {
8 const result = switch (x) {8 const result = switch (x) {
9 1, 2, 3, 4 ... 8 => false,9 1,
10 2,
11 3,
12 4 ... 8 => false,
10 13 => true,13 13 => true,
11 else => false,14 else => false,
12 };15 };
...@@ -34,8 +37,10 @@ test "implicit comptime switch" {...@@ -34,8 +37,10 @@ test "implicit comptime switch" {
34 const result = switch (x) {37 const result = switch (x) {
35 3 => 10,38 3 => 10,
36 4 => 11,39 4 => 11,
37 5, 6 => 12,40 5,
38 7, 8 => 13,41 6 => 12,
42 7,
43 8 => 13,
39 else => 14,44 else => 14,
40 };45 };
4146
...@@ -61,7 +66,6 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void {...@@ -61,7 +66,6 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void {
61 }66 }
62}67}
6368
64
65test "switch statement" {69test "switch statement" {
66 nonConstSwitch(SwitchStatmentFoo.C);70 nonConstSwitch(SwitchStatmentFoo.C);
67}71}
...@@ -81,11 +85,16 @@ const SwitchStatmentFoo = enum {...@@ -81,11 +85,16 @@ const SwitchStatmentFoo = enum {
81 D,85 D,
82};86};
8387
84
85test "switch prong with variable" {88test "switch prong with variable" {
86 switchProngWithVarFn(SwitchProngWithVarEnum { .One = 13});89 switchProngWithVarFn(SwitchProngWithVarEnum {
87 switchProngWithVarFn(SwitchProngWithVarEnum { .Two = 13.0});90 .One = 13,
88 switchProngWithVarFn(SwitchProngWithVarEnum { .Meh = {}});91 });
92 switchProngWithVarFn(SwitchProngWithVarEnum {
93 .Two = 13.0,
94 });
95 switchProngWithVarFn(SwitchProngWithVarEnum {
96 .Meh = {},
97 });
89}98}
90const SwitchProngWithVarEnum = union(enum) {99const SwitchProngWithVarEnum = union(enum) {
91 One: i32,100 One: i32,
...@@ -93,7 +102,7 @@ const SwitchProngWithVarEnum = union(enum) {...@@ -93,7 +102,7 @@ const SwitchProngWithVarEnum = union(enum) {
93 Meh: void,102 Meh: void,
94};103};
95fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) void {104fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) void {
96 switch(*a) {105 switch (a.*) {
97 SwitchProngWithVarEnum.One => |x| {106 SwitchProngWithVarEnum.One => |x| {
98 assert(x == 13);107 assert(x == 13);
99 },108 },
...@@ -112,9 +121,11 @@ test "switch on enum using pointer capture" {...@@ -112,9 +121,11 @@ test "switch on enum using pointer capture" {
112}121}
113122
114fn testSwitchEnumPtrCapture() void {123fn testSwitchEnumPtrCapture() void {
115 var value = SwitchProngWithVarEnum { .One = 1234 };124 var value = SwitchProngWithVarEnum {
125 .One = 1234,
126 };
116 switch (value) {127 switch (value) {
117 SwitchProngWithVarEnum.One => |*x| *x += 1,128 SwitchProngWithVarEnum.One => |*x| x.* += 1,
118 else => unreachable,129 else => unreachable,
119 }130 }
120 switch (value) {131 switch (value) {
...@@ -125,8 +136,12 @@ fn testSwitchEnumPtrCapture() void {...@@ -125,8 +136,12 @@ fn testSwitchEnumPtrCapture() void {
125136
126test "switch with multiple expressions" {137test "switch with multiple expressions" {
127 const x = switch (returnsFive()) {138 const x = switch (returnsFive()) {
128 1, 2, 3 => 1,139 1,
129 4, 5, 6 => 2,140 2,
141 3 => 1,
142 4,
143 5,
144 6 => 2,
130 else => i32(3),145 else => i32(3),
131 };146 };
132 assert(x == 2);147 assert(x == 2);
...@@ -135,14 +150,15 @@ fn returnsFive() i32 {...@@ -135,14 +150,15 @@ fn returnsFive() i32 {
135 return 5;150 return 5;
136}151}
137152
138
139const Number = union(enum) {153const Number = union(enum) {
140 One: u64,154 One: u64,
141 Two: u8,155 Two: u8,
142 Three: f32,156 Three: f32,
143};157};
144158
145const number = Number { .Three = 1.23 };159const number = Number {
160 .Three = 1.23,
161};
146162
147fn returnsFalse() bool {163fn returnsFalse() bool {
148 switch (number) {164 switch (number) {
...@@ -198,7 +214,8 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {...@@ -198,7 +214,8 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {
198 return switch (x) {214 return switch (x) {
199 0 ... 100 => u8(0),215 0 ... 100 => u8(0),
200 101 ... 200 => 1,216 101 ... 200 => 1,
201 201, 203 => 2,217 201,
218 203 => 2,
202 202 => 4,219 202 => 4,
203 204 ... 255 => 3,220 204 ... 255 => 3,
204 };221 };
test/cases/switch_prong_err_enum.zig+6-2
...@@ -14,14 +14,18 @@ const FormValue = union(enum) {...@@ -14,14 +14,18 @@ const FormValue = union(enum) {
1414
15fn doThing(form_id: u64) error!FormValue {15fn doThing(form_id: u64) error!FormValue {
16 return switch (form_id) {16 return switch (form_id) {
17 17 => FormValue { .Address = try readOnce() },17 17 => FormValue {
18 .Address = try readOnce(),
19 },
18 else => error.InvalidDebugInfo,20 else => error.InvalidDebugInfo,
19 };21 };
20}22}
2123
22test "switch prong returns error enum" {24test "switch prong returns error enum" {
23 switch (doThing(17) catch unreachable) {25 switch (doThing(17) catch unreachable) {
24 FormValue.Address => |payload| { assert(payload == 1); },26 FormValue.Address => |payload| {
27 assert(payload == 1);
28 },
25 else => unreachable,29 else => unreachable,
26 }30 }
27 assert(read_count == 1);31 assert(read_count == 1);
test/cases/switch_prong_implicit_cast.zig+6-2
...@@ -7,8 +7,12 @@ const FormValue = union(enum) {...@@ -7,8 +7,12 @@ const FormValue = union(enum) {
77
8fn foo(id: u64) !FormValue {8fn foo(id: u64) !FormValue {
9 return switch (id) {9 return switch (id) {
10 2 => FormValue { .Two = true },10 2 => FormValue {
11 1 => FormValue { .One = {} },11 .Two = true,
12 },
13 1 => FormValue {
14 .One = {},
15 },
12 else => return error.Whatever,16 else => return error.Whatever,
13 };17 };
14}18}
test/cases/syntax.zig-7
...@@ -2,11 +2,9 @@...@@ -2,11 +2,9 @@
22
3const struct_trailing_comma = struct { x: i32, y: i32, };3const struct_trailing_comma = struct { x: i32, y: i32, };
4const struct_no_comma = struct { x: i32, y: i32 };4const struct_no_comma = struct { x: i32, y: i32 };
5const struct_no_comma_void_type = struct { x: i32, y };
6const struct_fn_no_comma = struct { fn m() void {} y: i32 };5const struct_fn_no_comma = struct { fn m() void {} y: i32 };
76
8const enum_no_comma = enum { A, B };7const enum_no_comma = enum { A, B };
9const enum_no_comma_type = enum { A, B: i32 };
108
11fn container_init() void {9fn container_init() void {
12 const S = struct { x: i32, y: i32 };10 const S = struct { x: i32, y: i32 };
...@@ -36,16 +34,11 @@ fn switch_prongs(x: i32) void {...@@ -36,16 +34,11 @@ fn switch_prongs(x: i32) void {
3634
37const fn_no_comma = fn(i32, i32)void;35const fn_no_comma = fn(i32, i32)void;
38const fn_trailing_comma = fn(i32, i32,)void;36const fn_trailing_comma = fn(i32, i32,)void;
39const fn_vararg_trailing_comma = fn(i32, i32, ...,)void;
4037
41fn fn_calls() void {38fn fn_calls() void {
42 fn add(x: i32, y: i32,) i32 { x + y };39 fn add(x: i32, y: i32,) i32 { x + y };
43 _ = add(1, 2);40 _ = add(1, 2);
44 _ = add(1, 2,);41 _ = add(1, 2,);
45
46 fn swallow(x: ...,) void {};
47 _ = swallow(1,2,3,);
48 _ = swallow();
49}42}
5043
51fn asm_lists() void {44fn asm_lists() void {
test/cases/try.zig+3-5
...@@ -3,14 +3,12 @@ const assert = @import("std").debug.assert;...@@ -3,14 +3,12 @@ const assert = @import("std").debug.assert;
3test "try on error union" {3test "try on error union" {
4 tryOnErrorUnionImpl();4 tryOnErrorUnionImpl();
5 comptime tryOnErrorUnionImpl();5 comptime tryOnErrorUnionImpl();
6
7}6}
87
9fn tryOnErrorUnionImpl() void {8fn tryOnErrorUnionImpl() void {
10 const x = if (returnsTen()) |val|9 const x = if (returnsTen()) |val| val + 1 else |err| switch (err) {
11 val + 110 error.ItBroke,
12 else |err| switch (err) {11 error.NoMem => 1,
13 error.ItBroke, error.NoMem => 1,
14 error.CrappedOut => i32(2),12 error.CrappedOut => i32(2),
15 else => unreachable,13 else => unreachable,
16 };14 };
test/cases/type_info.zig+177-142
...@@ -4,167 +4,199 @@ const TypeInfo = @import("builtin").TypeInfo;...@@ -4,167 +4,199 @@ const TypeInfo = @import("builtin").TypeInfo;
4const TypeId = @import("builtin").TypeId;4const TypeId = @import("builtin").TypeId;
55
6test "type info: tag type, void info" {6test "type info: tag type, void info" {
7 comptime {7 testBasic();
8 assert(@TagType(TypeInfo) == TypeId);8 comptime testBasic();
9 const void_info = @typeInfo(void);9}
10 assert(TypeId(void_info) == TypeId.Void);10
11 assert(void_info.Void == {});11fn testBasic() void {
12 }12 assert(@TagType(TypeInfo) == TypeId);
13 const void_info = @typeInfo(void);
14 assert(TypeId(void_info) == TypeId.Void);
15 assert(void_info.Void == {});
13}16}
1417
15test "type info: integer, floating point type info" {18test "type info: integer, floating point type info" {
16 comptime {19 testIntFloat();
17 const u8_info = @typeInfo(u8);20 comptime testIntFloat();
18 assert(TypeId(u8_info) == TypeId.Int);21}
19 assert(!u8_info.Int.is_signed);
20 assert(u8_info.Int.bits == 8);
2122
22 const f64_info = @typeInfo(f64);23fn testIntFloat() void {
23 assert(TypeId(f64_info) == TypeId.Float);24 const u8_info = @typeInfo(u8);
24 assert(f64_info.Float.bits == 64);25 assert(TypeId(u8_info) == TypeId.Int);
25 }26 assert(!u8_info.Int.is_signed);
27 assert(u8_info.Int.bits == 8);
28
29 const f64_info = @typeInfo(f64);
30 assert(TypeId(f64_info) == TypeId.Float);
31 assert(f64_info.Float.bits == 64);
26}32}
2733
28test "type info: pointer type info" {34test "type info: pointer type info" {
29 comptime {35 testPointer();
30 const u32_ptr_info = @typeInfo(&u32);36 comptime testPointer();
31 assert(TypeId(u32_ptr_info) == TypeId.Pointer);37}
32 assert(u32_ptr_info.Pointer.is_const == false);38
33 assert(u32_ptr_info.Pointer.is_volatile == false);39fn testPointer() void {
34 assert(u32_ptr_info.Pointer.alignment == 4);40 const u32_ptr_info = @typeInfo(&u32);
35 assert(u32_ptr_info.Pointer.child == u32);41 assert(TypeId(u32_ptr_info) == TypeId.Pointer);
36 }42 assert(u32_ptr_info.Pointer.is_const == false);
43 assert(u32_ptr_info.Pointer.is_volatile == false);
44 assert(u32_ptr_info.Pointer.alignment == 4);
45 assert(u32_ptr_info.Pointer.child == u32);
37}46}
3847
39test "type info: slice type info" {48test "type info: slice type info" {
40 comptime {49 testSlice();
41 const u32_slice_info = @typeInfo([]u32);50 comptime testSlice();
42 assert(TypeId(u32_slice_info) == TypeId.Slice);51}
43 assert(u32_slice_info.Slice.is_const == false);52
44 assert(u32_slice_info.Slice.is_volatile == false);53fn testSlice() void {
45 assert(u32_slice_info.Slice.alignment == 4);54 const u32_slice_info = @typeInfo([]u32);
46 assert(u32_slice_info.Slice.child == u32);55 assert(TypeId(u32_slice_info) == TypeId.Slice);
47 }56 assert(u32_slice_info.Slice.is_const == false);
57 assert(u32_slice_info.Slice.is_volatile == false);
58 assert(u32_slice_info.Slice.alignment == 4);
59 assert(u32_slice_info.Slice.child == u32);
48}60}
4961
50test "type info: array type info" {62test "type info: array type info" {
51 comptime {63 testArray();
52 const arr_info = @typeInfo([42]bool);64 comptime testArray();
53 assert(TypeId(arr_info) == TypeId.Array);65}
54 assert(arr_info.Array.len == 42);66
55 assert(arr_info.Array.child == bool);67fn testArray() void {
56 }68 const arr_info = @typeInfo([42]bool);
69 assert(TypeId(arr_info) == TypeId.Array);
70 assert(arr_info.Array.len == 42);
71 assert(arr_info.Array.child == bool);
57}72}
5873
59test "type info: nullable type info" {74test "type info: nullable type info" {
60 comptime {75 testNullable();
61 const null_info = @typeInfo(?void);76 comptime testNullable();
62 assert(TypeId(null_info) == TypeId.Nullable);77}
63 assert(null_info.Nullable.child == void);78
64 }79fn testNullable() void {
80 const null_info = @typeInfo(?void);
81 assert(TypeId(null_info) == TypeId.Nullable);
82 assert(null_info.Nullable.child == void);
65}83}
6684
67test "type info: promise info" {85test "type info: promise info" {
68 comptime {86 testPromise();
69 const null_promise_info = @typeInfo(promise);87 comptime testPromise();
70 assert(TypeId(null_promise_info) == TypeId.Promise);88}
71 assert(null_promise_info.Promise.child == @typeOf(undefined));
7289
73 const promise_info = @typeInfo(promise->usize);90fn testPromise() void {
74 assert(TypeId(promise_info) == TypeId.Promise);91 const null_promise_info = @typeInfo(promise);
75 assert(promise_info.Promise.child == usize);92 assert(TypeId(null_promise_info) == TypeId.Promise);
76 }93 assert(null_promise_info.Promise.child == @typeOf(undefined));
7794
95 const promise_info = @typeInfo(promise->usize);
96 assert(TypeId(promise_info) == TypeId.Promise);
97 assert(promise_info.Promise.child == usize);
78}98}
7999
80test "type info: error set, error union info" {100test "type info: error set, error union info" {
81 comptime {101 testErrorSet();
82 const TestErrorSet = error {102 comptime testErrorSet();
83 First,103}
84 Second,104
85 Third,105fn testErrorSet() void {
86 };106 const TestErrorSet = error {
87107 First,
88 const error_set_info = @typeInfo(TestErrorSet);108 Second,
89 assert(TypeId(error_set_info) == TypeId.ErrorSet);109 Third,
90 assert(error_set_info.ErrorSet.errors.len == 3);110 };
91 assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));111
92 assert(error_set_info.ErrorSet.errors[2].value == usize(TestErrorSet.Third));112 const error_set_info = @typeInfo(TestErrorSet);
93113 assert(TypeId(error_set_info) == TypeId.ErrorSet);
94 const error_union_info = @typeInfo(TestErrorSet!usize);114 assert(error_set_info.ErrorSet.errors.len == 3);
95 assert(TypeId(error_union_info) == TypeId.ErrorUnion);115 assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
96 assert(error_union_info.ErrorUnion.error_set == TestErrorSet);116 assert(error_set_info.ErrorSet.errors[2].value == usize(TestErrorSet.Third));
97 assert(error_union_info.ErrorUnion.payload == usize);117
98 }118 const error_union_info = @typeInfo(TestErrorSet!usize);
119 assert(TypeId(error_union_info) == TypeId.ErrorUnion);
120 assert(error_union_info.ErrorUnion.error_set == TestErrorSet);
121 assert(error_union_info.ErrorUnion.payload == usize);
99}122}
100123
101test "type info: enum info" {124test "type info: enum info" {
102 comptime {125 testEnum();
103 const Os = @import("builtin").Os;126 comptime testEnum();
127}
104128
105 const os_info = @typeInfo(Os);129fn testEnum() void {
106 assert(TypeId(os_info) == TypeId.Enum);130 const Os = @import("builtin").Os;
107 assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);131
108 assert(os_info.Enum.fields.len == 32);132 const os_info = @typeInfo(Os);
109 assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas"));133 assert(TypeId(os_info) == TypeId.Enum);
110 assert(os_info.Enum.fields[10].value == 10);134 assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
111 assert(os_info.Enum.tag_type == u5);135 assert(os_info.Enum.fields.len == 32);
112 assert(os_info.Enum.defs.len == 0);136 assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas"));
113 }137 assert(os_info.Enum.fields[10].value == 10);
138 assert(os_info.Enum.tag_type == u5);
139 assert(os_info.Enum.defs.len == 0);
114}140}
115141
116test "type info: union info" {142test "type info: union info" {
117 comptime {143 testUnion();
118 const typeinfo_info = @typeInfo(TypeInfo);144 comptime testUnion();
119 assert(TypeId(typeinfo_info) == TypeId.Union);145}
120 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);146
121 assert(typeinfo_info.Union.tag_type == TypeId);147fn testUnion() void {
122 assert(typeinfo_info.Union.fields.len == 26);148 const typeinfo_info = @typeInfo(TypeInfo);
123 assert(typeinfo_info.Union.fields[4].enum_field != null);149 assert(TypeId(typeinfo_info) == TypeId.Union);
124 assert((??typeinfo_info.Union.fields[4].enum_field).value == 4);150 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
125 assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));151 assert(typeinfo_info.Union.tag_type == TypeId);
126 assert(typeinfo_info.Union.defs.len == 21);152 assert(typeinfo_info.Union.fields.len == 26);
127153 assert(typeinfo_info.Union.fields[4].enum_field != null);
128 const TestNoTagUnion = union {154 assert((??typeinfo_info.Union.fields[4].enum_field).value == 4);
129 Foo: void,155 assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
130 Bar: u32,156 assert(typeinfo_info.Union.defs.len == 21);
131 };157
132158 const TestNoTagUnion = union {
133 const notag_union_info = @typeInfo(TestNoTagUnion);159 Foo: void,
134 assert(TypeId(notag_union_info) == TypeId.Union);160 Bar: u32,
135 assert(notag_union_info.Union.tag_type == @typeOf(undefined));161 };
136 assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);162
137 assert(notag_union_info.Union.fields.len == 2);163 const notag_union_info = @typeInfo(TestNoTagUnion);
138 assert(notag_union_info.Union.fields[0].enum_field == null);164 assert(TypeId(notag_union_info) == TypeId.Union);
139 assert(notag_union_info.Union.fields[1].field_type == u32);165 assert(notag_union_info.Union.tag_type == @typeOf(undefined));
140166 assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
141 const TestExternUnion = extern union {167 assert(notag_union_info.Union.fields.len == 2);
142 foo: &c_void,168 assert(notag_union_info.Union.fields[0].enum_field == null);
143 };169 assert(notag_union_info.Union.fields[1].field_type == u32);
144170
145 const extern_union_info = @typeInfo(TestExternUnion);171 const TestExternUnion = extern union {
146 assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);172 foo: &c_void,
147 assert(extern_union_info.Union.tag_type == @typeOf(undefined));173 };
148 assert(extern_union_info.Union.fields[0].enum_field == null);174
149 assert(extern_union_info.Union.fields[0].field_type == &c_void);175 const extern_union_info = @typeInfo(TestExternUnion);
150 }176 assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
177 assert(extern_union_info.Union.tag_type == @typeOf(undefined));
178 assert(extern_union_info.Union.fields[0].enum_field == null);
179 assert(extern_union_info.Union.fields[0].field_type == &c_void);
151}180}
152181
153test "type info: struct info" {182test "type info: struct info" {
154 comptime {183 testStruct();
155 const struct_info = @typeInfo(TestStruct);184 comptime testStruct();
156 assert(TypeId(struct_info) == TypeId.Struct);185}
157 assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);186
158 assert(struct_info.Struct.fields.len == 3);187fn testStruct() void {
159 assert(struct_info.Struct.fields[1].offset == null);188 const struct_info = @typeInfo(TestStruct);
160 assert(struct_info.Struct.fields[2].field_type == &TestStruct);189 assert(TypeId(struct_info) == TypeId.Struct);
161 assert(struct_info.Struct.defs.len == 2);190 assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
162 assert(struct_info.Struct.defs[0].is_pub);191 assert(struct_info.Struct.fields.len == 3);
163 assert(!struct_info.Struct.defs[0].data.Fn.is_extern);192 assert(struct_info.Struct.fields[1].offset == null);
164 assert(struct_info.Struct.defs[0].data.Fn.lib_name == null);193 assert(struct_info.Struct.fields[2].field_type == &TestStruct);
165 assert(struct_info.Struct.defs[0].data.Fn.return_type == void);194 assert(struct_info.Struct.defs.len == 2);
166 assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn(&const TestStruct)void);195 assert(struct_info.Struct.defs[0].is_pub);
167 }196 assert(!struct_info.Struct.defs[0].data.Fn.is_extern);
197 assert(struct_info.Struct.defs[0].data.Fn.lib_name == null);
198 assert(struct_info.Struct.defs[0].data.Fn.return_type == void);
199 assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn(&const TestStruct)void);
168}200}
169201
170const TestStruct = packed struct {202const TestStruct = packed struct {
...@@ -178,21 +210,24 @@ const TestStruct = packed struct {...@@ -178,21 +210,24 @@ const TestStruct = packed struct {
178};210};
179211
180test "type info: function type info" {212test "type info: function type info" {
181 comptime {213 testFunction();
182 const fn_info = @typeInfo(@typeOf(foo));214 comptime testFunction();
183 assert(TypeId(fn_info) == TypeId.Fn);215}
184 assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);216
185 assert(fn_info.Fn.is_generic);217fn testFunction() void {
186 assert(fn_info.Fn.args.len == 2);218 const fn_info = @typeInfo(@typeOf(foo));
187 assert(fn_info.Fn.is_var_args);219 assert(TypeId(fn_info) == TypeId.Fn);
188 assert(fn_info.Fn.return_type == @typeOf(undefined));220 assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
189 assert(fn_info.Fn.async_allocator_type == @typeOf(undefined));221 assert(fn_info.Fn.is_generic);
190222 assert(fn_info.Fn.args.len == 2);
191 const test_instance: TestStruct = undefined;223 assert(fn_info.Fn.is_var_args);
192 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));224 assert(fn_info.Fn.return_type == @typeOf(undefined));
193 assert(TypeId(bound_fn_info) == TypeId.BoundFn);225 assert(fn_info.Fn.async_allocator_type == @typeOf(undefined));
194 assert(bound_fn_info.BoundFn.args[0].arg_type == &const TestStruct);226
195 }227 const test_instance: TestStruct = undefined;
228 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
229 assert(TypeId(bound_fn_info) == TypeId.BoundFn);
230 assert(bound_fn_info.BoundFn.args[0].arg_type == &const TestStruct);
196}231}
197232
198fn foo(comptime a: usize, b: bool, args: ...) usize {233fn foo(comptime a: usize, b: bool, args: ...) usize {
test/cases/undefined.zig+2-2
...@@ -63,6 +63,6 @@ test "assign undefined to struct with method" {...@@ -63,6 +63,6 @@ test "assign undefined to struct with method" {
63}63}
6464
65test "type name of undefined" {65test "type name of undefined" {
66 const x = undefined;66 const x = undefined;
67 assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));67 assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
68}68}
test/cases/union.zig+50-36
...@@ -10,38 +10,41 @@ const Agg = struct {...@@ -10,38 +10,41 @@ const Agg = struct {
10 val2: Value,10 val2: Value,
11};11};
1212
13const v1 = Value { .Int = 1234 };13const v1 = Value{ .Int = 1234 };
14const v2 = Value { .Array = []u8{3} ** 9 };14const v2 = Value{ .Array = []u8{3} ** 9 };
1515
16const err = (error!Agg)(Agg {16const err = (error!Agg)(Agg{
17 .val1 = v1,17 .val1 = v1,
18 .val2 = v2,18 .val2 = v2,
19});19});
2020
21const array = []Value { v1, v2, v1, v2};21const array = []Value{
2222 v1,
23 v2,
24 v1,
25 v2,
26};
2327
24test "unions embedded in aggregate types" {28test "unions embedded in aggregate types" {
25 switch (array[1]) {29 switch (array[1]) {
26 Value.Array => |arr| assert(arr[4] == 3),30 Value.Array => |arr| assert(arr[4] == 3),
27 else => unreachable,31 else => unreachable,
28 }32 }
29 switch((err catch unreachable).val1) {33 switch ((err catch unreachable).val1) {
30 Value.Int => |x| assert(x == 1234),34 Value.Int => |x| assert(x == 1234),
31 else => unreachable,35 else => unreachable,
32 }36 }
33}37}
3438
35
36const Foo = union {39const Foo = union {
37 float: f64,40 float: f64,
38 int: i32,41 int: i32,
39};42};
4043
41test "basic unions" {44test "basic unions" {
42 var foo = Foo { .int = 1 };45 var foo = Foo{ .int = 1 };
43 assert(foo.int == 1);46 assert(foo.int == 1);
44 foo = Foo {.float = 12.34};47 foo = Foo{ .float = 12.34 };
45 assert(foo.float == 12.34);48 assert(foo.float == 12.34);
46}49}
4750
...@@ -66,11 +69,11 @@ test "init union with runtime value" {...@@ -66,11 +69,11 @@ test "init union with runtime value" {
66}69}
6770
68fn setFloat(foo: &Foo, x: f64) void {71fn setFloat(foo: &Foo, x: f64) void {
69 *foo = Foo { .float = x };72 foo.* = Foo{ .float = x };
70}73}
7174
72fn setInt(foo: &Foo, x: i32) void {75fn setInt(foo: &Foo, x: i32) void {
73 *foo = Foo { .int = x };76 foo.* = Foo{ .int = x };
74}77}
7578
76const FooExtern = extern union {79const FooExtern = extern union {
...@@ -79,13 +82,12 @@ const FooExtern = extern union {...@@ -79,13 +82,12 @@ const FooExtern = extern union {
79};82};
8083
81test "basic extern unions" {84test "basic extern unions" {
82 var foo = FooExtern { .int = 1 };85 var foo = FooExtern{ .int = 1 };
83 assert(foo.int == 1);86 assert(foo.int == 1);
84 foo.float = 12.34;87 foo.float = 12.34;
85 assert(foo.float == 12.34);88 assert(foo.float == 12.34);
86}89}
8790
88
89const Letter = enum {91const Letter = enum {
90 A,92 A,
91 B,93 B,
...@@ -103,12 +105,12 @@ test "union with specified enum tag" {...@@ -103,12 +105,12 @@ test "union with specified enum tag" {
103}105}
104106
105fn doTest() void {107fn doTest() void {
106 assert(bar(Payload {.A = 1234}) == -10);108 assert(bar(Payload{ .A = 1234 }) == -10);
107}109}
108110
109fn bar(value: &const Payload) i32 {111fn bar(value: &const Payload) i32 {
110 assert(Letter(*value) == Letter.A);112 assert(Letter(value.*) == Letter.A);
111 return switch (*value) {113 return switch (value.*) {
112 Payload.A => |x| return x - 1244,114 Payload.A => |x| return x - 1244,
113 Payload.B => |x| if (x == 12.34) i32(20) else 21,115 Payload.B => |x| if (x == 12.34) i32(20) else 21,
114 Payload.C => |x| if (x) i32(30) else 31,116 Payload.C => |x| if (x) i32(30) else 31,
...@@ -141,13 +143,13 @@ const MultipleChoice2 = union(enum(u32)) {...@@ -141,13 +143,13 @@ const MultipleChoice2 = union(enum(u32)) {
141143
142test "union(enum(u32)) with specified and unspecified tag values" {144test "union(enum(u32)) with specified and unspecified tag values" {
143 comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);145 comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);
144 testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 {.C = 123});146 testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
145 comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 { .C = 123} );147 comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
146}148}
147149
148fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) void {150fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) void {
149 assert(u32(@TagType(MultipleChoice2)(*x)) == 60);151 assert(u32(@TagType(MultipleChoice2)(x.*)) == 60);
150 assert(1123 == switch (*x) {152 assert(1123 == switch (x.*) {
151 MultipleChoice2.A => 1,153 MultipleChoice2.A => 1,
152 MultipleChoice2.B => 2,154 MultipleChoice2.B => 2,
153 MultipleChoice2.C => |v| i32(1000) + v,155 MultipleChoice2.C => |v| i32(1000) + v,
...@@ -160,10 +162,9 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) void...@@ -160,10 +162,9 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) void
160 });162 });
161}163}
162164
163
164const ExternPtrOrInt = extern union {165const ExternPtrOrInt = extern union {
165 ptr: &u8,166 ptr: &u8,
166 int: u64167 int: u64,
167};168};
168test "extern union size" {169test "extern union size" {
169 comptime assert(@sizeOf(ExternPtrOrInt) == 8);170 comptime assert(@sizeOf(ExternPtrOrInt) == 8);
...@@ -171,7 +172,7 @@ test "extern union size" {...@@ -171,7 +172,7 @@ test "extern union size" {
171172
172const PackedPtrOrInt = packed union {173const PackedPtrOrInt = packed union {
173 ptr: &u8,174 ptr: &u8,
174 int: u64175 int: u64,
175};176};
176test "extern union size" {177test "extern union size" {
177 comptime assert(@sizeOf(PackedPtrOrInt) == 8);178 comptime assert(@sizeOf(PackedPtrOrInt) == 8);
...@@ -184,8 +185,16 @@ test "union with only 1 field which is void should be zero bits" {...@@ -184,8 +185,16 @@ test "union with only 1 field which is void should be zero bits" {
184 comptime assert(@sizeOf(ZeroBits) == 0);185 comptime assert(@sizeOf(ZeroBits) == 0);
185}186}
186187
187const TheTag = enum {A, B, C};188const TheTag = enum {
188const TheUnion = union(TheTag) { A: i32, B: i32, C: i32 };189 A,
190 B,
191 C,
192};
193const TheUnion = union(TheTag) {
194 A: i32,
195 B: i32,
196 C: i32,
197};
189test "union field access gives the enum values" {198test "union field access gives the enum values" {
190 assert(TheUnion.A == TheTag.A);199 assert(TheUnion.A == TheTag.A);
191 assert(TheUnion.B == TheTag.B);200 assert(TheUnion.B == TheTag.B);
...@@ -193,20 +202,28 @@ test "union field access gives the enum values" {...@@ -193,20 +202,28 @@ test "union field access gives the enum values" {
193}202}
194203
195test "cast union to tag type of union" {204test "cast union to tag type of union" {
196 testCastUnionToTagType(TheUnion {.B = 1234});205 testCastUnionToTagType(TheUnion{ .B = 1234 });
197 comptime testCastUnionToTagType(TheUnion {.B = 1234});206 comptime testCastUnionToTagType(TheUnion{ .B = 1234 });
198}207}
199208
200fn testCastUnionToTagType(x: &const TheUnion) void {209fn testCastUnionToTagType(x: &const TheUnion) void {
201 assert(TheTag(*x) == TheTag.B);210 assert(TheTag(x.*) == TheTag.B);
202}211}
203212
204test "cast tag type of union to union" {213test "cast tag type of union to union" {
205 var x: Value2 = Letter2.B;214 var x: Value2 = Letter2.B;
206 assert(Letter2(x) == Letter2.B);215 assert(Letter2(x) == Letter2.B);
207}216}
208const Letter2 = enum { A, B, C };217const Letter2 = enum {
209const Value2 = union(Letter2) { A: i32, B, C, };218 A,
219 B,
220 C,
221};
222const Value2 = union(Letter2) {
223 A: i32,
224 B,
225 C,
226};
210227
211test "implicit cast union to its tag type" {228test "implicit cast union to its tag type" {
212 var x: Value2 = Letter2.B;229 var x: Value2 = Letter2.B;
...@@ -227,19 +244,16 @@ const TheUnion2 = union(enum) {...@@ -227,19 +244,16 @@ const TheUnion2 = union(enum) {
227};244};
228245
229fn assertIsTheUnion2Item1(value: &const TheUnion2) void {246fn assertIsTheUnion2Item1(value: &const TheUnion2) void {
230 assert(*value == TheUnion2.Item1);247 assert(value.* == TheUnion2.Item1);
231}248}
232249
233
234pub const PackThis = union(enum) {250pub const PackThis = union(enum) {
235 Invalid: bool,251 Invalid: bool,
236 StringLiteral: u2,252 StringLiteral: u2,
237};253};
238254
239test "constant packed union" {255test "constant packed union" {
240 testConstPackedUnion([]PackThis {256 testConstPackedUnion([]PackThis{PackThis{ .StringLiteral = 1 }});
241 PackThis { .StringLiteral = 1 },
242 });
243}257}
244258
245fn testConstPackedUnion(expected_tokens: []const PackThis) void {259fn testConstPackedUnion(expected_tokens: []const PackThis) void {
...@@ -252,7 +266,7 @@ test "switch on union with only 1 field" {...@@ -252,7 +266,7 @@ test "switch on union with only 1 field" {
252 switch (r) {266 switch (r) {
253 PartialInst.Compiled => {267 PartialInst.Compiled => {
254 var z: PartialInstWithPayload = undefined;268 var z: PartialInstWithPayload = undefined;
255 z = PartialInstWithPayload { .Compiled = 1234 };269 z = PartialInstWithPayload{ .Compiled = 1234 };
256 switch (z) {270 switch (z) {
257 PartialInstWithPayload.Compiled => |x| {271 PartialInstWithPayload.Compiled => |x| {
258 assert(x == 1234);272 assert(x == 1234);
test/cases/var_args.zig+16-9
...@@ -2,9 +2,12 @@ const assert = @import("std").debug.assert;...@@ -2,9 +2,12 @@ const assert = @import("std").debug.assert;
22
3fn add(args: ...) i32 {3fn add(args: ...) i32 {
4 var sum = i32(0);4 var sum = i32(0);
5 {comptime var i: usize = 0; inline while (i < args.len) : (i += 1) {5 {
6 sum += args[i];6 comptime var i: usize = 0;
7 }}7 inline while (i < args.len) : (i += 1) {
8 sum += args[i];
9 }
10 }
8 return sum;11 return sum;
9}12}
1013
...@@ -55,18 +58,23 @@ fn extraFn(extra: u32, args: ...) usize {...@@ -55,18 +58,23 @@ fn extraFn(extra: u32, args: ...) usize {
55 return args.len;58 return args.len;
56}59}
5760
61const foos = []fn(...) bool {
62 foo1,
63 foo2,
64};
5865
59const foos = []fn(...) bool { foo1, foo2 };66fn foo1(args: ...) bool {
6067 return true;
61fn foo1(args: ...) bool { return true; }68}
62fn foo2(args: ...) bool { return false; }69fn foo2(args: ...) bool {
70 return false;
71}
6372
64test "array of var args functions" {73test "array of var args functions" {
65 assert(foos[0]());74 assert(foos[0]());
66 assert(!foos[1]());75 assert(!foos[1]());
67}76}
6877
69
70test "pass array and slice of same array to var args should have same pointers" {78test "pass array and slice of same array to var args should have same pointers" {
71 const array = "hi";79 const array = "hi";
72 const slice: []const u8 = array;80 const slice: []const u8 = array;
...@@ -79,7 +87,6 @@ fn assertSlicePtrsEql(args: ...) void {...@@ -79,7 +87,6 @@ fn assertSlicePtrsEql(args: ...) void {
79 assert(s1.ptr == s2.ptr);87 assert(s1.ptr == s2.ptr);
80}88}
8189
82
83test "pass zero length array to var args param" {90test "pass zero length array to var args param" {
84 doNothingWithFirstArg("");91 doNothingWithFirstArg("");
85}92}
test/cases/while.zig+41-24
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
22
3test "while loop" {3test "while loop" {
4 var i : i32 = 0;4 var i: i32 = 0;
5 while (i < 4) {5 while (i < 4) {
6 i += 1;6 i += 1;
7 }7 }
...@@ -35,7 +35,7 @@ test "continue and break" {...@@ -35,7 +35,7 @@ test "continue and break" {
35}35}
36var continue_and_break_counter: i32 = 0;36var continue_and_break_counter: i32 = 0;
37fn runContinueAndBreakTest() void {37fn runContinueAndBreakTest() void {
38 var i : i32 = 0;38 var i: i32 = 0;
39 while (true) {39 while (true) {
40 continue_and_break_counter += 2;40 continue_and_break_counter += 2;
41 i += 1;41 i += 1;
...@@ -58,10 +58,13 @@ fn returnWithImplicitCastFromWhileLoopTest() error!void {...@@ -58,10 +58,13 @@ fn returnWithImplicitCastFromWhileLoopTest() error!void {
5858
59test "while with continue expression" {59test "while with continue expression" {
60 var sum: i32 = 0;60 var sum: i32 = 0;
61 {var i: i32 = 0; while (i < 10) : (i += 1) {61 {
62 if (i == 5) continue;62 var i: i32 = 0;
63 sum += i;63 while (i < 10) : (i += 1) {
64 }}64 if (i == 5) continue;
65 sum += i;
66 }
67 }
65 assert(sum == 40);68 assert(sum == 40);
66}69}
6770
...@@ -117,17 +120,13 @@ test "while with error union condition" {...@@ -117,17 +120,13 @@ test "while with error union condition" {
117120
118var numbers_left: i32 = undefined;121var numbers_left: i32 = undefined;
119fn getNumberOrErr() error!i32 {122fn getNumberOrErr() error!i32 {
120 return if (numbers_left == 0)123 return if (numbers_left == 0) error.OutOfNumbers else x: {
121 error.OutOfNumbers
122 else x: {
123 numbers_left -= 1;124 numbers_left -= 1;
124 break :x numbers_left;125 break :x numbers_left;
125 };126 };
126}127}
127fn getNumberOrNull() ?i32 {128fn getNumberOrNull() ?i32 {
128 return if (numbers_left == 0)129 return if (numbers_left == 0) null else x: {
129 null
130 else x: {
131 numbers_left -= 1;130 numbers_left -= 1;
132 break :x numbers_left;131 break :x numbers_left;
133 };132 };
...@@ -136,42 +135,48 @@ fn getNumberOrNull() ?i32 {...@@ -136,42 +135,48 @@ fn getNumberOrNull() ?i32 {
136test "while on nullable with else result follow else prong" {135test "while on nullable with else result follow else prong" {
137 const result = while (returnNull()) |value| {136 const result = while (returnNull()) |value| {
138 break value;137 break value;
139 } else i32(2);138 } else
139 i32(2);
140 assert(result == 2);140 assert(result == 2);
141}141}
142142
143test "while on nullable with else result follow break prong" {143test "while on nullable with else result follow break prong" {
144 const result = while (returnMaybe(10)) |value| {144 const result = while (returnMaybe(10)) |value| {
145 break value;145 break value;
146 } else i32(2);146 } else
147 i32(2);
147 assert(result == 10);148 assert(result == 10);
148}149}
149150
150test "while on error union with else result follow else prong" {151test "while on error union with else result follow else prong" {
151 const result = while (returnError()) |value| {152 const result = while (returnError()) |value| {
152 break value;153 break value;
153 } else |err| i32(2);154 } else|err|
155 i32(2);
154 assert(result == 2);156 assert(result == 2);
155}157}
156158
157test "while on error union with else result follow break prong" {159test "while on error union with else result follow break prong" {
158 const result = while (returnSuccess(10)) |value| {160 const result = while (returnSuccess(10)) |value| {
159 break value;161 break value;
160 } else |err| i32(2);162 } else|err|
163 i32(2);
161 assert(result == 10);164 assert(result == 10);
162}165}
163166
164test "while on bool with else result follow else prong" {167test "while on bool with else result follow else prong" {
165 const result = while (returnFalse()) {168 const result = while (returnFalse()) {
166 break i32(10);169 break i32(10);
167 } else i32(2);170 } else
171 i32(2);
168 assert(result == 2);172 assert(result == 2);
169}173}
170174
171test "while on bool with else result follow break prong" {175test "while on bool with else result follow break prong" {
172 const result = while (returnTrue()) {176 const result = while (returnTrue()) {
173 break i32(10);177 break i32(10);
174 } else i32(2);178 } else
179 i32(2);
175 assert(result == 10);180 assert(result == 10);
176}181}
177182
...@@ -202,9 +207,21 @@ fn testContinueOuter() void {...@@ -202,9 +207,21 @@ fn testContinueOuter() void {
202 }207 }
203}208}
204209
205fn returnNull() ?i32 { return null; }210fn returnNull() ?i32 {
206fn returnMaybe(x: i32) ?i32 { return x; }211 return null;
207fn returnError() error!i32 { return error.YouWantedAnError; }212}
208fn returnSuccess(x: i32) error!i32 { return x; }213fn returnMaybe(x: i32) ?i32 {
209fn returnFalse() bool { return false; }214 return x;
210fn returnTrue() bool { return true; }215}
216fn returnError() error!i32 {
217 return error.YouWantedAnError;
218}
219fn returnSuccess(x: i32) error!i32 {
220 return x;
221}
222fn returnFalse() bool {
223 return false;
224}
225fn returnTrue() bool {
226 return true;
227}
test/compare_output.zig+4-4
...@@ -131,7 +131,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -131,7 +131,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
131 \\const is_windows = builtin.os == builtin.Os.windows;131 \\const is_windows = builtin.os == builtin.Os.windows;
132 \\const c = @cImport({132 \\const c = @cImport({
133 \\ if (is_windows) {133 \\ if (is_windows) {
134 \\ // See https://github.com/zig-lang/zig/issues/515134 \\ // See https://github.com/ziglang/zig/issues/515
135 \\ @cDefine("_NO_CRT_STDIO_INLINE", "1");135 \\ @cDefine("_NO_CRT_STDIO_INLINE", "1");
136 \\ @cInclude("io.h");136 \\ @cInclude("io.h");
137 \\ @cInclude("fcntl.h");137 \\ @cInclude("fcntl.h");
...@@ -287,9 +287,9 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -287,9 +287,9 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
287 \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) c_int {287 \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) c_int {
288 \\ const a_int = @ptrCast(&align(1) const i32, a ?? unreachable);288 \\ const a_int = @ptrCast(&align(1) const i32, a ?? unreachable);
289 \\ const b_int = @ptrCast(&align(1) const i32, b ?? unreachable);289 \\ const b_int = @ptrCast(&align(1) const i32, b ?? unreachable);
290 \\ if (*a_int < *b_int) {290 \\ if (a_int.* < b_int.*) {
291 \\ return -1;291 \\ return -1;
292 \\ } else if (*a_int > *b_int) {292 \\ } else if (a_int.* > b_int.*) {
293 \\ return 1;293 \\ return 1;
294 \\ } else {294 \\ } else {
295 \\ return 0;295 \\ return 0;
...@@ -316,7 +316,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {...@@ -316,7 +316,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
316 \\const is_windows = builtin.os == builtin.Os.windows;316 \\const is_windows = builtin.os == builtin.Os.windows;
317 \\const c = @cImport({317 \\const c = @cImport({
318 \\ if (is_windows) {318 \\ if (is_windows) {
319 \\ // See https://github.com/zig-lang/zig/issues/515319 \\ // See https://github.com/ziglang/zig/issues/515
320 \\ @cDefine("_NO_CRT_STDIO_INLINE", "1");320 \\ @cDefine("_NO_CRT_STDIO_INLINE", "1");
321 \\ @cInclude("io.h");321 \\ @cInclude("io.h");
322 \\ @cInclude("fcntl.h");322 \\ @cInclude("fcntl.h");
test/compile_errors.zig+15-15
...@@ -4,7 +4,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -4,7 +4,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
4 cases.add("invalid deref on switch target",4 cases.add("invalid deref on switch target",
5 \\comptime {5 \\comptime {
6 \\ var tile = Tile.Empty;6 \\ var tile = Tile.Empty;
7 \\ switch (*tile) {7 \\ switch (tile.*) {
8 \\ Tile.Empty => {},8 \\ Tile.Empty => {},
9 \\ Tile.Filled => {},9 \\ Tile.Filled => {},
10 \\ }10 \\ }
...@@ -14,7 +14,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -14,7 +14,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
14 \\ Filled,14 \\ Filled,
15 \\};15 \\};
16 ,16 ,
17 ".tmp_source.zig:3:13: error: invalid deref on switch target");17 ".tmp_source.zig:3:17: error: invalid deref on switch target");
1818
19 cases.add("invalid field access in comptime",19 cases.add("invalid field access in comptime",
20 \\comptime { var x = doesnt_exist.whatever; }20 \\comptime { var x = doesnt_exist.whatever; }
...@@ -1408,14 +1408,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1408,14 +1408,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1408 \\ Two: i32,1408 \\ Two: i32,
1409 \\};1409 \\};
1410 \\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) bool {1410 \\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) bool {
1411 \\ return *a == *b;1411 \\ return a.* == b.*;
1412 \\}1412 \\}
1413 \\1413 \\
1414 \\export fn entry1() usize { return @sizeOf(@typeOf(bad_eql_1)); }1414 \\export fn entry1() usize { return @sizeOf(@typeOf(bad_eql_1)); }
1415 \\export fn entry2() usize { return @sizeOf(@typeOf(bad_eql_2)); }1415 \\export fn entry2() usize { return @sizeOf(@typeOf(bad_eql_2)); }
1416 ,1416 ,
1417 ".tmp_source.zig:2:14: error: operator not allowed for type '[]u8'",1417 ".tmp_source.zig:2:14: error: operator not allowed for type '[]u8'",
1418 ".tmp_source.zig:9:15: error: operator not allowed for type 'EnumWithData'");1418 ".tmp_source.zig:9:16: error: operator not allowed for type 'EnumWithData'");
14191419
1420 cases.add("non-const switch number literal",1420 cases.add("non-const switch number literal",
1421 \\export fn foo() void {1421 \\export fn foo() void {
...@@ -1513,7 +1513,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1513,7 +1513,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1513 \\var bytes: [ext()]u8 = undefined;1513 \\var bytes: [ext()]u8 = undefined;
1514 \\export fn f() void {1514 \\export fn f() void {
1515 \\ for (bytes) |*b, i| {1515 \\ for (bytes) |*b, i| {
1516 \\ *b = u8(i);1516 \\ b.* = u8(i);
1517 \\ }1517 \\ }
1518 \\}1518 \\}
1519 , ".tmp_source.zig:2:13: error: unable to evaluate constant expression");1519 , ".tmp_source.zig:2:13: error: unable to evaluate constant expression");
...@@ -1819,7 +1819,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1819,7 +1819,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1819 \\}1819 \\}
1820 \\1820 \\
1821 \\fn bar(x: &const u3) u3 {1821 \\fn bar(x: &const u3) u3 {
1822 \\ return *x;1822 \\ return x.*;
1823 \\}1823 \\}
1824 \\1824 \\
1825 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }1825 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
...@@ -1903,12 +1903,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1903,12 +1903,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1903 \\var s_buffer: [10]u8 = undefined;1903 \\var s_buffer: [10]u8 = undefined;
1904 \\pub fn pass(in: []u8) []u8 {1904 \\pub fn pass(in: []u8) []u8 {
1905 \\ var out = &s_buffer;1905 \\ var out = &s_buffer;
1906 \\ *out[0] = in[0];1906 \\ out[0].* = in[0];
1907 \\ return (*out)[0..1];1907 \\ return out.*[0..1];
1908 \\}1908 \\}
1909 \\1909 \\
1910 \\export fn entry() usize { return @sizeOf(@typeOf(pass)); }1910 \\export fn entry() usize { return @sizeOf(@typeOf(pass)); }
1911 , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'");1911 , ".tmp_source.zig:4:11: error: attempt to dereference non pointer type '[10]u8'");
19121912
1913 cases.add("pass const ptr to mutable ptr fn",1913 cases.add("pass const ptr to mutable ptr fn",
1914 \\fn foo() bool {1914 \\fn foo() bool {
...@@ -2434,7 +2434,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -2434,7 +2434,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
2434 \\}2434 \\}
2435 \\2435 \\
2436 \\fn bar(x: &u32) void {2436 \\fn bar(x: &u32) void {
2437 \\ *x += 1;2437 \\ x.* += 1;
2438 \\}2438 \\}
2439 ,2439 ,
2440 ".tmp_source.zig:8:13: error: expected type '&u32', found '&align(1) u32'");2440 ".tmp_source.zig:8:13: error: expected type '&u32', found '&align(1) u32'");
...@@ -2461,7 +2461,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -2461,7 +2461,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
2461 \\export fn entry() u32 {2461 \\export fn entry() u32 {
2462 \\ var bytes: [4]u8 = []u8{0x01, 0x02, 0x03, 0x04};2462 \\ var bytes: [4]u8 = []u8{0x01, 0x02, 0x03, 0x04};
2463 \\ const ptr = @ptrCast(&u32, &bytes[0]);2463 \\ const ptr = @ptrCast(&u32, &bytes[0]);
2464 \\ return *ptr;2464 \\ return ptr.*;
2465 \\}2465 \\}
2466 ,2466 ,
2467 ".tmp_source.zig:3:17: error: cast increases pointer alignment",2467 ".tmp_source.zig:3:17: error: cast increases pointer alignment",
...@@ -2540,14 +2540,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -2540,14 +2540,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
2540 \\2540 \\
2541 \\export fn entry(opaque: &Opaque) void {2541 \\export fn entry(opaque: &Opaque) void {
2542 \\ var m2 = &2;2542 \\ var m2 = &2;
2543 \\ const y: u32 = *m2;2543 \\ const y: u32 = m2.*;
2544 \\2544 \\
2545 \\ var a = undefined;2545 \\ var a = undefined;
2546 \\ var b = 1;2546 \\ var b = 1;
2547 \\ var c = 1.0;2547 \\ var c = 1.0;
2548 \\ var d = this;2548 \\ var d = this;
2549 \\ var e = null;2549 \\ var e = null;
2550 \\ var f = *opaque;2550 \\ var f = opaque.*;
2551 \\ var g = i32;2551 \\ var g = i32;
2552 \\ var h = @import("std");2552 \\ var h = @import("std");
2553 \\ var i = (Foo {}).bar;2553 \\ var i = (Foo {}).bar;
...@@ -3136,13 +3136,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -3136,13 +3136,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
3136 \\ foo(a);3136 \\ foo(a);
3137 \\}3137 \\}
3138 \\fn foo(a: &const Payload) void {3138 \\fn foo(a: &const Payload) void {
3139 \\ switch (*a) {3139 \\ switch (a.*) {
3140 \\ Payload.A => {},3140 \\ Payload.A => {},
3141 \\ else => unreachable,3141 \\ else => unreachable,
3142 \\ }3142 \\ }
3143 \\}3143 \\}
3144 ,3144 ,
3145 ".tmp_source.zig:11:13: error: switch on union which has no attached enum",3145 ".tmp_source.zig:11:14: error: switch on union which has no attached enum",
3146 ".tmp_source.zig:1:17: note: consider 'union(enum)' here");3146 ".tmp_source.zig:1:17: note: consider 'union(enum)' here");
31473147
3148 cases.add("enum in field count range but not matching tag",3148 cases.add("enum in field count range but not matching tag",
test/standalone/brace_expansion/main.zig+23-20
...@@ -16,7 +16,7 @@ const Token = union(enum) {...@@ -16,7 +16,7 @@ const Token = union(enum) {
1616
17var global_allocator: &mem.Allocator = undefined;17var global_allocator: &mem.Allocator = undefined;
1818
19fn tokenize(input:[] const u8) !ArrayList(Token) {19fn tokenize(input: []const u8) !ArrayList(Token) {
20 const State = enum {20 const State = enum {
21 Start,21 Start,
22 Word,22 Word,
...@@ -29,7 +29,8 @@ fn tokenize(input:[] const u8) !ArrayList(Token) {...@@ -29,7 +29,8 @@ fn tokenize(input:[] const u8) !ArrayList(Token) {
29 for (input) |b, i| {29 for (input) |b, i| {
30 switch (state) {30 switch (state) {
31 State.Start => switch (b) {31 State.Start => switch (b) {
32 'a'...'z', 'A'...'Z' => {32 'a' ... 'z',
33 'A' ... 'Z' => {
33 state = State.Word;34 state = State.Word;
34 tok_begin = i;35 tok_begin = i;
35 },36 },
...@@ -39,9 +40,12 @@ fn tokenize(input:[] const u8) !ArrayList(Token) {...@@ -39,9 +40,12 @@ fn tokenize(input:[] const u8) !ArrayList(Token) {
39 else => return error.InvalidInput,40 else => return error.InvalidInput,
40 },41 },
41 State.Word => switch (b) {42 State.Word => switch (b) {
42 'a'...'z', 'A'...'Z' => {},43 'a' ... 'z',
43 '{', '}', ',' => {44 'A' ... 'Z' => {},
44 try token_list.append(Token { .Word = input[tok_begin..i] });45 '{',
46 '}',
47 ',' => {
48 try token_list.append(Token{ .Word = input[tok_begin..i] });
45 switch (b) {49 switch (b) {
46 '{' => try token_list.append(Token.OpenBrace),50 '{' => try token_list.append(Token.OpenBrace),
47 '}' => try token_list.append(Token.CloseBrace),51 '}' => try token_list.append(Token.CloseBrace),
...@@ -56,7 +60,7 @@ fn tokenize(input:[] const u8) !ArrayList(Token) {...@@ -56,7 +60,7 @@ fn tokenize(input:[] const u8) !ArrayList(Token) {
56 }60 }
57 switch (state) {61 switch (state) {
58 State.Start => {},62 State.Start => {},
59 State.Word => try token_list.append(Token {.Word = input[tok_begin..] }),63 State.Word => try token_list.append(Token{ .Word = input[tok_begin..] }),
60 }64 }
61 try token_list.append(Token.Eof);65 try token_list.append(Token.Eof);
62 return token_list;66 return token_list;
...@@ -68,24 +72,24 @@ const Node = union(enum) {...@@ -68,24 +72,24 @@ const Node = union(enum) {
68 Combine: []Node,72 Combine: []Node,
69};73};
7074
71const ParseError = error {75const ParseError = error{
72 InvalidInput,76 InvalidInput,
73 OutOfMemory,77 OutOfMemory,
74};78};
7579
76fn parse(tokens: &const ArrayList(Token), token_index: &usize) ParseError!Node {80fn parse(tokens: &const ArrayList(Token), token_index: &usize) ParseError!Node {
77 const first_token = tokens.items[*token_index];81 const first_token = tokens.items[token_index.*];
78 *token_index += 1;82 token_index.* += 1;
7983
80 const result_node = switch (first_token) {84 const result_node = switch (first_token) {
81 Token.Word => |word| Node { .Scalar = word },85 Token.Word => |word| Node{ .Scalar = word },
82 Token.OpenBrace => blk: {86 Token.OpenBrace => blk: {
83 var list = ArrayList(Node).init(global_allocator);87 var list = ArrayList(Node).init(global_allocator);
84 while (true) {88 while (true) {
85 try list.append(try parse(tokens, token_index));89 try list.append(try parse(tokens, token_index));
8690
87 const token = tokens.items[*token_index];91 const token = tokens.items[token_index.*];
88 *token_index += 1;92 token_index.* += 1;
8993
90 switch (token) {94 switch (token) {
91 Token.CloseBrace => break,95 Token.CloseBrace => break,
...@@ -93,17 +97,18 @@ fn parse(tokens: &const ArrayList(Token), token_index: &usize) ParseError!Node {...@@ -93,17 +97,18 @@ fn parse(tokens: &const ArrayList(Token), token_index: &usize) ParseError!Node {
93 else => return error.InvalidInput,97 else => return error.InvalidInput,
94 }98 }
95 }99 }
96 break :blk Node { .List = list };100 break :blk Node{ .List = list };
97 },101 },
98 else => return error.InvalidInput,102 else => return error.InvalidInput,
99 };103 };
100104
101 switch (tokens.items[*token_index]) {105 switch (tokens.items[token_index.*]) {
102 Token.Word, Token.OpenBrace => {106 Token.Word,
107 Token.OpenBrace => {
103 const pair = try global_allocator.alloc(Node, 2);108 const pair = try global_allocator.alloc(Node, 2);
104 pair[0] = result_node;109 pair[0] = result_node;
105 pair[1] = try parse(tokens, token_index);110 pair[1] = try parse(tokens, token_index);
106 return Node { .Combine = pair };111 return Node{ .Combine = pair };
107 },112 },
108 else => return result_node,113 else => return result_node,
109 }114 }
...@@ -137,13 +142,11 @@ fn expandString(input: []const u8, output: &Buffer) !void {...@@ -137,13 +142,11 @@ fn expandString(input: []const u8, output: &Buffer) !void {
137 }142 }
138}143}
139144
140const ExpandNodeError = error {145const ExpandNodeError = error{OutOfMemory};
141 OutOfMemory,
142};
143146
144fn expandNode(node: &const Node, output: &ArrayList(Buffer)) ExpandNodeError!void {147fn expandNode(node: &const Node, output: &ArrayList(Buffer)) ExpandNodeError!void {
145 assert(output.len == 0);148 assert(output.len == 0);
146 switch (*node) {149 switch (node.*) {
147 Node.Scalar => |scalar| {150 Node.Scalar => |scalar| {
148 try output.append(try Buffer.init(global_allocator, scalar));151 try output.append(try Buffer.init(global_allocator, scalar));
149 },152 },
test/tests.zig+90-100
...@@ -27,18 +27,18 @@ const TestTarget = struct {...@@ -27,18 +27,18 @@ const TestTarget = struct {
27 environ: builtin.Environ,27 environ: builtin.Environ,
28};28};
2929
30const test_targets = []TestTarget {30const test_targets = []TestTarget{
31 TestTarget {31 TestTarget{
32 .os = builtin.Os.linux,32 .os = builtin.Os.linux,
33 .arch = builtin.Arch.x86_64,33 .arch = builtin.Arch.x86_64,
34 .environ = builtin.Environ.gnu,34 .environ = builtin.Environ.gnu,
35 },35 },
36 TestTarget {36 TestTarget{
37 .os = builtin.Os.macosx,37 .os = builtin.Os.macosx,
38 .arch = builtin.Arch.x86_64,38 .arch = builtin.Arch.x86_64,
39 .environ = builtin.Environ.unknown,39 .environ = builtin.Environ.unknown,
40 },40 },
41 TestTarget {41 TestTarget{
42 .os = builtin.Os.windows,42 .os = builtin.Os.windows,
43 .arch = builtin.Arch.x86_64,43 .arch = builtin.Arch.x86_64,
44 .environ = builtin.Environ.msvc,44 .environ = builtin.Environ.msvc,
...@@ -49,7 +49,7 @@ const max_stdout_size = 1 * 1024 * 1024; // 1 MB...@@ -49,7 +49,7 @@ const max_stdout_size = 1 * 1024 * 1024; // 1 MB
4949
50pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {50pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
51 const cases = b.allocator.create(CompareOutputContext) catch unreachable;51 const cases = b.allocator.create(CompareOutputContext) catch unreachable;
52 *cases = CompareOutputContext {52 cases.* = CompareOutputContext{
53 .b = b,53 .b = b,
54 .step = b.step("test-compare-output", "Run the compare output tests"),54 .step = b.step("test-compare-output", "Run the compare output tests"),
55 .test_index = 0,55 .test_index = 0,
...@@ -63,7 +63,7 @@ pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) &build...@@ -63,7 +63,7 @@ pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) &build
6363
64pub fn addRuntimeSafetyTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {64pub fn addRuntimeSafetyTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
65 const cases = b.allocator.create(CompareOutputContext) catch unreachable;65 const cases = b.allocator.create(CompareOutputContext) catch unreachable;
66 *cases = CompareOutputContext {66 cases.* = CompareOutputContext{
67 .b = b,67 .b = b,
68 .step = b.step("test-runtime-safety", "Run the runtime safety tests"),68 .step = b.step("test-runtime-safety", "Run the runtime safety tests"),
69 .test_index = 0,69 .test_index = 0,
...@@ -77,7 +77,7 @@ pub fn addRuntimeSafetyTests(b: &build.Builder, test_filter: ?[]const u8) &build...@@ -77,7 +77,7 @@ pub fn addRuntimeSafetyTests(b: &build.Builder, test_filter: ?[]const u8) &build
7777
78pub fn addCompileErrorTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {78pub fn addCompileErrorTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
79 const cases = b.allocator.create(CompileErrorContext) catch unreachable;79 const cases = b.allocator.create(CompileErrorContext) catch unreachable;
80 *cases = CompileErrorContext {80 cases.* = CompileErrorContext{
81 .b = b,81 .b = b,
82 .step = b.step("test-compile-errors", "Run the compile error tests"),82 .step = b.step("test-compile-errors", "Run the compile error tests"),
83 .test_index = 0,83 .test_index = 0,
...@@ -91,7 +91,7 @@ pub fn addCompileErrorTests(b: &build.Builder, test_filter: ?[]const u8) &build....@@ -91,7 +91,7 @@ pub fn addCompileErrorTests(b: &build.Builder, test_filter: ?[]const u8) &build.
9191
92pub fn addBuildExampleTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {92pub fn addBuildExampleTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
93 const cases = b.allocator.create(BuildExamplesContext) catch unreachable;93 const cases = b.allocator.create(BuildExamplesContext) catch unreachable;
94 *cases = BuildExamplesContext {94 cases.* = BuildExamplesContext{
95 .b = b,95 .b = b,
96 .step = b.step("test-build-examples", "Build the examples"),96 .step = b.step("test-build-examples", "Build the examples"),
97 .test_index = 0,97 .test_index = 0,
...@@ -105,7 +105,7 @@ pub fn addBuildExampleTests(b: &build.Builder, test_filter: ?[]const u8) &build....@@ -105,7 +105,7 @@ pub fn addBuildExampleTests(b: &build.Builder, test_filter: ?[]const u8) &build.
105105
106pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {106pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
107 const cases = b.allocator.create(CompareOutputContext) catch unreachable;107 const cases = b.allocator.create(CompareOutputContext) catch unreachable;
108 *cases = CompareOutputContext {108 cases.* = CompareOutputContext{
109 .b = b,109 .b = b,
110 .step = b.step("test-asm-link", "Run the assemble and link tests"),110 .step = b.step("test-asm-link", "Run the assemble and link tests"),
111 .test_index = 0,111 .test_index = 0,
...@@ -119,7 +119,7 @@ pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) &bui...@@ -119,7 +119,7 @@ pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) &bui
119119
120pub fn addTranslateCTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {120pub fn addTranslateCTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
121 const cases = b.allocator.create(TranslateCContext) catch unreachable;121 const cases = b.allocator.create(TranslateCContext) catch unreachable;
122 *cases = TranslateCContext {122 cases.* = TranslateCContext{
123 .b = b,123 .b = b,
124 .step = b.step("test-translate-c", "Run the C transation tests"),124 .step = b.step("test-translate-c", "Run the C transation tests"),
125 .test_index = 0,125 .test_index = 0,
...@@ -133,7 +133,7 @@ pub fn addTranslateCTests(b: &build.Builder, test_filter: ?[]const u8) &build.St...@@ -133,7 +133,7 @@ pub fn addTranslateCTests(b: &build.Builder, test_filter: ?[]const u8) &build.St
133133
134pub fn addGenHTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {134pub fn addGenHTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
135 const cases = b.allocator.create(GenHContext) catch unreachable;135 const cases = b.allocator.create(GenHContext) catch unreachable;
136 *cases = GenHContext {136 cases.* = GenHContext{
137 .b = b,137 .b = b,
138 .step = b.step("test-gen-h", "Run the C header file generation tests"),138 .step = b.step("test-gen-h", "Run the C header file generation tests"),
139 .test_index = 0,139 .test_index = 0,
...@@ -145,22 +145,26 @@ pub fn addGenHTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {...@@ -145,22 +145,26 @@ pub fn addGenHTests(b: &build.Builder, test_filter: ?[]const u8) &build.Step {
145 return cases.step;145 return cases.step;
146}146}
147147
148148pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []const u8, name: []const u8, desc: []const u8, with_lldb: bool) &build.Step {
149pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []const u8,
150 name:[] const u8, desc: []const u8, with_lldb: bool) &build.Step
151{
152 const step = b.step(b.fmt("test-{}", name), desc);149 const step = b.step(b.fmt("test-{}", name), desc);
153 for (test_targets) |test_target| {150 for (test_targets) |test_target| {
154 const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch);151 const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch);
155 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {152 for ([]Mode{
156 for ([]bool{false, true}) |link_libc| {153 Mode.Debug,
154 Mode.ReleaseSafe,
155 Mode.ReleaseFast,
156 Mode.ReleaseSmall,
157 }) |mode| {
158 for ([]bool{
159 false,
160 true,
161 }) |link_libc| {
157 if (link_libc and !is_native) {162 if (link_libc and !is_native) {
158 // don't assume we have a cross-compiling libc set up163 // don't assume we have a cross-compiling libc set up
159 continue;164 continue;
160 }165 }
161 const these_tests = b.addTest(root_src);166 const these_tests = b.addTest(root_src);
162 these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os),167 these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os), @tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare"));
163 @tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare"));
164 these_tests.setFilter(test_filter);168 these_tests.setFilter(test_filter);
165 these_tests.setBuildMode(mode);169 these_tests.setBuildMode(mode);
166 if (!is_native) {170 if (!is_native) {
...@@ -171,7 +175,15 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons...@@ -171,7 +175,15 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons
171 }175 }
172 if (with_lldb) {176 if (with_lldb) {
173 these_tests.setExecCmd([]?[]const u8{177 these_tests.setExecCmd([]?[]const u8{
174 "lldb", null, "-o", "run", "-o", "bt", "-o", "exit"});178 "lldb",
179 null,
180 "-o",
181 "run",
182 "-o",
183 "bt",
184 "-o",
185 "exit",
186 });
175 }187 }
176 step.dependOn(&these_tests.step);188 step.dependOn(&these_tests.step);
177 }189 }
...@@ -206,7 +218,7 @@ pub const CompareOutputContext = struct {...@@ -206,7 +218,7 @@ pub const CompareOutputContext = struct {
206 };218 };
207219
208 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {220 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {
209 self.sources.append(SourceFile {221 self.sources.append(SourceFile{
210 .filename = filename,222 .filename = filename,
211 .source = source,223 .source = source,
212 }) catch unreachable;224 }) catch unreachable;
...@@ -226,13 +238,10 @@ pub const CompareOutputContext = struct {...@@ -226,13 +238,10 @@ pub const CompareOutputContext = struct {
226 test_index: usize,238 test_index: usize,
227 cli_args: []const []const u8,239 cli_args: []const []const u8,
228240
229 pub fn create(context: &CompareOutputContext, exe_path: []const u8,241 pub fn create(context: &CompareOutputContext, exe_path: []const u8, name: []const u8, expected_output: []const u8, cli_args: []const []const u8) &RunCompareOutputStep {
230 name: []const u8, expected_output: []const u8,
231 cli_args: []const []const u8) &RunCompareOutputStep
232 {
233 const allocator = context.b.allocator;242 const allocator = context.b.allocator;
234 const ptr = allocator.create(RunCompareOutputStep) catch unreachable;243 const ptr = allocator.create(RunCompareOutputStep) catch unreachable;
235 *ptr = RunCompareOutputStep {244 ptr.* = RunCompareOutputStep{
236 .context = context,245 .context = context,
237 .exe_path = exe_path,246 .exe_path = exe_path,
238 .name = name,247 .name = name,
...@@ -258,7 +267,7 @@ pub const CompareOutputContext = struct {...@@ -258,7 +267,7 @@ pub const CompareOutputContext = struct {
258 args.append(arg) catch unreachable;267 args.append(arg) catch unreachable;
259 }268 }
260269
261 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);270 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
262271
263 const child = os.ChildProcess.init(args.toSliceConst(), b.allocator) catch unreachable;272 const child = os.ChildProcess.init(args.toSliceConst(), b.allocator) catch unreachable;
264 defer child.deinit();273 defer child.deinit();
...@@ -295,7 +304,6 @@ pub const CompareOutputContext = struct {...@@ -295,7 +304,6 @@ pub const CompareOutputContext = struct {
295 },304 },
296 }305 }
297306
298
299 if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) {307 if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) {
300 warn(308 warn(
301 \\309 \\
...@@ -318,12 +326,10 @@ pub const CompareOutputContext = struct {...@@ -318,12 +326,10 @@ pub const CompareOutputContext = struct {
318 name: []const u8,326 name: []const u8,
319 test_index: usize,327 test_index: usize,
320328
321 pub fn create(context: &CompareOutputContext, exe_path: []const u8,329 pub fn create(context: &CompareOutputContext, exe_path: []const u8, name: []const u8) &RuntimeSafetyRunStep {
322 name: []const u8) &RuntimeSafetyRunStep
323 {
324 const allocator = context.b.allocator;330 const allocator = context.b.allocator;
325 const ptr = allocator.create(RuntimeSafetyRunStep) catch unreachable;331 const ptr = allocator.create(RuntimeSafetyRunStep) catch unreachable;
326 *ptr = RuntimeSafetyRunStep {332 ptr.* = RuntimeSafetyRunStep{
327 .context = context,333 .context = context,
328 .exe_path = exe_path,334 .exe_path = exe_path,
329 .name = name,335 .name = name,
...@@ -340,7 +346,7 @@ pub const CompareOutputContext = struct {...@@ -340,7 +346,7 @@ pub const CompareOutputContext = struct {
340346
341 const full_exe_path = b.pathFromRoot(self.exe_path);347 const full_exe_path = b.pathFromRoot(self.exe_path);
342348
343 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);349 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
344350
345 const child = os.ChildProcess.init([][]u8{full_exe_path}, b.allocator) catch unreachable;351 const child = os.ChildProcess.init([][]u8{full_exe_path}, b.allocator) catch unreachable;
346 defer child.deinit();352 defer child.deinit();
...@@ -358,19 +364,16 @@ pub const CompareOutputContext = struct {...@@ -358,19 +364,16 @@ pub const CompareOutputContext = struct {
358 switch (term) {364 switch (term) {
359 Term.Exited => |code| {365 Term.Exited => |code| {
360 if (code != expected_exit_code) {366 if (code != expected_exit_code) {
361 warn("\nProgram expected to exit with code {} " ++367 warn("\nProgram expected to exit with code {} " ++ "but exited with code {}\n", expected_exit_code, code);
362 "but exited with code {}\n", expected_exit_code, code);
363 return error.TestFailed;368 return error.TestFailed;
364 }369 }
365 },370 },
366 Term.Signal => |sig| {371 Term.Signal => |sig| {
367 warn("\nProgram expected to exit with code {} " ++372 warn("\nProgram expected to exit with code {} " ++ "but instead signaled {}\n", expected_exit_code, sig);
368 "but instead signaled {}\n", expected_exit_code, sig);
369 return error.TestFailed;373 return error.TestFailed;
370 },374 },
371 else => {375 else => {
372 warn("\nProgram expected to exit with code {}" ++376 warn("\nProgram expected to exit with code {}" ++ " but exited in an unexpected way\n", expected_exit_code);
373 " but exited in an unexpected way\n", expected_exit_code);
374 return error.TestFailed;377 return error.TestFailed;
375 },378 },
376 }379 }
...@@ -379,10 +382,8 @@ pub const CompareOutputContext = struct {...@@ -379,10 +382,8 @@ pub const CompareOutputContext = struct {
379 }382 }
380 };383 };
381384
382 pub fn createExtra(self: &CompareOutputContext, name: []const u8, source: []const u8,385 pub fn createExtra(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8, special: Special) TestCase {
383 expected_output: []const u8, special: Special) TestCase386 var tc = TestCase{
384 {
385 var tc = TestCase {
386 .name = name,387 .name = name,
387 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),388 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
388 .expected_output = expected_output,389 .expected_output = expected_output,
...@@ -395,9 +396,7 @@ pub const CompareOutputContext = struct {...@@ -395,9 +396,7 @@ pub const CompareOutputContext = struct {
395 return tc;396 return tc;
396 }397 }
397398
398 pub fn create(self: &CompareOutputContext, name: []const u8, source: []const u8,399 pub fn create(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) TestCase {
399 expected_output: []const u8) TestCase
400 {
401 return createExtra(self, name, source, expected_output, Special.None);400 return createExtra(self, name, source, expected_output, Special.None);
402 }401 }
403402
...@@ -431,8 +430,7 @@ pub const CompareOutputContext = struct {...@@ -431,8 +430,7 @@ pub const CompareOutputContext = struct {
431 Special.Asm => {430 Special.Asm => {
432 const annotated_case_name = fmt.allocPrint(self.b.allocator, "assemble-and-link {}", case.name) catch unreachable;431 const annotated_case_name = fmt.allocPrint(self.b.allocator, "assemble-and-link {}", case.name) catch unreachable;
433 if (self.test_filter) |filter| {432 if (self.test_filter) |filter| {
434 if (mem.indexOf(u8, annotated_case_name, filter) == null)433 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
435 return;
436 }434 }
437435
438 const exe = b.addExecutable("test", null);436 const exe = b.addExecutable("test", null);
...@@ -444,19 +442,21 @@ pub const CompareOutputContext = struct {...@@ -444,19 +442,21 @@ pub const CompareOutputContext = struct {
444 exe.step.dependOn(&write_src.step);442 exe.step.dependOn(&write_src.step);
445 }443 }
446444
447 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name,445 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name, case.expected_output, case.cli_args);
448 case.expected_output, case.cli_args);
449 run_and_cmp_output.step.dependOn(&exe.step);446 run_and_cmp_output.step.dependOn(&exe.step);
450447
451 self.step.dependOn(&run_and_cmp_output.step);448 self.step.dependOn(&run_and_cmp_output.step);
452 },449 },
453 Special.None => {450 Special.None => {
454 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {451 for ([]Mode{
455 const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})",452 Mode.Debug,
456 "compare-output", case.name, @tagName(mode)) catch unreachable;453 Mode.ReleaseSafe,
454 Mode.ReleaseFast,
455 Mode.ReleaseSmall,
456 }) |mode| {
457 const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", "compare-output", case.name, @tagName(mode)) catch unreachable;
457 if (self.test_filter) |filter| {458 if (self.test_filter) |filter| {
458 if (mem.indexOf(u8, annotated_case_name, filter) == null)459 if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
459 continue;
460 }460 }
461461
462 const exe = b.addExecutable("test", root_src);462 const exe = b.addExecutable("test", root_src);
...@@ -471,8 +471,7 @@ pub const CompareOutputContext = struct {...@@ -471,8 +471,7 @@ pub const CompareOutputContext = struct {
471 exe.step.dependOn(&write_src.step);471 exe.step.dependOn(&write_src.step);
472 }472 }
473473
474 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(),474 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name, case.expected_output, case.cli_args);
475 annotated_case_name, case.expected_output, case.cli_args);
476 run_and_cmp_output.step.dependOn(&exe.step);475 run_and_cmp_output.step.dependOn(&exe.step);
477476
478 self.step.dependOn(&run_and_cmp_output.step);477 self.step.dependOn(&run_and_cmp_output.step);
...@@ -481,8 +480,7 @@ pub const CompareOutputContext = struct {...@@ -481,8 +480,7 @@ pub const CompareOutputContext = struct {
481 Special.RuntimeSafety => {480 Special.RuntimeSafety => {
482 const annotated_case_name = fmt.allocPrint(self.b.allocator, "safety {}", case.name) catch unreachable;481 const annotated_case_name = fmt.allocPrint(self.b.allocator, "safety {}", case.name) catch unreachable;
483 if (self.test_filter) |filter| {482 if (self.test_filter) |filter| {
484 if (mem.indexOf(u8, annotated_case_name, filter) == null)483 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
485 return;
486 }484 }
487485
488 const exe = b.addExecutable("test", root_src);486 const exe = b.addExecutable("test", root_src);
...@@ -524,7 +522,7 @@ pub const CompileErrorContext = struct {...@@ -524,7 +522,7 @@ pub const CompileErrorContext = struct {
524 };522 };
525523
526 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {524 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {
527 self.sources.append(SourceFile {525 self.sources.append(SourceFile{
528 .filename = filename,526 .filename = filename,
529 .source = source,527 .source = source,
530 }) catch unreachable;528 }) catch unreachable;
...@@ -543,12 +541,10 @@ pub const CompileErrorContext = struct {...@@ -543,12 +541,10 @@ pub const CompileErrorContext = struct {
543 case: &const TestCase,541 case: &const TestCase,
544 build_mode: Mode,542 build_mode: Mode,
545543
546 pub fn create(context: &CompileErrorContext, name: []const u8,544 pub fn create(context: &CompileErrorContext, name: []const u8, case: &const TestCase, build_mode: Mode) &CompileCmpOutputStep {
547 case: &const TestCase, build_mode: Mode) &CompileCmpOutputStep
548 {
549 const allocator = context.b.allocator;545 const allocator = context.b.allocator;
550 const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;546 const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;
551 *ptr = CompileCmpOutputStep {547 ptr.* = CompileCmpOutputStep{
552 .step = build.Step.init("CompileCmpOutput", allocator, make),548 .step = build.Step.init("CompileCmpOutput", allocator, make),
553 .context = context,549 .context = context,
554 .name = name,550 .name = name,
...@@ -586,7 +582,7 @@ pub const CompileErrorContext = struct {...@@ -586,7 +582,7 @@ pub const CompileErrorContext = struct {
586 Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable,582 Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable,
587 }583 }
588584
589 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);585 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
590586
591 if (b.verbose) {587 if (b.verbose) {
592 printInvocation(zig_args.toSliceConst());588 printInvocation(zig_args.toSliceConst());
...@@ -626,7 +622,6 @@ pub const CompileErrorContext = struct {...@@ -626,7 +622,6 @@ pub const CompileErrorContext = struct {
626 },622 },
627 }623 }
628624
629
630 const stdout = stdout_buf.toSliceConst();625 const stdout = stdout_buf.toSliceConst();
631 const stderr = stderr_buf.toSliceConst();626 const stderr = stderr_buf.toSliceConst();
632627
...@@ -666,11 +661,9 @@ pub const CompileErrorContext = struct {...@@ -666,11 +661,9 @@ pub const CompileErrorContext = struct {
666 warn("\n");661 warn("\n");
667 }662 }
668663
669 pub fn create(self: &CompileErrorContext, name: []const u8, source: []const u8,664 pub fn create(self: &CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) &TestCase {
670 expected_lines: ...) &TestCase
671 {
672 const tc = self.b.allocator.create(TestCase) catch unreachable;665 const tc = self.b.allocator.create(TestCase) catch unreachable;
673 *tc = TestCase {666 tc.* = TestCase{
674 .name = name,667 .name = name,
675 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),668 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
676 .expected_errors = ArrayList([]const u8).init(self.b.allocator),669 .expected_errors = ArrayList([]const u8).init(self.b.allocator),
...@@ -705,12 +698,13 @@ pub const CompileErrorContext = struct {...@@ -705,12 +698,13 @@ pub const CompileErrorContext = struct {
705 pub fn addCase(self: &CompileErrorContext, case: &const TestCase) void {698 pub fn addCase(self: &CompileErrorContext, case: &const TestCase) void {
706 const b = self.b;699 const b = self.b;
707700
708 for ([]Mode{Mode.Debug, Mode.ReleaseFast}) |mode| {701 for ([]Mode{
709 const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {} ({})",702 Mode.Debug,
710 case.name, @tagName(mode)) catch unreachable;703 Mode.ReleaseFast,
704 }) |mode| {
705 const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {} ({})", case.name, @tagName(mode)) catch unreachable;
711 if (self.test_filter) |filter| {706 if (self.test_filter) |filter| {
712 if (mem.indexOf(u8, annotated_case_name, filter) == null)707 if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
713 continue;
714 }708 }
715709
716 const compile_and_cmp_errors = CompileCmpOutputStep.create(self, annotated_case_name, case, mode);710 const compile_and_cmp_errors = CompileCmpOutputStep.create(self, annotated_case_name, case, mode);
...@@ -744,8 +738,7 @@ pub const BuildExamplesContext = struct {...@@ -744,8 +738,7 @@ pub const BuildExamplesContext = struct {
744738
745 const annotated_case_name = b.fmt("build {} (Debug)", build_file);739 const annotated_case_name = b.fmt("build {} (Debug)", build_file);
746 if (self.test_filter) |filter| {740 if (self.test_filter) |filter| {
747 if (mem.indexOf(u8, annotated_case_name, filter) == null)741 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
748 return;
749 }742 }
750743
751 var zig_args = ArrayList([]const u8).init(b.allocator);744 var zig_args = ArrayList([]const u8).init(b.allocator);
...@@ -773,12 +766,15 @@ pub const BuildExamplesContext = struct {...@@ -773,12 +766,15 @@ pub const BuildExamplesContext = struct {
773 pub fn addAllArgs(self: &BuildExamplesContext, root_src: []const u8, link_libc: bool) void {766 pub fn addAllArgs(self: &BuildExamplesContext, root_src: []const u8, link_libc: bool) void {
774 const b = self.b;767 const b = self.b;
775768
776 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {769 for ([]Mode{
777 const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {} ({})",770 Mode.Debug,
778 root_src, @tagName(mode)) catch unreachable;771 Mode.ReleaseSafe,
772 Mode.ReleaseFast,
773 Mode.ReleaseSmall,
774 }) |mode| {
775 const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {} ({})", root_src, @tagName(mode)) catch unreachable;
779 if (self.test_filter) |filter| {776 if (self.test_filter) |filter| {
780 if (mem.indexOf(u8, annotated_case_name, filter) == null)777 if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
781 continue;
782 }778 }
783779
784 const exe = b.addExecutable("test", root_src);780 const exe = b.addExecutable("test", root_src);
...@@ -813,7 +809,7 @@ pub const TranslateCContext = struct {...@@ -813,7 +809,7 @@ pub const TranslateCContext = struct {
813 };809 };
814810
815 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {811 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {
816 self.sources.append(SourceFile {812 self.sources.append(SourceFile{
817 .filename = filename,813 .filename = filename,
818 .source = source,814 .source = source,
819 }) catch unreachable;815 }) catch unreachable;
...@@ -834,7 +830,7 @@ pub const TranslateCContext = struct {...@@ -834,7 +830,7 @@ pub const TranslateCContext = struct {
834 pub fn create(context: &TranslateCContext, name: []const u8, case: &const TestCase) &TranslateCCmpOutputStep {830 pub fn create(context: &TranslateCContext, name: []const u8, case: &const TestCase) &TranslateCCmpOutputStep {
835 const allocator = context.b.allocator;831 const allocator = context.b.allocator;
836 const ptr = allocator.create(TranslateCCmpOutputStep) catch unreachable;832 const ptr = allocator.create(TranslateCCmpOutputStep) catch unreachable;
837 *ptr = TranslateCCmpOutputStep {833 ptr.* = TranslateCCmpOutputStep{
838 .step = build.Step.init("ParseCCmpOutput", allocator, make),834 .step = build.Step.init("ParseCCmpOutput", allocator, make),
839 .context = context,835 .context = context,
840 .name = name,836 .name = name,
...@@ -857,7 +853,7 @@ pub const TranslateCContext = struct {...@@ -857,7 +853,7 @@ pub const TranslateCContext = struct {
857 zig_args.append("translate-c") catch unreachable;853 zig_args.append("translate-c") catch unreachable;
858 zig_args.append(b.pathFromRoot(root_src)) catch unreachable;854 zig_args.append(b.pathFromRoot(root_src)) catch unreachable;
859855
860 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);856 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
861857
862 if (b.verbose) {858 if (b.verbose) {
863 printInvocation(zig_args.toSliceConst());859 printInvocation(zig_args.toSliceConst());
...@@ -939,11 +935,9 @@ pub const TranslateCContext = struct {...@@ -939,11 +935,9 @@ pub const TranslateCContext = struct {
939 warn("\n");935 warn("\n");
940 }936 }
941937
942 pub fn create(self: &TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8,938 pub fn create(self: &TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) &TestCase {
943 source: []const u8, expected_lines: ...) &TestCase
944 {
945 const tc = self.b.allocator.create(TestCase) catch unreachable;939 const tc = self.b.allocator.create(TestCase) catch unreachable;
946 *tc = TestCase {940 tc.* = TestCase{
947 .name = name,941 .name = name,
948 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),942 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
949 .expected_lines = ArrayList([]const u8).init(self.b.allocator),943 .expected_lines = ArrayList([]const u8).init(self.b.allocator),
...@@ -977,8 +971,7 @@ pub const TranslateCContext = struct {...@@ -977,8 +971,7 @@ pub const TranslateCContext = struct {
977971
978 const annotated_case_name = fmt.allocPrint(self.b.allocator, "translate-c {}", case.name) catch unreachable;972 const annotated_case_name = fmt.allocPrint(self.b.allocator, "translate-c {}", case.name) catch unreachable;
979 if (self.test_filter) |filter| {973 if (self.test_filter) |filter| {
980 if (mem.indexOf(u8, annotated_case_name, filter) == null)974 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
981 return;
982 }975 }
983976
984 const translate_c_and_cmp = TranslateCCmpOutputStep.create(self, annotated_case_name, case);977 const translate_c_and_cmp = TranslateCCmpOutputStep.create(self, annotated_case_name, case);
...@@ -1009,7 +1002,7 @@ pub const GenHContext = struct {...@@ -1009,7 +1002,7 @@ pub const GenHContext = struct {
1009 };1002 };
10101003
1011 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {1004 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) void {
1012 self.sources.append(SourceFile {1005 self.sources.append(SourceFile{
1013 .filename = filename,1006 .filename = filename,
1014 .source = source,1007 .source = source,
1015 }) catch unreachable;1008 }) catch unreachable;
...@@ -1031,7 +1024,7 @@ pub const GenHContext = struct {...@@ -1031,7 +1024,7 @@ pub const GenHContext = struct {
1031 pub fn create(context: &GenHContext, h_path: []const u8, name: []const u8, case: &const TestCase) &GenHCmpOutputStep {1024 pub fn create(context: &GenHContext, h_path: []const u8, name: []const u8, case: &const TestCase) &GenHCmpOutputStep {
1032 const allocator = context.b.allocator;1025 const allocator = context.b.allocator;
1033 const ptr = allocator.create(GenHCmpOutputStep) catch unreachable;1026 const ptr = allocator.create(GenHCmpOutputStep) catch unreachable;
1034 *ptr = GenHCmpOutputStep {1027 ptr.* = GenHCmpOutputStep{
1035 .step = build.Step.init("ParseCCmpOutput", allocator, make),1028 .step = build.Step.init("ParseCCmpOutput", allocator, make),
1036 .context = context,1029 .context = context,
1037 .h_path = h_path,1030 .h_path = h_path,
...@@ -1047,7 +1040,7 @@ pub const GenHContext = struct {...@@ -1047,7 +1040,7 @@ pub const GenHContext = struct {
1047 const self = @fieldParentPtr(GenHCmpOutputStep, "step", step);1040 const self = @fieldParentPtr(GenHCmpOutputStep, "step", step);
1048 const b = self.context.b;1041 const b = self.context.b;
10491042
1050 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);1043 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
10511044
1052 const full_h_path = b.pathFromRoot(self.h_path);1045 const full_h_path = b.pathFromRoot(self.h_path);
1053 const actual_h = try io.readFileAlloc(b.allocator, full_h_path);1046 const actual_h = try io.readFileAlloc(b.allocator, full_h_path);
...@@ -1076,11 +1069,9 @@ pub const GenHContext = struct {...@@ -1076,11 +1069,9 @@ pub const GenHContext = struct {
1076 warn("\n");1069 warn("\n");
1077 }1070 }
10781071
1079 pub fn create(self: &GenHContext, filename: []const u8, name: []const u8,1072 pub fn create(self: &GenHContext, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) &TestCase {
1080 source: []const u8, expected_lines: ...) &TestCase
1081 {
1082 const tc = self.b.allocator.create(TestCase) catch unreachable;1073 const tc = self.b.allocator.create(TestCase) catch unreachable;
1083 *tc = TestCase {1074 tc.* = TestCase{
1084 .name = name,1075 .name = name,
1085 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),1076 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
1086 .expected_lines = ArrayList([]const u8).init(self.b.allocator),1077 .expected_lines = ArrayList([]const u8).init(self.b.allocator),
...@@ -1105,8 +1096,7 @@ pub const GenHContext = struct {...@@ -1105,8 +1096,7 @@ pub const GenHContext = struct {
1105 const mode = builtin.Mode.Debug;1096 const mode = builtin.Mode.Debug;
1106 const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", case.name, @tagName(mode)) catch unreachable;1097 const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", case.name, @tagName(mode)) catch unreachable;
1107 if (self.test_filter) |filter| {1098 if (self.test_filter) |filter| {
1108 if (mem.indexOf(u8, annotated_case_name, filter) == null)1099 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
1109 return;
1110 }1100 }
11111101
1112 const obj = b.addObject("test", root_src);1102 const obj = b.addObject("test", root_src);
test/translate_c.zig+50-50
...@@ -720,43 +720,43 @@ pub fn addCases(cases: &tests.TranslateCContext) void {...@@ -720,43 +720,43 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
720 \\ var a: c_int = 0;720 \\ var a: c_int = 0;
721 \\ a += x: {721 \\ a += x: {
722 \\ const _ref = &a;722 \\ const _ref = &a;
723 \\ (*_ref) = ((*_ref) + 1);723 \\ _ref.* = (_ref.* + 1);
724 \\ break :x *_ref;724 \\ break :x _ref.*;
725 \\ };725 \\ };
726 \\ a -= x: {726 \\ a -= x: {
727 \\ const _ref = &a;727 \\ const _ref = &a;
728 \\ (*_ref) = ((*_ref) - 1);728 \\ _ref.* = (_ref.* - 1);
729 \\ break :x *_ref;729 \\ break :x _ref.*;
730 \\ };730 \\ };
731 \\ a *= x: {731 \\ a *= x: {
732 \\ const _ref = &a;732 \\ const _ref = &a;
733 \\ (*_ref) = ((*_ref) * 1);733 \\ _ref.* = (_ref.* * 1);
734 \\ break :x *_ref;734 \\ break :x _ref.*;
735 \\ };735 \\ };
736 \\ a &= x: {736 \\ a &= x: {
737 \\ const _ref = &a;737 \\ const _ref = &a;
738 \\ (*_ref) = ((*_ref) & 1);738 \\ _ref.* = (_ref.* & 1);
739 \\ break :x *_ref;739 \\ break :x _ref.*;
740 \\ };740 \\ };
741 \\ a |= x: {741 \\ a |= x: {
742 \\ const _ref = &a;742 \\ const _ref = &a;
743 \\ (*_ref) = ((*_ref) | 1);743 \\ _ref.* = (_ref.* | 1);
744 \\ break :x *_ref;744 \\ break :x _ref.*;
745 \\ };745 \\ };
746 \\ a ^= x: {746 \\ a ^= x: {
747 \\ const _ref = &a;747 \\ const _ref = &a;
748 \\ (*_ref) = ((*_ref) ^ 1);748 \\ _ref.* = (_ref.* ^ 1);
749 \\ break :x *_ref;749 \\ break :x _ref.*;
750 \\ };750 \\ };
751 \\ a >>= @import("std").math.Log2Int(c_int)(x: {751 \\ a >>= @import("std").math.Log2Int(c_int)(x: {
752 \\ const _ref = &a;752 \\ const _ref = &a;
753 \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_int)(1));753 \\ _ref.* = (_ref.* >> @import("std").math.Log2Int(c_int)(1));
754 \\ break :x *_ref;754 \\ break :x _ref.*;
755 \\ });755 \\ });
756 \\ a <<= @import("std").math.Log2Int(c_int)(x: {756 \\ a <<= @import("std").math.Log2Int(c_int)(x: {
757 \\ const _ref = &a;757 \\ const _ref = &a;
758 \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_int)(1));758 \\ _ref.* = (_ref.* << @import("std").math.Log2Int(c_int)(1));
759 \\ break :x *_ref;759 \\ break :x _ref.*;
760 \\ });760 \\ });
761 \\}761 \\}
762 );762 );
...@@ -778,43 +778,43 @@ pub fn addCases(cases: &tests.TranslateCContext) void {...@@ -778,43 +778,43 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
778 \\ var a: c_uint = c_uint(0);778 \\ var a: c_uint = c_uint(0);
779 \\ a +%= x: {779 \\ a +%= x: {
780 \\ const _ref = &a;780 \\ const _ref = &a;
781 \\ (*_ref) = ((*_ref) +% c_uint(1));781 \\ _ref.* = (_ref.* +% c_uint(1));
782 \\ break :x *_ref;782 \\ break :x _ref.*;
783 \\ };783 \\ };
784 \\ a -%= x: {784 \\ a -%= x: {
785 \\ const _ref = &a;785 \\ const _ref = &a;
786 \\ (*_ref) = ((*_ref) -% c_uint(1));786 \\ _ref.* = (_ref.* -% c_uint(1));
787 \\ break :x *_ref;787 \\ break :x _ref.*;
788 \\ };788 \\ };
789 \\ a *%= x: {789 \\ a *%= x: {
790 \\ const _ref = &a;790 \\ const _ref = &a;
791 \\ (*_ref) = ((*_ref) *% c_uint(1));791 \\ _ref.* = (_ref.* *% c_uint(1));
792 \\ break :x *_ref;792 \\ break :x _ref.*;
793 \\ };793 \\ };
794 \\ a &= x: {794 \\ a &= x: {
795 \\ const _ref = &a;795 \\ const _ref = &a;
796 \\ (*_ref) = ((*_ref) & c_uint(1));796 \\ _ref.* = (_ref.* & c_uint(1));
797 \\ break :x *_ref;797 \\ break :x _ref.*;
798 \\ };798 \\ };
799 \\ a |= x: {799 \\ a |= x: {
800 \\ const _ref = &a;800 \\ const _ref = &a;
801 \\ (*_ref) = ((*_ref) | c_uint(1));801 \\ _ref.* = (_ref.* | c_uint(1));
802 \\ break :x *_ref;802 \\ break :x _ref.*;
803 \\ };803 \\ };
804 \\ a ^= x: {804 \\ a ^= x: {
805 \\ const _ref = &a;805 \\ const _ref = &a;
806 \\ (*_ref) = ((*_ref) ^ c_uint(1));806 \\ _ref.* = (_ref.* ^ c_uint(1));
807 \\ break :x *_ref;807 \\ break :x _ref.*;
808 \\ };808 \\ };
809 \\ a >>= @import("std").math.Log2Int(c_uint)(x: {809 \\ a >>= @import("std").math.Log2Int(c_uint)(x: {
810 \\ const _ref = &a;810 \\ const _ref = &a;
811 \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_uint)(1));811 \\ _ref.* = (_ref.* >> @import("std").math.Log2Int(c_uint)(1));
812 \\ break :x *_ref;812 \\ break :x _ref.*;
813 \\ });813 \\ });
814 \\ a <<= @import("std").math.Log2Int(c_uint)(x: {814 \\ a <<= @import("std").math.Log2Int(c_uint)(x: {
815 \\ const _ref = &a;815 \\ const _ref = &a;
816 \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_uint)(1));816 \\ _ref.* = (_ref.* << @import("std").math.Log2Int(c_uint)(1));
817 \\ break :x *_ref;817 \\ break :x _ref.*;
818 \\ });818 \\ });
819 \\}819 \\}
820 );820 );
...@@ -853,26 +853,26 @@ pub fn addCases(cases: &tests.TranslateCContext) void {...@@ -853,26 +853,26 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
853 \\ u -%= 1;853 \\ u -%= 1;
854 \\ i = x: {854 \\ i = x: {
855 \\ const _ref = &i;855 \\ const _ref = &i;
856 \\ const _tmp = *_ref;856 \\ const _tmp = _ref.*;
857 \\ (*_ref) += 1;857 \\ _ref.* += 1;
858 \\ break :x _tmp;858 \\ break :x _tmp;
859 \\ };859 \\ };
860 \\ i = x: {860 \\ i = x: {
861 \\ const _ref = &i;861 \\ const _ref = &i;
862 \\ const _tmp = *_ref;862 \\ const _tmp = _ref.*;
863 \\ (*_ref) -= 1;863 \\ _ref.* -= 1;
864 \\ break :x _tmp;864 \\ break :x _tmp;
865 \\ };865 \\ };
866 \\ u = x: {866 \\ u = x: {
867 \\ const _ref = &u;867 \\ const _ref = &u;
868 \\ const _tmp = *_ref;868 \\ const _tmp = _ref.*;
869 \\ (*_ref) +%= 1;869 \\ _ref.* +%= 1;
870 \\ break :x _tmp;870 \\ break :x _tmp;
871 \\ };871 \\ };
872 \\ u = x: {872 \\ u = x: {
873 \\ const _ref = &u;873 \\ const _ref = &u;
874 \\ const _tmp = *_ref;874 \\ const _tmp = _ref.*;
875 \\ (*_ref) -%= 1;875 \\ _ref.* -%= 1;
876 \\ break :x _tmp;876 \\ break :x _tmp;
877 \\ };877 \\ };
878 \\}878 \\}
...@@ -901,23 +901,23 @@ pub fn addCases(cases: &tests.TranslateCContext) void {...@@ -901,23 +901,23 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
901 \\ u -%= 1;901 \\ u -%= 1;
902 \\ i = x: {902 \\ i = x: {
903 \\ const _ref = &i;903 \\ const _ref = &i;
904 \\ (*_ref) += 1;904 \\ _ref.* += 1;
905 \\ break :x *_ref;905 \\ break :x _ref.*;
906 \\ };906 \\ };
907 \\ i = x: {907 \\ i = x: {
908 \\ const _ref = &i;908 \\ const _ref = &i;
909 \\ (*_ref) -= 1;909 \\ _ref.* -= 1;
910 \\ break :x *_ref;910 \\ break :x _ref.*;
911 \\ };911 \\ };
912 \\ u = x: {912 \\ u = x: {
913 \\ const _ref = &u;913 \\ const _ref = &u;
914 \\ (*_ref) +%= 1;914 \\ _ref.* +%= 1;
915 \\ break :x *_ref;915 \\ break :x _ref.*;
916 \\ };916 \\ };
917 \\ u = x: {917 \\ u = x: {
918 \\ const _ref = &u;918 \\ const _ref = &u;
919 \\ (*_ref) -%= 1;919 \\ _ref.* -%= 1;
920 \\ break :x *_ref;920 \\ break :x _ref.*;
921 \\ };921 \\ };
922 \\}922 \\}
923 );923 );
...@@ -985,7 +985,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {...@@ -985,7 +985,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
985 \\}985 \\}
986 ,986 ,
987 \\pub export fn foo(x: ?&c_int) void {987 \\pub export fn foo(x: ?&c_int) void {
988 \\ (*??x) = 1;988 \\ (??x).* = 1;
989 \\}989 \\}
990 );990 );
991991
...@@ -1013,7 +1013,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {...@@ -1013,7 +1013,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
1013 \\pub fn foo() c_int {1013 \\pub fn foo() c_int {
1014 \\ var x: c_int = 1234;1014 \\ var x: c_int = 1234;
1015 \\ var ptr: ?&c_int = &x;1015 \\ var ptr: ?&c_int = &x;
1016 \\ return *??ptr;1016 \\ return (??ptr).*;
1017 \\}1017 \\}
1018 );1018 );
10191019