authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-22 23:22:17-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-22 23:22:17-04:00
log6938245fcc1daa6a63bcfcb3ba1092d569efc875
tree035b27a399c418cab679043f87282dc3de1ef5b1
parent7b68385d7d4448e81cc882d9a5464bf58d10dc0d
parent78c6d39cd49225bdfd2de4da7b1730ba26a41ba4

Merge remote-tracking branch 'origin/master' into zig-ast-to-zir


47 files changed, 1631 insertions(+), 647 deletions(-)

CMakeLists.txt+1
...@@ -288,6 +288,7 @@ set(ZIG_SOURCES...@@ -288,6 +288,7 @@ set(ZIG_SOURCES
288 "${CMAKE_SOURCE_DIR}/src/target.cpp"288 "${CMAKE_SOURCE_DIR}/src/target.cpp"
289 "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"289 "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
290 "${CMAKE_SOURCE_DIR}/src/util.cpp"290 "${CMAKE_SOURCE_DIR}/src/util.cpp"
291 "${CMAKE_SOURCE_DIR}/src/softfloat_ext.cpp"
291 "${ZIG_SOURCES_MEM_PROFILE}"292 "${ZIG_SOURCES_MEM_PROFILE}"
292)293)
293set(OPTIMIZED_C_SOURCES294set(OPTIMIZED_C_SOURCES
build.zig+4-1
...@@ -139,7 +139,10 @@ pub fn build(b: *Builder) !void {...@@ -139,7 +139,10 @@ pub fn build(b: *Builder) !void {
139 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));139 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
140 test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));140 test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));
141 test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));141 test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
142 test_step.dependOn(tests.addCliTests(b, test_filter, modes));142 const test_cli = tests.addCliTests(b, test_filter, modes);
143 const test_cli_step = b.step("test-cli", "Run zig cli tests");
144 test_cli_step.dependOn(test_cli);
145 test_step.dependOn(test_cli);
143 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));146 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
144 test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));147 test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
145 test_step.dependOn(tests.addTranslateCTests(b, test_filter));148 test_step.dependOn(tests.addTranslateCTests(b, test_filter));
doc/langref.html.in+79-80
...@@ -236,19 +236,18 @@ pub fn main() !void {...@@ -236,19 +236,18 @@ pub fn main() !void {
236}236}
237 {#code_end#}237 {#code_end#}
238 <p>238 <p>
239 Usually you don't want to write to stdout. You want to write to stderr. And you239 Usually you don't want to write to stdout. You want to write to stderr, and you
240 don't care if it fails. It's more like a <em>warning message</em> that you want240 don't care if it fails. For that you can use a simpler API:
241 to emit. For that you can use a simpler API:
242 </p>241 </p>
243 {#code_begin|exe|hello#}242 {#code_begin|exe|hello#}
244const warn = @import("std").debug.warn;243const print = @import("std").debug.print;
245244
246pub fn main() void {245pub fn main() void {
247 warn("Hello, world!\n", .{});246 print("Hello, world!\n", .{});
248}247}
249 {#code_end#}248 {#code_end#}
250 <p>249 <p>
251 Note that you can leave off the {#syntax#}!{#endsyntax#} from the return type because {#syntax#}warn{#endsyntax#} cannot fail.250 Note that you can leave off the {#syntax#}!{#endsyntax#} from the return type because {#syntax#}print{#endsyntax#} cannot fail.
252 </p>251 </p>
253 {#see_also|Values|@import|Errors|Root Source File#}252 {#see_also|Values|@import|Errors|Root Source File#}
254 {#header_close#}253 {#header_close#}
...@@ -307,7 +306,7 @@ const Timestamp = struct {...@@ -307,7 +306,7 @@ const Timestamp = struct {
307 {#header_open|Values#}306 {#header_open|Values#}
308 {#code_begin|exe|values#}307 {#code_begin|exe|values#}
309// Top-level declarations are order-independent:308// Top-level declarations are order-independent:
310const warn = std.debug.warn;309const print = std.debug.print;
311const std = @import("std");310const std = @import("std");
312const os = std.os;311const os = std.os;
313const assert = std.debug.assert;312const assert = std.debug.assert;
...@@ -315,14 +314,14 @@ const assert = std.debug.assert;...@@ -315,14 +314,14 @@ const assert = std.debug.assert;
315pub fn main() void {314pub fn main() void {
316 // integers315 // integers
317 const one_plus_one: i32 = 1 + 1;316 const one_plus_one: i32 = 1 + 1;
318 warn("1 + 1 = {}\n", .{one_plus_one});317 print("1 + 1 = {}\n", .{one_plus_one});
319318
320 // floats319 // floats
321 const seven_div_three: f32 = 7.0 / 3.0;320 const seven_div_three: f32 = 7.0 / 3.0;
322 warn("7.0 / 3.0 = {}\n", .{seven_div_three});321 print("7.0 / 3.0 = {}\n", .{seven_div_three});
323322
324 // boolean323 // boolean
325 warn("{}\n{}\n{}\n", .{324 print("{}\n{}\n{}\n", .{
326 true and false,325 true and false,
327 true or false,326 true or false,
328 !true,327 !true,
...@@ -332,7 +331,7 @@ pub fn main() void {...@@ -332,7 +331,7 @@ pub fn main() void {
332 var optional_value: ?[]const u8 = null;331 var optional_value: ?[]const u8 = null;
333 assert(optional_value == null);332 assert(optional_value == null);
334333
335 warn("\noptional 1\ntype: {}\nvalue: {}\n", .{334 print("\noptional 1\ntype: {}\nvalue: {}\n", .{
336 @typeName(@TypeOf(optional_value)),335 @typeName(@TypeOf(optional_value)),
337 optional_value,336 optional_value,
338 });337 });
...@@ -340,7 +339,7 @@ pub fn main() void {...@@ -340,7 +339,7 @@ pub fn main() void {
340 optional_value = "hi";339 optional_value = "hi";
341 assert(optional_value != null);340 assert(optional_value != null);
342341
343 warn("\noptional 2\ntype: {}\nvalue: {}\n", .{342 print("\noptional 2\ntype: {}\nvalue: {}\n", .{
344 @typeName(@TypeOf(optional_value)),343 @typeName(@TypeOf(optional_value)),
345 optional_value,344 optional_value,
346 });345 });
...@@ -348,14 +347,14 @@ pub fn main() void {...@@ -348,14 +347,14 @@ pub fn main() void {
348 // error union347 // error union
349 var number_or_error: anyerror!i32 = error.ArgNotFound;348 var number_or_error: anyerror!i32 = error.ArgNotFound;
350349
351 warn("\nerror union 1\ntype: {}\nvalue: {}\n", .{350 print("\nerror union 1\ntype: {}\nvalue: {}\n", .{
352 @typeName(@TypeOf(number_or_error)),351 @typeName(@TypeOf(number_or_error)),
353 number_or_error,352 number_or_error,
354 });353 });
355354
356 number_or_error = 1234;355 number_or_error = 1234;
357356
358 warn("\nerror union 2\ntype: {}\nvalue: {}\n", .{357 print("\nerror union 2\ntype: {}\nvalue: {}\n", .{
359 @typeName(@TypeOf(number_or_error)),358 @typeName(@TypeOf(number_or_error)),
360 number_or_error,359 number_or_error,
361 });360 });
...@@ -994,15 +993,15 @@ export fn foo_optimized(x: f64) f64 {...@@ -994,15 +993,15 @@ export fn foo_optimized(x: f64) f64 {
994 which operates in strict mode.</p>993 which operates in strict mode.</p>
995 {#code_begin|exe|float_mode#}994 {#code_begin|exe|float_mode#}
996 {#code_link_object|foo#}995 {#code_link_object|foo#}
997const warn = @import("std").debug.warn;996const print = @import("std").debug.print;
998997
999extern fn foo_strict(x: f64) f64;998extern fn foo_strict(x: f64) f64;
1000extern fn foo_optimized(x: f64) f64;999extern fn foo_optimized(x: f64) f64;
10011000
1002pub fn main() void {1001pub fn main() void {
1003 const x = 0.001;1002 const x = 0.001;
1004 warn("optimized = {}\n", .{foo_optimized(x)});1003 print("optimized = {}\n", .{foo_optimized(x)});
1005 warn("strict = {}\n", .{foo_strict(x)});1004 print("strict = {}\n", .{foo_strict(x)});
1006}1005}
1007 {#code_end#}1006 {#code_end#}
1008 {#see_also|@setFloatMode|Division by Zero#}1007 {#see_also|@setFloatMode|Division by Zero#}
...@@ -2668,9 +2667,9 @@ const std = @import("std");...@@ -2668,9 +2667,9 @@ const std = @import("std");
26682667
2669pub fn main() void {2668pub fn main() void {
2670 const Foo = struct {};2669 const Foo = struct {};
2671 std.debug.warn("variable: {}\n", .{@typeName(Foo)});2670 std.debug.print("variable: {}\n", .{@typeName(Foo)});
2672 std.debug.warn("anonymous: {}\n", .{@typeName(struct {})});2671 std.debug.print("anonymous: {}\n", .{@typeName(struct {})});
2673 std.debug.warn("function: {}\n", .{@typeName(List(i32))});2672 std.debug.print("function: {}\n", .{@typeName(List(i32))});
2674}2673}
26752674
2676fn List(comptime T: type) type {2675fn List(comptime T: type) type {
...@@ -3869,7 +3868,7 @@ test "if error union" {...@@ -3869,7 +3868,7 @@ test "if error union" {
3869 {#code_begin|test|defer#}3868 {#code_begin|test|defer#}
3870const std = @import("std");3869const std = @import("std");
3871const assert = std.debug.assert;3870const assert = std.debug.assert;
3872const warn = std.debug.warn;3871const print = std.debug.print;
38733872
3874// defer will execute an expression at the end of the current scope.3873// defer will execute an expression at the end of the current scope.
3875fn deferExample() usize {3874fn deferExample() usize {
...@@ -3892,18 +3891,18 @@ test "defer basics" {...@@ -3892,18 +3891,18 @@ test "defer basics" {
3892// If multiple defer statements are specified, they will be executed in3891// If multiple defer statements are specified, they will be executed in
3893// the reverse order they were run.3892// the reverse order they were run.
3894fn deferUnwindExample() void {3893fn deferUnwindExample() void {
3895 warn("\n", .{});3894 print("\n", .{});
38963895
3897 defer {3896 defer {
3898 warn("1 ", .{});3897 print("1 ", .{});
3899 }3898 }
3900 defer {3899 defer {
3901 warn("2 ", .{});3900 print("2 ", .{});
3902 }3901 }
3903 if (false) {3902 if (false) {
3904 // defers are not run if they are never executed.3903 // defers are not run if they are never executed.
3905 defer {3904 defer {
3906 warn("3 ", .{});3905 print("3 ", .{});
3907 }3906 }
3908 }3907 }
3909}3908}
...@@ -3918,15 +3917,15 @@ test "defer unwinding" {...@@ -3918,15 +3917,15 @@ test "defer unwinding" {
3918// This is especially useful in allowing a function to clean up properly3917// This is especially useful in allowing a function to clean up properly
3919// on error, and replaces goto error handling tactics as seen in c.3918// on error, and replaces goto error handling tactics as seen in c.
3920fn deferErrorExample(is_error: bool) !void {3919fn deferErrorExample(is_error: bool) !void {
3921 warn("\nstart of function\n", .{});3920 print("\nstart of function\n", .{});
39223921
3923 // This will always be executed on exit3922 // This will always be executed on exit
3924 defer {3923 defer {
3925 warn("end of function\n", .{});3924 print("end of function\n", .{});
3926 }3925 }
39273926
3928 errdefer {3927 errdefer {
3929 warn("encountered an error!\n", .{});3928 print("encountered an error!\n", .{});
3930 }3929 }
39313930
3932 if (is_error) {3931 if (is_error) {
...@@ -5925,13 +5924,13 @@ const Node = struct {...@@ -5925,13 +5924,13 @@ const Node = struct {
5925 Putting all of this together, let's see how {#syntax#}printf{#endsyntax#} works in Zig.5924 Putting all of this together, let's see how {#syntax#}printf{#endsyntax#} works in Zig.
5926 </p>5925 </p>
5927 {#code_begin|exe|printf#}5926 {#code_begin|exe|printf#}
5928const warn = @import("std").debug.warn;5927const print = @import("std").debug.print;
59295928
5930const a_number: i32 = 1234;5929const a_number: i32 = 1234;
5931const a_string = "foobar";5930const a_string = "foobar";
59325931
5933pub fn main() void {5932pub fn main() void {
5934 warn("here is a string: '{}' here is a number: {}\n", .{a_string, a_number});5933 print("here is a string: '{}' here is a number: {}\n", .{a_string, a_number});
5935}5934}
5936 {#code_end#}5935 {#code_end#}
59375936
...@@ -6045,13 +6044,13 @@ pub fn printValue(self: *OutStream, value: var) !void {...@@ -6045,13 +6044,13 @@ pub fn printValue(self: *OutStream, value: var) !void {
6045 And now, what happens if we give too many arguments to {#syntax#}printf{#endsyntax#}?6044 And now, what happens if we give too many arguments to {#syntax#}printf{#endsyntax#}?
6046 </p>6045 </p>
6047 {#code_begin|test_err|Unused arguments#}6046 {#code_begin|test_err|Unused arguments#}
6048const warn = @import("std").debug.warn;6047const print = @import("std").debug.print;
60496048
6050const a_number: i32 = 1234;6049const a_number: i32 = 1234;
6051const a_string = "foobar";6050const a_string = "foobar";
60526051
6053test "printf too many arguments" {6052test "printf too many arguments" {
6054 warn("here is a string: '{}' here is a number: {}\n", .{6053 print("here is a string: '{}' here is a number: {}\n", .{
6055 a_string,6054 a_string,
6056 a_number,6055 a_number,
6057 a_number,6056 a_number,
...@@ -6066,14 +6065,14 @@ test "printf too many arguments" {...@@ -6066,14 +6065,14 @@ test "printf too many arguments" {
6066 only that it is a compile-time known value that can be coerced to a {#syntax#}[]const u8{#endsyntax#}:6065 only that it is a compile-time known value that can be coerced to a {#syntax#}[]const u8{#endsyntax#}:
6067 </p>6066 </p>
6068 {#code_begin|exe|printf#}6067 {#code_begin|exe|printf#}
6069const warn = @import("std").debug.warn;6068const print = @import("std").debug.print;
60706069
6071const a_number: i32 = 1234;6070const a_number: i32 = 1234;
6072const a_string = "foobar";6071const a_string = "foobar";
6073const fmt = "here is a string: '{}' here is a number: {}\n";6072const fmt = "here is a string: '{}' here is a number: {}\n";
60746073
6075pub fn main() void {6074pub fn main() void {
6076 warn(fmt, .{a_string, a_number});6075 print(fmt, .{a_string, a_number});
6077}6076}
6078 {#code_end#}6077 {#code_end#}
6079 <p>6078 <p>
...@@ -6511,7 +6510,7 @@ pub fn main() void {...@@ -6511,7 +6510,7 @@ pub fn main() void {
65116510
6512fn amainWrap() void {6511fn amainWrap() void {
6513 amain() catch |e| {6512 amain() catch |e| {
6514 std.debug.warn("{}\n", .{e});6513 std.debug.print("{}\n", .{e});
6515 if (@errorReturnTrace()) |trace| {6514 if (@errorReturnTrace()) |trace| {
6516 std.debug.dumpStackTrace(trace.*);6515 std.debug.dumpStackTrace(trace.*);
6517 }6516 }
...@@ -6541,8 +6540,8 @@ fn amain() !void {...@@ -6541,8 +6540,8 @@ fn amain() !void {
6541 const download_text = try await download_frame;6540 const download_text = try await download_frame;
6542 defer allocator.free(download_text);6541 defer allocator.free(download_text);
65436542
6544 std.debug.warn("download_text: {}\n", .{download_text});6543 std.debug.print("download_text: {}\n", .{download_text});
6545 std.debug.warn("file_text: {}\n", .{file_text});6544 std.debug.print("file_text: {}\n", .{file_text});
6546}6545}
65476546
6548var global_download_frame: anyframe = undefined;6547var global_download_frame: anyframe = undefined;
...@@ -6552,7 +6551,7 @@ fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {...@@ -6552,7 +6551,7 @@ fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
6552 suspend {6551 suspend {
6553 global_download_frame = @frame();6552 global_download_frame = @frame();
6554 }6553 }
6555 std.debug.warn("fetchUrl returning\n", .{});6554 std.debug.print("fetchUrl returning\n", .{});
6556 return result;6555 return result;
6557}6556}
65586557
...@@ -6563,7 +6562,7 @@ fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {...@@ -6563,7 +6562,7 @@ fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
6563 suspend {6562 suspend {
6564 global_file_frame = @frame();6563 global_file_frame = @frame();
6565 }6564 }
6566 std.debug.warn("readFile returning\n", .{});6565 std.debug.print("readFile returning\n", .{});
6567 return result;6566 return result;
6568}6567}
6569 {#code_end#}6568 {#code_end#}
...@@ -6581,7 +6580,7 @@ pub fn main() void {...@@ -6581,7 +6580,7 @@ pub fn main() void {
65816580
6582fn amainWrap() void {6581fn amainWrap() void {
6583 amain() catch |e| {6582 amain() catch |e| {
6584 std.debug.warn("{}\n", .{e});6583 std.debug.print("{}\n", .{e});
6585 if (@errorReturnTrace()) |trace| {6584 if (@errorReturnTrace()) |trace| {
6586 std.debug.dumpStackTrace(trace.*);6585 std.debug.dumpStackTrace(trace.*);
6587 }6586 }
...@@ -6611,21 +6610,21 @@ fn amain() !void {...@@ -6611,21 +6610,21 @@ fn amain() !void {
6611 const download_text = try await download_frame;6610 const download_text = try await download_frame;
6612 defer allocator.free(download_text);6611 defer allocator.free(download_text);
66136612
6614 std.debug.warn("download_text: {}\n", .{download_text});6613 std.debug.print("download_text: {}\n", .{download_text});
6615 std.debug.warn("file_text: {}\n", .{file_text});6614 std.debug.print("file_text: {}\n", .{file_text});
6616}6615}
66176616
6618fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {6617fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
6619 const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");6618 const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");
6620 errdefer allocator.free(result);6619 errdefer allocator.free(result);
6621 std.debug.warn("fetchUrl returning\n", .{});6620 std.debug.print("fetchUrl returning\n", .{});
6622 return result;6621 return result;
6623}6622}
66246623
6625fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {6624fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
6626 const result = try std.mem.dupe(allocator, u8, "this is the file contents");6625 const result = try std.mem.dupe(allocator, u8, "this is the file contents");
6627 errdefer allocator.free(result);6626 errdefer allocator.free(result);
6628 std.debug.warn("readFile returning\n", .{});6627 std.debug.print("readFile returning\n", .{});
6629 return result;6628 return result;
6630}6629}
6631 {#code_end#}6630 {#code_end#}
...@@ -7121,7 +7120,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -7121,7 +7120,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
7121 compile-time executing code.7120 compile-time executing code.
7122 </p>7121 </p>
7123 {#code_begin|test_err|found compile log statement#}7122 {#code_begin|test_err|found compile log statement#}
7124const warn = @import("std").debug.warn;7123const print = @import("std").debug.print;
71257124
7126const num1 = blk: {7125const num1 = blk: {
7127 var val1: i32 = 99;7126 var val1: i32 = 99;
...@@ -7133,7 +7132,7 @@ const num1 = blk: {...@@ -7133,7 +7132,7 @@ const num1 = blk: {
7133test "main" {7132test "main" {
7134 @compileLog("comptime in main");7133 @compileLog("comptime in main");
71357134
7136 warn("Runtime in main, num1 = {}.\n", .{num1});7135 print("Runtime in main, num1 = {}.\n", .{num1});
7137}7136}
7138 {#code_end#}7137 {#code_end#}
7139 <p>7138 <p>
...@@ -7145,7 +7144,7 @@ test "main" {...@@ -7145,7 +7144,7 @@ test "main" {
7145 program compiles successfully and the generated executable prints:7144 program compiles successfully and the generated executable prints:
7146 </p>7145 </p>
7147 {#code_begin|test#}7146 {#code_begin|test#}
7148const warn = @import("std").debug.warn;7147const print = @import("std").debug.print;
71497148
7150const num1 = blk: {7149const num1 = blk: {
7151 var val1: i32 = 99;7150 var val1: i32 = 99;
...@@ -7154,7 +7153,7 @@ const num1 = blk: {...@@ -7154,7 +7153,7 @@ const num1 = blk: {
7154};7153};
71557154
7156test "main" {7155test "main" {
7157 warn("Runtime in main, num1 = {}.\n", .{num1});7156 print("Runtime in main, num1 = {}.\n", .{num1});
7158}7157}
7159 {#code_end#}7158 {#code_end#}
7160 {#header_close#}7159 {#header_close#}
...@@ -8205,7 +8204,7 @@ test "vector @splat" {...@@ -8205,7 +8204,7 @@ test "vector @splat" {
8205 {#header_open|@This#}8204 {#header_open|@This#}
8206 <pre>{#syntax#}@This() type{#endsyntax#}</pre>8205 <pre>{#syntax#}@This() type{#endsyntax#}</pre>
8207 <p>8206 <p>
8208 Returns the innermost struct or union that this function call is inside.8207 Returns the innermost struct, enum, or union that this function call is inside.
8209 This can be useful for an anonymous struct that needs to refer to itself:8208 This can be useful for an anonymous struct that needs to refer to itself:
8210 </p>8209 </p>
8211 {#code_begin|test#}8210 {#code_begin|test#}
...@@ -8555,7 +8554,7 @@ const std = @import("std");...@@ -8555,7 +8554,7 @@ const std = @import("std");
8555pub fn main() void {8554pub fn main() void {
8556 var value: i32 = -1;8555 var value: i32 = -1;
8557 var unsigned = @intCast(u32, value);8556 var unsigned = @intCast(u32, value);
8558 std.debug.warn("value: {}\n", .{unsigned});8557 std.debug.print("value: {}\n", .{unsigned});
8559}8558}
8560 {#code_end#}8559 {#code_end#}
8561 <p>8560 <p>
...@@ -8577,7 +8576,7 @@ const std = @import("std");...@@ -8577,7 +8576,7 @@ const std = @import("std");
8577pub fn main() void {8576pub fn main() void {
8578 var spartan_count: u16 = 300;8577 var spartan_count: u16 = 300;
8579 const byte = @intCast(u8, spartan_count);8578 const byte = @intCast(u8, spartan_count);
8580 std.debug.warn("value: {}\n", .{byte});8579 std.debug.print("value: {}\n", .{byte});
8581}8580}
8582 {#code_end#}8581 {#code_end#}
8583 <p>8582 <p>
...@@ -8611,7 +8610,7 @@ const std = @import("std");...@@ -8611,7 +8610,7 @@ const std = @import("std");
8611pub fn main() void {8610pub fn main() void {
8612 var byte: u8 = 255;8611 var byte: u8 = 255;
8613 byte += 1;8612 byte += 1;
8614 std.debug.warn("value: {}\n", .{byte});8613 std.debug.print("value: {}\n", .{byte});
8615}8614}
8616 {#code_end#}8615 {#code_end#}
8617 {#header_close#}8616 {#header_close#}
...@@ -8629,16 +8628,16 @@ pub fn main() void {...@@ -8629,16 +8628,16 @@ pub fn main() void {
8629 <p>Example of catching an overflow for addition:</p>8628 <p>Example of catching an overflow for addition:</p>
8630 {#code_begin|exe_err#}8629 {#code_begin|exe_err#}
8631const math = @import("std").math;8630const math = @import("std").math;
8632const warn = @import("std").debug.warn;8631const print = @import("std").debug.print;
8633pub fn main() !void {8632pub fn main() !void {
8634 var byte: u8 = 255;8633 var byte: u8 = 255;
86358634
8636 byte = if (math.add(u8, byte, 1)) |result| result else |err| {8635 byte = if (math.add(u8, byte, 1)) |result| result else |err| {
8637 warn("unable to add one: {}\n", .{@errorName(err)});8636 print("unable to add one: {}\n", .{@errorName(err)});
8638 return err;8637 return err;
8639 };8638 };
86408639
8641 warn("result: {}\n", .{byte});8640 print("result: {}\n", .{byte});
8642}8641}
8643 {#code_end#}8642 {#code_end#}
8644 {#header_close#}8643 {#header_close#}
...@@ -8657,15 +8656,15 @@ pub fn main() !void {...@@ -8657,15 +8656,15 @@ pub fn main() !void {
8657 Example of {#link|@addWithOverflow#}:8656 Example of {#link|@addWithOverflow#}:
8658 </p>8657 </p>
8659 {#code_begin|exe#}8658 {#code_begin|exe#}
8660const warn = @import("std").debug.warn;8659const print = @import("std").debug.print;
8661pub fn main() void {8660pub fn main() void {
8662 var byte: u8 = 255;8661 var byte: u8 = 255;
86638662
8664 var result: u8 = undefined;8663 var result: u8 = undefined;
8665 if (@addWithOverflow(u8, byte, 10, &result)) {8664 if (@addWithOverflow(u8, byte, 10, &result)) {
8666 warn("overflowed result: {}\n", .{result});8665 print("overflowed result: {}\n", .{result});
8667 } else {8666 } else {
8668 warn("result: {}\n", .{result});8667 print("result: {}\n", .{result});
8669 }8668 }
8670}8669}
8671 {#code_end#}8670 {#code_end#}
...@@ -8710,7 +8709,7 @@ const std = @import("std");...@@ -8710,7 +8709,7 @@ const std = @import("std");
8710pub fn main() void {8709pub fn main() void {
8711 var x: u8 = 0b01010101;8710 var x: u8 = 0b01010101;
8712 var y = @shlExact(x, 2);8711 var y = @shlExact(x, 2);
8713 std.debug.warn("value: {}\n", .{y});8712 std.debug.print("value: {}\n", .{y});
8714}8713}
8715 {#code_end#}8714 {#code_end#}
8716 {#header_close#}8715 {#header_close#}
...@@ -8728,7 +8727,7 @@ const std = @import("std");...@@ -8728,7 +8727,7 @@ const std = @import("std");
8728pub fn main() void {8727pub fn main() void {
8729 var x: u8 = 0b10101010;8728 var x: u8 = 0b10101010;
8730 var y = @shrExact(x, 2);8729 var y = @shrExact(x, 2);
8731 std.debug.warn("value: {}\n", .{y});8730 std.debug.print("value: {}\n", .{y});
8732}8731}
8733 {#code_end#}8732 {#code_end#}
8734 {#header_close#}8733 {#header_close#}
...@@ -8749,7 +8748,7 @@ pub fn main() void {...@@ -8749,7 +8748,7 @@ pub fn main() void {
8749 var a: u32 = 1;8748 var a: u32 = 1;
8750 var b: u32 = 0;8749 var b: u32 = 0;
8751 var c = a / b;8750 var c = a / b;
8752 std.debug.warn("value: {}\n", .{c});8751 std.debug.print("value: {}\n", .{c});
8753}8752}
8754 {#code_end#}8753 {#code_end#}
8755 {#header_close#}8754 {#header_close#}
...@@ -8770,7 +8769,7 @@ pub fn main() void {...@@ -8770,7 +8769,7 @@ pub fn main() void {
8770 var a: u32 = 10;8769 var a: u32 = 10;
8771 var b: u32 = 0;8770 var b: u32 = 0;
8772 var c = a % b;8771 var c = a % b;
8773 std.debug.warn("value: {}\n", .{c});8772 std.debug.print("value: {}\n", .{c});
8774}8773}
8775 {#code_end#}8774 {#code_end#}
8776 {#header_close#}8775 {#header_close#}
...@@ -8791,7 +8790,7 @@ pub fn main() void {...@@ -8791,7 +8790,7 @@ pub fn main() void {
8791 var a: u32 = 10;8790 var a: u32 = 10;
8792 var b: u32 = 3;8791 var b: u32 = 3;
8793 var c = @divExact(a, b);8792 var c = @divExact(a, b);
8794 std.debug.warn("value: {}\n", .{c});8793 std.debug.print("value: {}\n", .{c});
8795}8794}
8796 {#code_end#}8795 {#code_end#}
8797 {#header_close#}8796 {#header_close#}
...@@ -8810,20 +8809,20 @@ const std = @import("std");...@@ -8810,20 +8809,20 @@ const std = @import("std");
8810pub fn main() void {8809pub fn main() void {
8811 var optional_number: ?i32 = null;8810 var optional_number: ?i32 = null;
8812 var number = optional_number.?;8811 var number = optional_number.?;
8813 std.debug.warn("value: {}\n", .{number});8812 std.debug.print("value: {}\n", .{number});
8814}8813}
8815 {#code_end#}8814 {#code_end#}
8816 <p>One way to avoid this crash is to test for null instead of assuming non-null, with8815 <p>One way to avoid this crash is to test for null instead of assuming non-null, with
8817 the {#syntax#}if{#endsyntax#} expression:</p>8816 the {#syntax#}if{#endsyntax#} expression:</p>
8818 {#code_begin|exe|test#}8817 {#code_begin|exe|test#}
8819const warn = @import("std").debug.warn;8818const print = @import("std").debug.print;
8820pub fn main() void {8819pub fn main() void {
8821 const optional_number: ?i32 = null;8820 const optional_number: ?i32 = null;
88228821
8823 if (optional_number) |number| {8822 if (optional_number) |number| {
8824 warn("got number: {}\n", .{number});8823 print("got number: {}\n", .{number});
8825 } else {8824 } else {
8826 warn("it's null\n", .{});8825 print("it's null\n", .{});
8827 }8826 }
8828}8827}
8829 {#code_end#}8828 {#code_end#}
...@@ -8846,7 +8845,7 @@ const std = @import("std");...@@ -8846,7 +8845,7 @@ const std = @import("std");
88468845
8847pub fn main() void {8846pub fn main() void {
8848 const number = getNumberOrFail() catch unreachable;8847 const number = getNumberOrFail() catch unreachable;
8849 std.debug.warn("value: {}\n", .{number});8848 std.debug.print("value: {}\n", .{number});
8850}8849}
88518850
8852fn getNumberOrFail() !i32 {8851fn getNumberOrFail() !i32 {
...@@ -8856,15 +8855,15 @@ fn getNumberOrFail() !i32 {...@@ -8856,15 +8855,15 @@ fn getNumberOrFail() !i32 {
8856 <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with8855 <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with
8857 the {#syntax#}if{#endsyntax#} expression:</p>8856 the {#syntax#}if{#endsyntax#} expression:</p>
8858 {#code_begin|exe#}8857 {#code_begin|exe#}
8859const warn = @import("std").debug.warn;8858const print = @import("std").debug.print;
88608859
8861pub fn main() void {8860pub fn main() void {
8862 const result = getNumberOrFail();8861 const result = getNumberOrFail();
88638862
8864 if (result) |number| {8863 if (result) |number| {
8865 warn("got number: {}\n", .{number});8864 print("got number: {}\n", .{number});
8866 } else |err| {8865 } else |err| {
8867 warn("got error: {}\n", .{@errorName(err)});8866 print("got error: {}\n", .{@errorName(err)});
8868 }8867 }
8869}8868}
88708869
...@@ -8891,7 +8890,7 @@ pub fn main() void {...@@ -8891,7 +8890,7 @@ pub fn main() void {
8891 var err = error.AnError;8890 var err = error.AnError;
8892 var number = @errorToInt(err) + 500;8891 var number = @errorToInt(err) + 500;
8893 var invalid_err = @intToError(number);8892 var invalid_err = @intToError(number);
8894 std.debug.warn("value: {}\n", .{number});8893 std.debug.print("value: {}\n", .{number});
8895}8894}
8896 {#code_end#}8895 {#code_end#}
8897 {#header_close#}8896 {#header_close#}
...@@ -8921,7 +8920,7 @@ const Foo = enum {...@@ -8921,7 +8920,7 @@ const Foo = enum {
8921pub fn main() void {8920pub fn main() void {
8922 var a: u2 = 3;8921 var a: u2 = 3;
8923 var b = @intToEnum(Foo, a);8922 var b = @intToEnum(Foo, a);
8924 std.debug.warn("value: {}\n", .{@tagName(b)});8923 std.debug.print("value: {}\n", .{@tagName(b)});
8925}8924}
8926 {#code_end#}8925 {#code_end#}
8927 {#header_close#}8926 {#header_close#}
...@@ -8958,7 +8957,7 @@ pub fn main() void {...@@ -8958,7 +8957,7 @@ pub fn main() void {
8958}8957}
8959fn foo(set1: Set1) void {8958fn foo(set1: Set1) void {
8960 const x = @errSetCast(Set2, set1);8959 const x = @errSetCast(Set2, set1);
8961 std.debug.warn("value: {}\n", .{x});8960 std.debug.print("value: {}\n", .{x});
8962}8961}
8963 {#code_end#}8962 {#code_end#}
8964 {#header_close#}8963 {#header_close#}
...@@ -9015,7 +9014,7 @@ pub fn main() void {...@@ -9015,7 +9014,7 @@ pub fn main() void {
90159014
9016fn bar(f: *Foo) void {9015fn bar(f: *Foo) void {
9017 f.float = 12.34;9016 f.float = 12.34;
9018 std.debug.warn("value: {}\n", .{f.float});9017 std.debug.print("value: {}\n", .{f.float});
9019}9018}
9020 {#code_end#}9019 {#code_end#}
9021 <p>9020 <p>
...@@ -9039,7 +9038,7 @@ pub fn main() void {...@@ -9039,7 +9038,7 @@ pub fn main() void {
90399038
9040fn bar(f: *Foo) void {9039fn bar(f: *Foo) void {
9041 f.* = Foo{ .float = 12.34 };9040 f.* = Foo{ .float = 12.34 };
9042 std.debug.warn("value: {}\n", .{f.float});9041 std.debug.print("value: {}\n", .{f.float});
9043}9042}
9044 {#code_end#}9043 {#code_end#}
9045 <p>9044 <p>
...@@ -9058,7 +9057,7 @@ pub fn main() void {...@@ -9058,7 +9057,7 @@ pub fn main() void {
9058 var f = Foo{ .int = 42 };9057 var f = Foo{ .int = 42 };
9059 f = Foo{ .float = undefined };9058 f = Foo{ .float = undefined };
9060 bar(&f);9059 bar(&f);
9061 std.debug.warn("value: {}\n", .{f.float});9060 std.debug.print("value: {}\n", .{f.float});
9062}9061}
90639062
9064fn bar(f: *Foo) void {9063fn bar(f: *Foo) void {
...@@ -9178,7 +9177,7 @@ pub fn main() !void {...@@ -9178,7 +9177,7 @@ pub fn main() !void {
9178 const allocator = &arena.allocator;9177 const allocator = &arena.allocator;
91799178
9180 const ptr = try allocator.create(i32);9179 const ptr = try allocator.create(i32);
9181 std.debug.warn("ptr={*}\n", .{ptr});9180 std.debug.print("ptr={*}\n", .{ptr});
9182}9181}
9183 {#code_end#}9182 {#code_end#}
9184 When using this kind of allocator, there is no need to free anything manually. Everything9183 When using this kind of allocator, there is no need to free anything manually. Everything
...@@ -9712,7 +9711,7 @@ pub fn main() !void {...@@ -9712,7 +9711,7 @@ pub fn main() !void {
9712 defer std.process.argsFree(std.heap.page_allocator, args);9711 defer std.process.argsFree(std.heap.page_allocator, args);
97139712
9714 for (args) |arg, i| {9713 for (args) |arg, i| {
9715 std.debug.warn("{}: {}\n", .{i, arg});9714 std.debug.print("{}: {}\n", .{i, arg});
9716 }9715 }
9717}9716}
9718 {#code_end#}9717 {#code_end#}
...@@ -9734,7 +9733,7 @@ pub fn main() !void {...@@ -9734,7 +9733,7 @@ pub fn main() !void {
9734 try preopens.populate();9733 try preopens.populate();
97359734
9736 for (preopens.asSlice()) |preopen, i| {9735 for (preopens.asSlice()) |preopen, i| {
9737 std.debug.warn("{}: {}\n", .{ i, preopen });9736 std.debug.print("{}: {}\n", .{ i, preopen });
9738 }9737 }
9739}9738}
9740 {#code_end#}9739 {#code_end#}
lib/std/array_list.zig+1-1
...@@ -162,7 +162,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -162,7 +162,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
162 mem.copy(T, self.items[oldlen..], items);162 mem.copy(T, self.items[oldlen..], items);
163 }163 }
164164
165 pub usingnamespace if (T != u8) struct { } else struct {165 pub usingnamespace if (T != u8) struct {} else struct {
166 pub const Writer = std.io.Writer(*Self, error{OutOfMemory}, appendWrite);166 pub const Writer = std.io.Writer(*Self, error{OutOfMemory}, appendWrite);
167167
168 /// Initializes a Writer which will append to the list.168 /// Initializes a Writer which will append to the list.
lib/std/build.zig+7
...@@ -2559,3 +2559,10 @@ pub const InstalledFile = struct {...@@ -2559,3 +2559,10 @@ pub const InstalledFile = struct {
2559 dir: InstallDir,2559 dir: InstallDir,
2560 path: []const u8,2560 path: []const u8,
2561};2561};
2562
2563test "" {
2564 // The only purpose of this test is to get all these untested functions
2565 // to be referenced to avoid regression so it is okay to skip some targets.
2566 if (comptime std.Target.current.cpu.arch.ptrBitWidth() == 64)
2567 std.meta.refAllDecls(@This());
2568}
lib/std/build/emit_raw.zig+4
...@@ -215,3 +215,7 @@ pub const InstallRawStep = struct {...@@ -215,3 +215,7 @@ pub const InstallRawStep = struct {
215 try emitRaw(builder.allocator, full_src_path, full_dest_path);215 try emitRaw(builder.allocator, full_src_path, full_dest_path);
216 }216 }
217};217};
218
219test "" {
220 std.meta.refAllDecls(InstallRawStep);
221}
lib/std/builtin.zig+17-10
...@@ -166,7 +166,7 @@ pub const TypeInfo = union(enum) {...@@ -166,7 +166,7 @@ pub const TypeInfo = union(enum) {
166 Fn: Fn,166 Fn: Fn,
167 BoundFn: Fn,167 BoundFn: Fn,
168 Opaque: void,168 Opaque: void,
169 Frame: void,169 Frame: Frame,
170 AnyFrame: AnyFrame,170 AnyFrame: AnyFrame,
171 Vector: Vector,171 Vector: Vector,
172 EnumLiteral: void,172 EnumLiteral: void,
...@@ -244,8 +244,8 @@ pub const TypeInfo = union(enum) {...@@ -244,8 +244,8 @@ pub const TypeInfo = union(enum) {
244 /// therefore must be kept in sync with the compiler implementation.244 /// therefore must be kept in sync with the compiler implementation.
245 pub const Struct = struct {245 pub const Struct = struct {
246 layout: ContainerLayout,246 layout: ContainerLayout,
247 fields: []StructField,247 fields: []const StructField,
248 decls: []Declaration,248 decls: []const Declaration,
249 };249 };
250250
251 /// This data structure is used by the Zig language code generation and251 /// This data structure is used by the Zig language code generation and
...@@ -265,12 +265,13 @@ pub const TypeInfo = union(enum) {...@@ -265,12 +265,13 @@ pub const TypeInfo = union(enum) {
265 /// therefore must be kept in sync with the compiler implementation.265 /// therefore must be kept in sync with the compiler implementation.
266 pub const Error = struct {266 pub const Error = struct {
267 name: []const u8,267 name: []const u8,
268 /// This field is ignored when using @Type().
268 value: comptime_int,269 value: comptime_int,
269 };270 };
270271
271 /// This data structure is used by the Zig language code generation and272 /// This data structure is used by the Zig language code generation and
272 /// therefore must be kept in sync with the compiler implementation.273 /// therefore must be kept in sync with the compiler implementation.
273 pub const ErrorSet = ?[]Error;274 pub const ErrorSet = ?[]const Error;
274275
275 /// This data structure is used by the Zig language code generation and276 /// This data structure is used by the Zig language code generation and
276 /// therefore must be kept in sync with the compiler implementation.277 /// therefore must be kept in sync with the compiler implementation.
...@@ -284,8 +285,8 @@ pub const TypeInfo = union(enum) {...@@ -284,8 +285,8 @@ pub const TypeInfo = union(enum) {
284 pub const Enum = struct {285 pub const Enum = struct {
285 layout: ContainerLayout,286 layout: ContainerLayout,
286 tag_type: type,287 tag_type: type,
287 fields: []EnumField,288 fields: []const EnumField,
288 decls: []Declaration,289 decls: []const Declaration,
289 is_exhaustive: bool,290 is_exhaustive: bool,
290 };291 };
291292
...@@ -302,8 +303,8 @@ pub const TypeInfo = union(enum) {...@@ -302,8 +303,8 @@ pub const TypeInfo = union(enum) {
302 pub const Union = struct {303 pub const Union = struct {
303 layout: ContainerLayout,304 layout: ContainerLayout,
304 tag_type: ?type,305 tag_type: ?type,
305 fields: []UnionField,306 fields: []const UnionField,
306 decls: []Declaration,307 decls: []const Declaration,
307 };308 };
308309
309 /// This data structure is used by the Zig language code generation and310 /// This data structure is used by the Zig language code generation and
...@@ -321,7 +322,13 @@ pub const TypeInfo = union(enum) {...@@ -321,7 +322,13 @@ pub const TypeInfo = union(enum) {
321 is_generic: bool,322 is_generic: bool,
322 is_var_args: bool,323 is_var_args: bool,
323 return_type: ?type,324 return_type: ?type,
324 args: []FnArg,325 args: []const FnArg,
326 };
327
328 /// This data structure is used by the Zig language code generation and
329 /// therefore must be kept in sync with the compiler implementation.
330 pub const Frame = struct {
331 function: var,
325 };332 };
326333
327 /// This data structure is used by the Zig language code generation and334 /// This data structure is used by the Zig language code generation and
...@@ -361,7 +368,7 @@ pub const TypeInfo = union(enum) {...@@ -361,7 +368,7 @@ pub const TypeInfo = union(enum) {
361 is_export: bool,368 is_export: bool,
362 lib_name: ?[]const u8,369 lib_name: ?[]const u8,
363 return_type: type,370 return_type: type,
364 arg_names: [][]const u8,371 arg_names: []const []const u8,
365372
366 /// This data structure is used by the Zig language code generation and373 /// This data structure is used by the Zig language code generation and
367 /// therefore must be kept in sync with the compiler implementation.374 /// therefore must be kept in sync with the compiler implementation.
lib/std/c.zig+1
...@@ -102,6 +102,7 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;...@@ -102,6 +102,7 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
102pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int;102pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int;
103pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int;103pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int;
104pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int;104pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int;
105pub extern "c" fn symlinkat(oldpath: [*:0]const u8, newdirfd: fd_t, newpath: [*:0]const u8) c_int;
105pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int;106pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int;
106pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int;107pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int;
107pub extern "c" fn chdir(path: [*:0]const u8) c_int;108pub extern "c" fn chdir(path: [*:0]const u8) c_int;
lib/std/c/tokenizer.zig+50-50
...@@ -278,62 +278,62 @@ pub const Token = struct {...@@ -278,62 +278,62 @@ pub const Token = struct {
278278
279 // TODO extensions279 // TODO extensions
280 pub const keywords = std.ComptimeStringMap(Id, .{280 pub const keywords = std.ComptimeStringMap(Id, .{
281 .{"auto", .Keyword_auto},281 .{ "auto", .Keyword_auto },
282 .{"break", .Keyword_break},282 .{ "break", .Keyword_break },
283 .{"case", .Keyword_case},283 .{ "case", .Keyword_case },
284 .{"char", .Keyword_char},284 .{ "char", .Keyword_char },
285 .{"const", .Keyword_const},285 .{ "const", .Keyword_const },
286 .{"continue", .Keyword_continue},286 .{ "continue", .Keyword_continue },
287 .{"default", .Keyword_default},287 .{ "default", .Keyword_default },
288 .{"do", .Keyword_do},288 .{ "do", .Keyword_do },
289 .{"double", .Keyword_double},289 .{ "double", .Keyword_double },
290 .{"else", .Keyword_else},290 .{ "else", .Keyword_else },
291 .{"enum", .Keyword_enum},291 .{ "enum", .Keyword_enum },
292 .{"extern", .Keyword_extern},292 .{ "extern", .Keyword_extern },
293 .{"float", .Keyword_float},293 .{ "float", .Keyword_float },
294 .{"for", .Keyword_for},294 .{ "for", .Keyword_for },
295 .{"goto", .Keyword_goto},295 .{ "goto", .Keyword_goto },
296 .{"if", .Keyword_if},296 .{ "if", .Keyword_if },
297 .{"int", .Keyword_int},297 .{ "int", .Keyword_int },
298 .{"long", .Keyword_long},298 .{ "long", .Keyword_long },
299 .{"register", .Keyword_register},299 .{ "register", .Keyword_register },
300 .{"return", .Keyword_return},300 .{ "return", .Keyword_return },
301 .{"short", .Keyword_short},301 .{ "short", .Keyword_short },
302 .{"signed", .Keyword_signed},302 .{ "signed", .Keyword_signed },
303 .{"sizeof", .Keyword_sizeof},303 .{ "sizeof", .Keyword_sizeof },
304 .{"static", .Keyword_static},304 .{ "static", .Keyword_static },
305 .{"struct", .Keyword_struct},305 .{ "struct", .Keyword_struct },
306 .{"switch", .Keyword_switch},306 .{ "switch", .Keyword_switch },
307 .{"typedef", .Keyword_typedef},307 .{ "typedef", .Keyword_typedef },
308 .{"union", .Keyword_union},308 .{ "union", .Keyword_union },
309 .{"unsigned", .Keyword_unsigned},309 .{ "unsigned", .Keyword_unsigned },
310 .{"void", .Keyword_void},310 .{ "void", .Keyword_void },
311 .{"volatile", .Keyword_volatile},311 .{ "volatile", .Keyword_volatile },
312 .{"while", .Keyword_while},312 .{ "while", .Keyword_while },
313313
314 // ISO C99314 // ISO C99
315 .{"_Bool", .Keyword_bool},315 .{ "_Bool", .Keyword_bool },
316 .{"_Complex", .Keyword_complex},316 .{ "_Complex", .Keyword_complex },
317 .{"_Imaginary", .Keyword_imaginary},317 .{ "_Imaginary", .Keyword_imaginary },
318 .{"inline", .Keyword_inline},318 .{ "inline", .Keyword_inline },
319 .{"restrict", .Keyword_restrict},319 .{ "restrict", .Keyword_restrict },
320320
321 // ISO C11321 // ISO C11
322 .{"_Alignas", .Keyword_alignas},322 .{ "_Alignas", .Keyword_alignas },
323 .{"_Alignof", .Keyword_alignof},323 .{ "_Alignof", .Keyword_alignof },
324 .{"_Atomic", .Keyword_atomic},324 .{ "_Atomic", .Keyword_atomic },
325 .{"_Generic", .Keyword_generic},325 .{ "_Generic", .Keyword_generic },
326 .{"_Noreturn", .Keyword_noreturn},326 .{ "_Noreturn", .Keyword_noreturn },
327 .{"_Static_assert", .Keyword_static_assert},327 .{ "_Static_assert", .Keyword_static_assert },
328 .{"_Thread_local", .Keyword_thread_local},328 .{ "_Thread_local", .Keyword_thread_local },
329329
330 // Preprocessor directives330 // Preprocessor directives
331 .{"include", .Keyword_include},331 .{ "include", .Keyword_include },
332 .{"define", .Keyword_define},332 .{ "define", .Keyword_define },
333 .{"ifdef", .Keyword_ifdef},333 .{ "ifdef", .Keyword_ifdef },
334 .{"ifndef", .Keyword_ifndef},334 .{ "ifndef", .Keyword_ifndef },
335 .{"error", .Keyword_error},335 .{ "error", .Keyword_error },
336 .{"pragma", .Keyword_pragma},336 .{ "pragma", .Keyword_pragma },
337 });337 });
338338
339 // TODO do this in the preprocessor339 // TODO do this in the preprocessor
lib/std/debug.zig+7-3
...@@ -52,9 +52,13 @@ pub const LineInfo = struct {...@@ -52,9 +52,13 @@ pub const LineInfo = struct {
5252
53var stderr_mutex = std.Mutex.init();53var stderr_mutex = std.Mutex.init();
5454
55/// Tries to write to stderr, unbuffered, and ignores any error returned.55/// Deprecated. Use `std.log` functions for logging or `std.debug.print` for
56/// Does not append a newline.56/// "printf debugging".
57pub fn warn(comptime fmt: []const u8, args: var) void {57pub const warn = print;
58
59/// Print to stderr, unbuffered, and silently returning on failure. Intended
60/// for use in "printf debugging." Use `std.log` functions for proper logging.
61pub fn print(comptime fmt: []const u8, args: var) void {
58 const held = stderr_mutex.acquire();62 const held = stderr_mutex.acquire();
59 defer held.release();63 defer held.release();
60 const stderr = io.getStdErr().writer();64 const stderr = io.getStdErr().writer();
lib/std/fmt.zig+175-175
...@@ -69,14 +69,14 @@ fn peekIsAlign(comptime fmt: []const u8) bool {...@@ -69,14 +69,14 @@ fn peekIsAlign(comptime fmt: []const u8) bool {
69///69///
70/// If a formatted user type contains a function of the type70/// If a formatted user type contains a function of the type
71/// ```71/// ```
72/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void72/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: var) !void
73/// ```73/// ```
74/// with `?` being the type formatted, this function will be called instead of the default implementation.74/// with `?` being the type formatted, this function will be called instead of the default implementation.
75/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.75/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
76///76///
77/// A user type may be a `struct`, `vector`, `union` or `enum` type.77/// A user type may be a `struct`, `vector`, `union` or `enum` type.
78pub fn format(78pub fn format(
79 out_stream: var,79 writer: var,
80 comptime fmt: []const u8,80 comptime fmt: []const u8,
81 args: var,81 args: var,
82) !void {82) !void {
...@@ -136,7 +136,7 @@ pub fn format(...@@ -136,7 +136,7 @@ pub fn format(
136 .Start => switch (c) {136 .Start => switch (c) {
137 '{' => {137 '{' => {
138 if (start_index < i) {138 if (start_index < i) {
139 try out_stream.writeAll(fmt[start_index..i]);139 try writer.writeAll(fmt[start_index..i]);
140 }140 }
141141
142 start_index = i;142 start_index = i;
...@@ -148,7 +148,7 @@ pub fn format(...@@ -148,7 +148,7 @@ pub fn format(
148 },148 },
149 '}' => {149 '}' => {
150 if (start_index < i) {150 if (start_index < i) {
151 try out_stream.writeAll(fmt[start_index..i]);151 try writer.writeAll(fmt[start_index..i]);
152 }152 }
153 state = .CloseBrace;153 state = .CloseBrace;
154 },154 },
...@@ -183,7 +183,7 @@ pub fn format(...@@ -183,7 +183,7 @@ pub fn format(
183 args[arg_to_print],183 args[arg_to_print],
184 fmt[0..0],184 fmt[0..0],
185 options,185 options,
186 out_stream,186 writer,
187 default_max_depth,187 default_max_depth,
188 );188 );
189189
...@@ -214,7 +214,7 @@ pub fn format(...@@ -214,7 +214,7 @@ pub fn format(
214 args[arg_to_print],214 args[arg_to_print],
215 fmt[specifier_start..i],215 fmt[specifier_start..i],
216 options,216 options,
217 out_stream,217 writer,
218 default_max_depth,218 default_max_depth,
219 );219 );
220 state = .Start;220 state = .Start;
...@@ -259,7 +259,7 @@ pub fn format(...@@ -259,7 +259,7 @@ pub fn format(
259 args[arg_to_print],259 args[arg_to_print],
260 fmt[specifier_start..specifier_end],260 fmt[specifier_start..specifier_end],
261 options,261 options,
262 out_stream,262 writer,
263 default_max_depth,263 default_max_depth,
264 );264 );
265 state = .Start;265 state = .Start;
...@@ -285,7 +285,7 @@ pub fn format(...@@ -285,7 +285,7 @@ pub fn format(
285 args[arg_to_print],285 args[arg_to_print],
286 fmt[specifier_start..specifier_end],286 fmt[specifier_start..specifier_end],
287 options,287 options,
288 out_stream,288 writer,
289 default_max_depth,289 default_max_depth,
290 );290 );
291 state = .Start;291 state = .Start;
...@@ -306,7 +306,7 @@ pub fn format(...@@ -306,7 +306,7 @@ pub fn format(
306 }306 }
307 }307 }
308 if (start_index < fmt.len) {308 if (start_index < fmt.len) {
309 try out_stream.writeAll(fmt[start_index..]);309 try writer.writeAll(fmt[start_index..]);
310 }310 }
311}311}
312312
...@@ -314,140 +314,140 @@ pub fn formatType(...@@ -314,140 +314,140 @@ pub fn formatType(
314 value: var,314 value: var,
315 comptime fmt: []const u8,315 comptime fmt: []const u8,
316 options: FormatOptions,316 options: FormatOptions,
317 out_stream: var,317 writer: var,
318 max_depth: usize,318 max_depth: usize,
319) @TypeOf(out_stream).Error!void {319) @TypeOf(writer).Error!void {
320 if (comptime std.mem.eql(u8, fmt, "*")) {320 if (comptime std.mem.eql(u8, fmt, "*")) {
321 try out_stream.writeAll(@typeName(@TypeOf(value).Child));321 try writer.writeAll(@typeName(@TypeOf(value).Child));
322 try out_stream.writeAll("@");322 try writer.writeAll("@");
323 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, out_stream);323 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
324 return;324 return;
325 }325 }
326326
327 const T = @TypeOf(value);327 const T = @TypeOf(value);
328 if (comptime std.meta.trait.hasFn("format")(T)) {328 if (comptime std.meta.trait.hasFn("format")(T)) {
329 return try value.format(fmt, options, out_stream);329 return try value.format(fmt, options, writer);
330 }330 }
331331
332 switch (@typeInfo(T)) {332 switch (@typeInfo(T)) {
333 .ComptimeInt, .Int, .ComptimeFloat, .Float => {333 .ComptimeInt, .Int, .ComptimeFloat, .Float => {
334 return formatValue(value, fmt, options, out_stream);334 return formatValue(value, fmt, options, writer);
335 },335 },
336 .Void => {336 .Void => {
337 return formatBuf("void", options, out_stream);337 return formatBuf("void", options, writer);
338 },338 },
339 .Bool => {339 .Bool => {
340 return formatBuf(if (value) "true" else "false", options, out_stream);340 return formatBuf(if (value) "true" else "false", options, writer);
341 },341 },
342 .Optional => {342 .Optional => {
343 if (value) |payload| {343 if (value) |payload| {
344 return formatType(payload, fmt, options, out_stream, max_depth);344 return formatType(payload, fmt, options, writer, max_depth);
345 } else {345 } else {
346 return formatBuf("null", options, out_stream);346 return formatBuf("null", options, writer);
347 }347 }
348 },348 },
349 .ErrorUnion => {349 .ErrorUnion => {
350 if (value) |payload| {350 if (value) |payload| {
351 return formatType(payload, fmt, options, out_stream, max_depth);351 return formatType(payload, fmt, options, writer, max_depth);
352 } else |err| {352 } else |err| {
353 return formatType(err, fmt, options, out_stream, max_depth);353 return formatType(err, fmt, options, writer, max_depth);
354 }354 }
355 },355 },
356 .ErrorSet => {356 .ErrorSet => {
357 try out_stream.writeAll("error.");357 try writer.writeAll("error.");
358 return out_stream.writeAll(@errorName(value));358 return writer.writeAll(@errorName(value));
359 },359 },
360 .Enum => |enumInfo| {360 .Enum => |enumInfo| {
361 try out_stream.writeAll(@typeName(T));361 try writer.writeAll(@typeName(T));
362 if (enumInfo.is_exhaustive) {362 if (enumInfo.is_exhaustive) {
363 try out_stream.writeAll(".");363 try writer.writeAll(".");
364 try out_stream.writeAll(@tagName(value));364 try writer.writeAll(@tagName(value));
365 return;365 return;
366 }366 }
367367
368 // Use @tagName only if value is one of known fields368 // Use @tagName only if value is one of known fields
369 inline for (enumInfo.fields) |enumField| {369 inline for (enumInfo.fields) |enumField| {
370 if (@enumToInt(value) == enumField.value) {370 if (@enumToInt(value) == enumField.value) {
371 try out_stream.writeAll(".");371 try writer.writeAll(".");
372 try out_stream.writeAll(@tagName(value));372 try writer.writeAll(@tagName(value));
373 return;373 return;
374 }374 }
375 }375 }
376376
377 try out_stream.writeAll("(");377 try writer.writeAll("(");
378 try formatType(@enumToInt(value), fmt, options, out_stream, max_depth);378 try formatType(@enumToInt(value), fmt, options, writer, max_depth);
379 try out_stream.writeAll(")");379 try writer.writeAll(")");
380 },380 },
381 .Union => {381 .Union => {
382 try out_stream.writeAll(@typeName(T));382 try writer.writeAll(@typeName(T));
383 if (max_depth == 0) {383 if (max_depth == 0) {
384 return out_stream.writeAll("{ ... }");384 return writer.writeAll("{ ... }");
385 }385 }
386 const info = @typeInfo(T).Union;386 const info = @typeInfo(T).Union;
387 if (info.tag_type) |UnionTagType| {387 if (info.tag_type) |UnionTagType| {
388 try out_stream.writeAll("{ .");388 try writer.writeAll("{ .");
389 try out_stream.writeAll(@tagName(@as(UnionTagType, value)));389 try writer.writeAll(@tagName(@as(UnionTagType, value)));
390 try out_stream.writeAll(" = ");390 try writer.writeAll(" = ");
391 inline for (info.fields) |u_field| {391 inline for (info.fields) |u_field| {
392 if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {392 if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
393 try formatType(@field(value, u_field.name), fmt, options, out_stream, max_depth - 1);393 try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1);
394 }394 }
395 }395 }
396 try out_stream.writeAll(" }");396 try writer.writeAll(" }");
397 } else {397 } else {
398 try format(out_stream, "@{x}", .{@ptrToInt(&value)});398 try format(writer, "@{x}", .{@ptrToInt(&value)});
399 }399 }
400 },400 },
401 .Struct => |StructT| {401 .Struct => |StructT| {
402 try out_stream.writeAll(@typeName(T));402 try writer.writeAll(@typeName(T));
403 if (max_depth == 0) {403 if (max_depth == 0) {
404 return out_stream.writeAll("{ ... }");404 return writer.writeAll("{ ... }");
405 }405 }
406 try out_stream.writeAll("{");406 try writer.writeAll("{");
407 inline for (StructT.fields) |f, i| {407 inline for (StructT.fields) |f, i| {
408 if (i == 0) {408 if (i == 0) {
409 try out_stream.writeAll(" .");409 try writer.writeAll(" .");
410 } else {410 } else {
411 try out_stream.writeAll(", .");411 try writer.writeAll(", .");
412 }412 }
413 try out_stream.writeAll(f.name);413 try writer.writeAll(f.name);
414 try out_stream.writeAll(" = ");414 try writer.writeAll(" = ");
415 try formatType(@field(value, f.name), fmt, options, out_stream, max_depth - 1);415 try formatType(@field(value, f.name), fmt, options, writer, max_depth - 1);
416 }416 }
417 try out_stream.writeAll(" }");417 try writer.writeAll(" }");
418 },418 },
419 .Pointer => |ptr_info| switch (ptr_info.size) {419 .Pointer => |ptr_info| switch (ptr_info.size) {
420 .One => switch (@typeInfo(ptr_info.child)) {420 .One => switch (@typeInfo(ptr_info.child)) {
421 .Array => |info| {421 .Array => |info| {
422 if (info.child == u8) {422 if (info.child == u8) {
423 return formatText(value, fmt, options, out_stream);423 return formatText(value, fmt, options, writer);
424 }424 }
425 return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });425 return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
426 },426 },
427 .Enum, .Union, .Struct => {427 .Enum, .Union, .Struct => {
428 return formatType(value.*, fmt, options, out_stream, max_depth);428 return formatType(value.*, fmt, options, writer, max_depth);
429 },429 },
430 else => return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),430 else => return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
431 },431 },
432 .Many, .C => {432 .Many, .C => {
433 if (ptr_info.sentinel) |sentinel| {433 if (ptr_info.sentinel) |sentinel| {
434 return formatType(mem.span(value), fmt, options, out_stream, max_depth);434 return formatType(mem.span(value), fmt, options, writer, max_depth);
435 }435 }
436 if (ptr_info.child == u8) {436 if (ptr_info.child == u8) {
437 if (fmt.len > 0 and fmt[0] == 's') {437 if (fmt.len > 0 and fmt[0] == 's') {
438 return formatText(mem.span(value), fmt, options, out_stream);438 return formatText(mem.span(value), fmt, options, writer);
439 }439 }
440 }440 }
441 return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });441 return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
442 },442 },
443 .Slice => {443 .Slice => {
444 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {444 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
445 return formatText(value, fmt, options, out_stream);445 return formatText(value, fmt, options, writer);
446 }446 }
447 if (ptr_info.child == u8) {447 if (ptr_info.child == u8) {
448 return formatText(value, fmt, options, out_stream);448 return formatText(value, fmt, options, writer);
449 }449 }
450 return format(out_stream, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });450 return format(writer, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
451 },451 },
452 },452 },
453 .Array => |info| {453 .Array => |info| {
...@@ -462,27 +462,27 @@ pub fn formatType(...@@ -462,27 +462,27 @@ pub fn formatType(
462 .sentinel = null,462 .sentinel = null,
463 },463 },
464 });464 });
465 return formatType(@as(Slice, &value), fmt, options, out_stream, max_depth);465 return formatType(@as(Slice, &value), fmt, options, writer, max_depth);
466 },466 },
467 .Vector => {467 .Vector => {
468 const len = @typeInfo(T).Vector.len;468 const len = @typeInfo(T).Vector.len;
469 try out_stream.writeAll("{ ");469 try writer.writeAll("{ ");
470 var i: usize = 0;470 var i: usize = 0;
471 while (i < len) : (i += 1) {471 while (i < len) : (i += 1) {
472 try formatValue(value[i], fmt, options, out_stream);472 try formatValue(value[i], fmt, options, writer);
473 if (i < len - 1) {473 if (i < len - 1) {
474 try out_stream.writeAll(", ");474 try writer.writeAll(", ");
475 }475 }
476 }476 }
477 try out_stream.writeAll(" }");477 try writer.writeAll(" }");
478 },478 },
479 .Fn => {479 .Fn => {
480 return format(out_stream, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });480 return format(writer, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
481 },481 },
482 .Type => return out_stream.writeAll(@typeName(T)),482 .Type => return writer.writeAll(@typeName(T)),
483 .EnumLiteral => {483 .EnumLiteral => {
484 const buffer = [_]u8{'.'} ++ @tagName(value);484 const buffer = [_]u8{'.'} ++ @tagName(value);
485 return formatType(buffer, fmt, options, out_stream, max_depth);485 return formatType(buffer, fmt, options, writer, max_depth);
486 },486 },
487 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),487 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
488 }488 }
...@@ -492,19 +492,19 @@ fn formatValue(...@@ -492,19 +492,19 @@ fn formatValue(
492 value: var,492 value: var,
493 comptime fmt: []const u8,493 comptime fmt: []const u8,
494 options: FormatOptions,494 options: FormatOptions,
495 out_stream: var,495 writer: var,
496) !void {496) !void {
497 if (comptime std.mem.eql(u8, fmt, "B")) {497 if (comptime std.mem.eql(u8, fmt, "B")) {
498 return formatBytes(value, options, 1000, out_stream);498 return formatBytes(value, options, 1000, writer);
499 } else if (comptime std.mem.eql(u8, fmt, "Bi")) {499 } else if (comptime std.mem.eql(u8, fmt, "Bi")) {
500 return formatBytes(value, options, 1024, out_stream);500 return formatBytes(value, options, 1024, writer);
501 }501 }
502502
503 const T = @TypeOf(value);503 const T = @TypeOf(value);
504 switch (@typeInfo(T)) {504 switch (@typeInfo(T)) {
505 .Float, .ComptimeFloat => return formatFloatValue(value, fmt, options, out_stream),505 .Float, .ComptimeFloat => return formatFloatValue(value, fmt, options, writer),
506 .Int, .ComptimeInt => return formatIntValue(value, fmt, options, out_stream),506 .Int, .ComptimeInt => return formatIntValue(value, fmt, options, writer),
507 .Bool => return formatBuf(if (value) "true" else "false", options, out_stream),507 .Bool => return formatBuf(if (value) "true" else "false", options, writer),
508 else => comptime unreachable,508 else => comptime unreachable,
509 }509 }
510}510}
...@@ -513,7 +513,7 @@ pub fn formatIntValue(...@@ -513,7 +513,7 @@ pub fn formatIntValue(
513 value: var,513 value: var,
514 comptime fmt: []const u8,514 comptime fmt: []const u8,
515 options: FormatOptions,515 options: FormatOptions,
516 out_stream: var,516 writer: var,
517) !void {517) !void {
518 comptime var radix = 10;518 comptime var radix = 10;
519 comptime var uppercase = false;519 comptime var uppercase = false;
...@@ -529,7 +529,7 @@ pub fn formatIntValue(...@@ -529,7 +529,7 @@ pub fn formatIntValue(
529 uppercase = false;529 uppercase = false;
530 } else if (comptime std.mem.eql(u8, fmt, "c")) {530 } else if (comptime std.mem.eql(u8, fmt, "c")) {
531 if (@TypeOf(int_value).bit_count <= 8) {531 if (@TypeOf(int_value).bit_count <= 8) {
532 return formatAsciiChar(@as(u8, int_value), options, out_stream);532 return formatAsciiChar(@as(u8, int_value), options, writer);
533 } else {533 } else {
534 @compileError("Cannot print integer that is larger than 8 bits as a ascii");534 @compileError("Cannot print integer that is larger than 8 bits as a ascii");
535 }535 }
...@@ -546,19 +546,19 @@ pub fn formatIntValue(...@@ -546,19 +546,19 @@ pub fn formatIntValue(
546 @compileError("Unknown format string: '" ++ fmt ++ "'");546 @compileError("Unknown format string: '" ++ fmt ++ "'");
547 }547 }
548548
549 return formatInt(int_value, radix, uppercase, options, out_stream);549 return formatInt(int_value, radix, uppercase, options, writer);
550}550}
551551
552fn formatFloatValue(552fn formatFloatValue(
553 value: var,553 value: var,
554 comptime fmt: []const u8,554 comptime fmt: []const u8,
555 options: FormatOptions,555 options: FormatOptions,
556 out_stream: var,556 writer: var,
557) !void {557) !void {
558 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {558 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
559 return formatFloatScientific(value, options, out_stream);559 return formatFloatScientific(value, options, writer);
560 } else if (comptime std.mem.eql(u8, fmt, "d")) {560 } else if (comptime std.mem.eql(u8, fmt, "d")) {
561 return formatFloatDecimal(value, options, out_stream);561 return formatFloatDecimal(value, options, writer);
562 } else {562 } else {
563 @compileError("Unknown format string: '" ++ fmt ++ "'");563 @compileError("Unknown format string: '" ++ fmt ++ "'");
564 }564 }
...@@ -568,13 +568,13 @@ pub fn formatText(...@@ -568,13 +568,13 @@ pub fn formatText(
568 bytes: []const u8,568 bytes: []const u8,
569 comptime fmt: []const u8,569 comptime fmt: []const u8,
570 options: FormatOptions,570 options: FormatOptions,
571 out_stream: var,571 writer: var,
572) !void {572) !void {
573 if (comptime std.mem.eql(u8, fmt, "s") or (fmt.len == 0)) {573 if (comptime std.mem.eql(u8, fmt, "s") or (fmt.len == 0)) {
574 return formatBuf(bytes, options, out_stream);574 return formatBuf(bytes, options, writer);
575 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {575 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
576 for (bytes) |c| {576 for (bytes) |c| {
577 try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, out_stream);577 try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, writer);
578 }578 }
579 return;579 return;
580 } else {580 } else {
...@@ -585,38 +585,38 @@ pub fn formatText(...@@ -585,38 +585,38 @@ pub fn formatText(
585pub fn formatAsciiChar(585pub fn formatAsciiChar(
586 c: u8,586 c: u8,
587 options: FormatOptions,587 options: FormatOptions,
588 out_stream: var,588 writer: var,
589) !void {589) !void {
590 return out_stream.writeAll(@as(*const [1]u8, &c));590 return writer.writeAll(@as(*const [1]u8, &c));
591}591}
592592
593pub fn formatBuf(593pub fn formatBuf(
594 buf: []const u8,594 buf: []const u8,
595 options: FormatOptions,595 options: FormatOptions,
596 out_stream: var,596 writer: var,
597) !void {597) !void {
598 const width = options.width orelse buf.len;598 const width = options.width orelse buf.len;
599 var padding = if (width > buf.len) (width - buf.len) else 0;599 var padding = if (width > buf.len) (width - buf.len) else 0;
600 const pad_byte = [1]u8{options.fill};600 const pad_byte = [1]u8{options.fill};
601 switch (options.alignment) {601 switch (options.alignment) {
602 .Left => {602 .Left => {
603 try out_stream.writeAll(buf);603 try writer.writeAll(buf);
604 while (padding > 0) : (padding -= 1) {604 while (padding > 0) : (padding -= 1) {
605 try out_stream.writeAll(&pad_byte);605 try writer.writeAll(&pad_byte);
606 }606 }
607 },607 },
608 .Center => {608 .Center => {
609 const padl = padding / 2;609 const padl = padding / 2;
610 var i: usize = 0;610 var i: usize = 0;
611 while (i < padl) : (i += 1) try out_stream.writeAll(&pad_byte);611 while (i < padl) : (i += 1) try writer.writeAll(&pad_byte);
612 try out_stream.writeAll(buf);612 try writer.writeAll(buf);
613 while (i < padding) : (i += 1) try out_stream.writeAll(&pad_byte);613 while (i < padding) : (i += 1) try writer.writeAll(&pad_byte);
614 },614 },
615 .Right => {615 .Right => {
616 while (padding > 0) : (padding -= 1) {616 while (padding > 0) : (padding -= 1) {
617 try out_stream.writeAll(&pad_byte);617 try writer.writeAll(&pad_byte);
618 }618 }
619 try out_stream.writeAll(buf);619 try writer.writeAll(buf);
620 },620 },
621 }621 }
622}622}
...@@ -627,38 +627,38 @@ pub fn formatBuf(...@@ -627,38 +627,38 @@ pub fn formatBuf(
627pub fn formatFloatScientific(627pub fn formatFloatScientific(
628 value: var,628 value: var,
629 options: FormatOptions,629 options: FormatOptions,
630 out_stream: var,630 writer: var,
631) !void {631) !void {
632 var x = @floatCast(f64, value);632 var x = @floatCast(f64, value);
633633
634 // Errol doesn't handle these special cases.634 // Errol doesn't handle these special cases.
635 if (math.signbit(x)) {635 if (math.signbit(x)) {
636 try out_stream.writeAll("-");636 try writer.writeAll("-");
637 x = -x;637 x = -x;
638 }638 }
639639
640 if (math.isNan(x)) {640 if (math.isNan(x)) {
641 return out_stream.writeAll("nan");641 return writer.writeAll("nan");
642 }642 }
643 if (math.isPositiveInf(x)) {643 if (math.isPositiveInf(x)) {
644 return out_stream.writeAll("inf");644 return writer.writeAll("inf");
645 }645 }
646 if (x == 0.0) {646 if (x == 0.0) {
647 try out_stream.writeAll("0");647 try writer.writeAll("0");
648648
649 if (options.precision) |precision| {649 if (options.precision) |precision| {
650 if (precision != 0) {650 if (precision != 0) {
651 try out_stream.writeAll(".");651 try writer.writeAll(".");
652 var i: usize = 0;652 var i: usize = 0;
653 while (i < precision) : (i += 1) {653 while (i < precision) : (i += 1) {
654 try out_stream.writeAll("0");654 try writer.writeAll("0");
655 }655 }
656 }656 }
657 } else {657 } else {
658 try out_stream.writeAll(".0");658 try writer.writeAll(".0");
659 }659 }
660660
661 try out_stream.writeAll("e+00");661 try writer.writeAll("e+00");
662 return;662 return;
663 }663 }
664664
...@@ -668,50 +668,50 @@ pub fn formatFloatScientific(...@@ -668,50 +668,50 @@ pub fn formatFloatScientific(
668 if (options.precision) |precision| {668 if (options.precision) |precision| {
669 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);669 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
670670
671 try out_stream.writeAll(float_decimal.digits[0..1]);671 try writer.writeAll(float_decimal.digits[0..1]);
672672
673 // {e0} case prints no `.`673 // {e0} case prints no `.`
674 if (precision != 0) {674 if (precision != 0) {
675 try out_stream.writeAll(".");675 try writer.writeAll(".");
676676
677 var printed: usize = 0;677 var printed: usize = 0;
678 if (float_decimal.digits.len > 1) {678 if (float_decimal.digits.len > 1) {
679 const num_digits = math.min(float_decimal.digits.len, precision + 1);679 const num_digits = math.min(float_decimal.digits.len, precision + 1);
680 try out_stream.writeAll(float_decimal.digits[1..num_digits]);680 try writer.writeAll(float_decimal.digits[1..num_digits]);
681 printed += num_digits - 1;681 printed += num_digits - 1;
682 }682 }
683683
684 while (printed < precision) : (printed += 1) {684 while (printed < precision) : (printed += 1) {
685 try out_stream.writeAll("0");685 try writer.writeAll("0");
686 }686 }
687 }687 }
688 } else {688 } else {
689 try out_stream.writeAll(float_decimal.digits[0..1]);689 try writer.writeAll(float_decimal.digits[0..1]);
690 try out_stream.writeAll(".");690 try writer.writeAll(".");
691 if (float_decimal.digits.len > 1) {691 if (float_decimal.digits.len > 1) {
692 const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len;692 const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len;
693693
694 try out_stream.writeAll(float_decimal.digits[1..num_digits]);694 try writer.writeAll(float_decimal.digits[1..num_digits]);
695 } else {695 } else {
696 try out_stream.writeAll("0");696 try writer.writeAll("0");
697 }697 }
698 }698 }
699699
700 try out_stream.writeAll("e");700 try writer.writeAll("e");
701 const exp = float_decimal.exp - 1;701 const exp = float_decimal.exp - 1;
702702
703 if (exp >= 0) {703 if (exp >= 0) {
704 try out_stream.writeAll("+");704 try writer.writeAll("+");
705 if (exp > -10 and exp < 10) {705 if (exp > -10 and exp < 10) {
706 try out_stream.writeAll("0");706 try writer.writeAll("0");
707 }707 }
708 try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, out_stream);708 try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, writer);
709 } else {709 } else {
710 try out_stream.writeAll("-");710 try writer.writeAll("-");
711 if (exp > -10 and exp < 10) {711 if (exp > -10 and exp < 10) {
712 try out_stream.writeAll("0");712 try writer.writeAll("0");
713 }713 }
714 try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, out_stream);714 try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, writer);
715 }715 }
716}716}
717717
...@@ -720,34 +720,34 @@ pub fn formatFloatScientific(...@@ -720,34 +720,34 @@ pub fn formatFloatScientific(
720pub fn formatFloatDecimal(720pub fn formatFloatDecimal(
721 value: var,721 value: var,
722 options: FormatOptions,722 options: FormatOptions,
723 out_stream: var,723 writer: var,
724) !void {724) !void {
725 var x = @as(f64, value);725 var x = @as(f64, value);
726726
727 // Errol doesn't handle these special cases.727 // Errol doesn't handle these special cases.
728 if (math.signbit(x)) {728 if (math.signbit(x)) {
729 try out_stream.writeAll("-");729 try writer.writeAll("-");
730 x = -x;730 x = -x;
731 }731 }
732732
733 if (math.isNan(x)) {733 if (math.isNan(x)) {
734 return out_stream.writeAll("nan");734 return writer.writeAll("nan");
735 }735 }
736 if (math.isPositiveInf(x)) {736 if (math.isPositiveInf(x)) {
737 return out_stream.writeAll("inf");737 return writer.writeAll("inf");
738 }738 }
739 if (x == 0.0) {739 if (x == 0.0) {
740 try out_stream.writeAll("0");740 try writer.writeAll("0");
741741
742 if (options.precision) |precision| {742 if (options.precision) |precision| {
743 if (precision != 0) {743 if (precision != 0) {
744 try out_stream.writeAll(".");744 try writer.writeAll(".");
745 var i: usize = 0;745 var i: usize = 0;
746 while (i < precision) : (i += 1) {746 while (i < precision) : (i += 1) {
747 try out_stream.writeAll("0");747 try writer.writeAll("0");
748 }748 }
749 } else {749 } else {
750 try out_stream.writeAll(".0");750 try writer.writeAll(".0");
751 }751 }
752 }752 }
753753
...@@ -769,14 +769,14 @@ pub fn formatFloatDecimal(...@@ -769,14 +769,14 @@ pub fn formatFloatDecimal(
769769
770 if (num_digits_whole > 0) {770 if (num_digits_whole > 0) {
771 // We may have to zero pad, for instance 1e4 requires zero padding.771 // We may have to zero pad, for instance 1e4 requires zero padding.
772 try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);772 try writer.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
773773
774 var i = num_digits_whole_no_pad;774 var i = num_digits_whole_no_pad;
775 while (i < num_digits_whole) : (i += 1) {775 while (i < num_digits_whole) : (i += 1) {
776 try out_stream.writeAll("0");776 try writer.writeAll("0");
777 }777 }
778 } else {778 } else {
779 try out_stream.writeAll("0");779 try writer.writeAll("0");
780 }780 }
781781
782 // {.0} special case doesn't want a trailing '.'782 // {.0} special case doesn't want a trailing '.'
...@@ -784,7 +784,7 @@ pub fn formatFloatDecimal(...@@ -784,7 +784,7 @@ pub fn formatFloatDecimal(
784 return;784 return;
785 }785 }
786786
787 try out_stream.writeAll(".");787 try writer.writeAll(".");
788788
789 // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.789 // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
790 var printed: usize = 0;790 var printed: usize = 0;
...@@ -796,7 +796,7 @@ pub fn formatFloatDecimal(...@@ -796,7 +796,7 @@ pub fn formatFloatDecimal(
796796
797 var i: usize = 0;797 var i: usize = 0;
798 while (i < zeros_to_print) : (i += 1) {798 while (i < zeros_to_print) : (i += 1) {
799 try out_stream.writeAll("0");799 try writer.writeAll("0");
800 printed += 1;800 printed += 1;
801 }801 }
802802
...@@ -808,14 +808,14 @@ pub fn formatFloatDecimal(...@@ -808,14 +808,14 @@ pub fn formatFloatDecimal(
808 // Remaining fractional portion, zero-padding if insufficient.808 // Remaining fractional portion, zero-padding if insufficient.
809 assert(precision >= printed);809 assert(precision >= printed);
810 if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {810 if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
811 try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);811 try writer.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
812 return;812 return;
813 } else {813 } else {
814 try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);814 try writer.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
815 printed += float_decimal.digits.len - num_digits_whole_no_pad;815 printed += float_decimal.digits.len - num_digits_whole_no_pad;
816816
817 while (printed < precision) : (printed += 1) {817 while (printed < precision) : (printed += 1) {
818 try out_stream.writeAll("0");818 try writer.writeAll("0");
819 }819 }
820 }820 }
821 } else {821 } else {
...@@ -827,14 +827,14 @@ pub fn formatFloatDecimal(...@@ -827,14 +827,14 @@ pub fn formatFloatDecimal(
827827
828 if (num_digits_whole > 0) {828 if (num_digits_whole > 0) {
829 // We may have to zero pad, for instance 1e4 requires zero padding.829 // We may have to zero pad, for instance 1e4 requires zero padding.
830 try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);830 try writer.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
831831
832 var i = num_digits_whole_no_pad;832 var i = num_digits_whole_no_pad;
833 while (i < num_digits_whole) : (i += 1) {833 while (i < num_digits_whole) : (i += 1) {
834 try out_stream.writeAll("0");834 try writer.writeAll("0");
835 }835 }
836 } else {836 } else {
837 try out_stream.writeAll("0");837 try writer.writeAll("0");
838 }838 }
839839
840 // Omit `.` if no fractional portion840 // Omit `.` if no fractional portion
...@@ -842,7 +842,7 @@ pub fn formatFloatDecimal(...@@ -842,7 +842,7 @@ pub fn formatFloatDecimal(
842 return;842 return;
843 }843 }
844844
845 try out_stream.writeAll(".");845 try writer.writeAll(".");
846846
847 // Zero-fill until we reach significant digits or run out of precision.847 // Zero-fill until we reach significant digits or run out of precision.
848 if (float_decimal.exp < 0) {848 if (float_decimal.exp < 0) {
...@@ -850,11 +850,11 @@ pub fn formatFloatDecimal(...@@ -850,11 +850,11 @@ pub fn formatFloatDecimal(
850850
851 var i: usize = 0;851 var i: usize = 0;
852 while (i < zero_digit_count) : (i += 1) {852 while (i < zero_digit_count) : (i += 1) {
853 try out_stream.writeAll("0");853 try writer.writeAll("0");
854 }854 }
855 }855 }
856856
857 try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);857 try writer.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
858 }858 }
859}859}
860860
...@@ -862,10 +862,10 @@ pub fn formatBytes(...@@ -862,10 +862,10 @@ pub fn formatBytes(
862 value: var,862 value: var,
863 options: FormatOptions,863 options: FormatOptions,
864 comptime radix: usize,864 comptime radix: usize,
865 out_stream: var,865 writer: var,
866) !void {866) !void {
867 if (value == 0) {867 if (value == 0) {
868 return out_stream.writeAll("0B");868 return writer.writeAll("0B");
869 }869 }
870870
871 const is_float = comptime std.meta.trait.is(.Float)(@TypeOf(value));871 const is_float = comptime std.meta.trait.is(.Float)(@TypeOf(value));
...@@ -885,10 +885,10 @@ pub fn formatBytes(...@@ -885,10 +885,10 @@ pub fn formatBytes(
885 else => unreachable,885 else => unreachable,
886 };886 };
887887
888 try formatFloatDecimal(new_value, options, out_stream);888 try formatFloatDecimal(new_value, options, writer);
889889
890 if (suffix == ' ') {890 if (suffix == ' ') {
891 return out_stream.writeAll("B");891 return writer.writeAll("B");
892 }892 }
893893
894 const buf = switch (radix) {894 const buf = switch (radix) {
...@@ -896,7 +896,7 @@ pub fn formatBytes(...@@ -896,7 +896,7 @@ pub fn formatBytes(
896 1024 => &[_]u8{ suffix, 'i', 'B' },896 1024 => &[_]u8{ suffix, 'i', 'B' },
897 else => unreachable,897 else => unreachable,
898 };898 };
899 return out_stream.writeAll(buf);899 return writer.writeAll(buf);
900}900}
901901
902pub fn formatInt(902pub fn formatInt(
...@@ -904,7 +904,7 @@ pub fn formatInt(...@@ -904,7 +904,7 @@ pub fn formatInt(
904 base: u8,904 base: u8,
905 uppercase: bool,905 uppercase: bool,
906 options: FormatOptions,906 options: FormatOptions,
907 out_stream: var,907 writer: var,
908) !void {908) !void {
909 const int_value = if (@TypeOf(value) == comptime_int) blk: {909 const int_value = if (@TypeOf(value) == comptime_int) blk: {
910 const Int = math.IntFittingRange(value, value);910 const Int = math.IntFittingRange(value, value);
...@@ -913,9 +913,9 @@ pub fn formatInt(...@@ -913,9 +913,9 @@ pub fn formatInt(
913 value;913 value;
914914
915 if (@TypeOf(int_value).is_signed) {915 if (@TypeOf(int_value).is_signed) {
916 return formatIntSigned(int_value, base, uppercase, options, out_stream);916 return formatIntSigned(int_value, base, uppercase, options, writer);
917 } else {917 } else {
918 return formatIntUnsigned(int_value, base, uppercase, options, out_stream);918 return formatIntUnsigned(int_value, base, uppercase, options, writer);
919 }919 }
920}920}
921921
...@@ -924,7 +924,7 @@ fn formatIntSigned(...@@ -924,7 +924,7 @@ fn formatIntSigned(
924 base: u8,924 base: u8,
925 uppercase: bool,925 uppercase: bool,
926 options: FormatOptions,926 options: FormatOptions,
927 out_stream: var,927 writer: var,
928) !void {928) !void {
929 const new_options = FormatOptions{929 const new_options = FormatOptions{
930 .width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,930 .width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
...@@ -934,15 +934,15 @@ fn formatIntSigned(...@@ -934,15 +934,15 @@ fn formatIntSigned(
934 const bit_count = @typeInfo(@TypeOf(value)).Int.bits;934 const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
935 const Uint = std.meta.Int(false, bit_count);935 const Uint = std.meta.Int(false, bit_count);
936 if (value < 0) {936 if (value < 0) {
937 try out_stream.writeAll("-");937 try writer.writeAll("-");
938 const new_value = math.absCast(value);938 const new_value = math.absCast(value);
939 return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);939 return formatIntUnsigned(new_value, base, uppercase, new_options, writer);
940 } else if (options.width == null or options.width.? == 0) {940 } else if (options.width == null or options.width.? == 0) {
941 return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, out_stream);941 return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, writer);
942 } else {942 } else {
943 try out_stream.writeAll("+");943 try writer.writeAll("+");
944 const new_value = @intCast(Uint, value);944 const new_value = @intCast(Uint, value);
945 return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);945 return formatIntUnsigned(new_value, base, uppercase, new_options, writer);
946 }946 }
947}947}
948948
...@@ -951,7 +951,7 @@ fn formatIntUnsigned(...@@ -951,7 +951,7 @@ fn formatIntUnsigned(
951 base: u8,951 base: u8,
952 uppercase: bool,952 uppercase: bool,
953 options: FormatOptions,953 options: FormatOptions,
954 out_stream: var,954 writer: var,
955) !void {955) !void {
956 assert(base >= 2);956 assert(base >= 2);
957 var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;957 var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;
...@@ -976,22 +976,22 @@ fn formatIntUnsigned(...@@ -976,22 +976,22 @@ fn formatIntUnsigned(
976 const zero_byte: u8 = options.fill;976 const zero_byte: u8 = options.fill;
977 var leftover_padding = padding - index;977 var leftover_padding = padding - index;
978 while (true) {978 while (true) {
979 try out_stream.writeAll(@as(*const [1]u8, &zero_byte)[0..]);979 try writer.writeAll(@as(*const [1]u8, &zero_byte)[0..]);
980 leftover_padding -= 1;980 leftover_padding -= 1;
981 if (leftover_padding == 0) break;981 if (leftover_padding == 0) break;
982 }982 }
983 mem.set(u8, buf[0..index], options.fill);983 mem.set(u8, buf[0..index], options.fill);
984 return out_stream.writeAll(&buf);984 return writer.writeAll(&buf);
985 } else {985 } else {
986 const padded_buf = buf[index - padding ..];986 const padded_buf = buf[index - padding ..];
987 mem.set(u8, padded_buf[0..padding], options.fill);987 mem.set(u8, padded_buf[0..padding], options.fill);
988 return out_stream.writeAll(padded_buf);988 return writer.writeAll(padded_buf);
989 }989 }
990}990}
991991
992pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {992pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {
993 var fbs = std.io.fixedBufferStream(out_buf);993 var fbs = std.io.fixedBufferStream(out_buf);
994 formatInt(value, base, uppercase, options, fbs.outStream()) catch unreachable;994 formatInt(value, base, uppercase, options, fbs.writer()) catch unreachable;
995 return fbs.pos;995 return fbs.pos;
996}996}
997997
...@@ -1098,15 +1098,15 @@ pub const BufPrintError = error{...@@ -1098,15 +1098,15 @@ pub const BufPrintError = error{
1098};1098};
1099pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {1099pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
1100 var fbs = std.io.fixedBufferStream(buf);1100 var fbs = std.io.fixedBufferStream(buf);
1101 try format(fbs.outStream(), fmt, args);1101 try format(fbs.writer(), fmt, args);
1102 return fbs.getWritten();1102 return fbs.getWritten();
1103}1103}
11041104
1105// Count the characters needed for format. Useful for preallocating memory1105// Count the characters needed for format. Useful for preallocating memory
1106pub fn count(comptime fmt: []const u8, args: var) u64 {1106pub fn count(comptime fmt: []const u8, args: var) u64 {
1107 var counting_stream = std.io.countingOutStream(std.io.null_out_stream);1107 var counting_writer = std.io.countingWriter(std.io.null_writer);
1108 format(counting_stream.outStream(), fmt, args) catch |err| switch (err) {};1108 format(counting_writer.writer(), fmt, args) catch |err| switch (err) {};
1109 return counting_stream.bytes_written;1109 return counting_writer.bytes_written;
1110}1110}
11111111
1112pub const AllocPrintError = error{OutOfMemory};1112pub const AllocPrintError = error{OutOfMemory};
...@@ -1215,15 +1215,15 @@ test "buffer" {...@@ -1215,15 +1215,15 @@ test "buffer" {
1215 {1215 {
1216 var buf1: [32]u8 = undefined;1216 var buf1: [32]u8 = undefined;
1217 var fbs = std.io.fixedBufferStream(&buf1);1217 var fbs = std.io.fixedBufferStream(&buf1);
1218 try formatType(1234, "", FormatOptions{}, fbs.outStream(), default_max_depth);1218 try formatType(1234, "", FormatOptions{}, fbs.writer(), default_max_depth);
1219 std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234"));1219 std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234"));
12201220
1221 fbs.reset();1221 fbs.reset();
1222 try formatType('a', "c", FormatOptions{}, fbs.outStream(), default_max_depth);1222 try formatType('a', "c", FormatOptions{}, fbs.writer(), default_max_depth);
1223 std.testing.expect(mem.eql(u8, fbs.getWritten(), "a"));1223 std.testing.expect(mem.eql(u8, fbs.getWritten(), "a"));
12241224
1225 fbs.reset();1225 fbs.reset();
1226 try formatType(0b1100, "b", FormatOptions{}, fbs.outStream(), default_max_depth);1226 try formatType(0b1100, "b", FormatOptions{}, fbs.writer(), default_max_depth);
1227 std.testing.expect(mem.eql(u8, fbs.getWritten(), "1100"));1227 std.testing.expect(mem.eql(u8, fbs.getWritten(), "1100"));
1228 }1228 }
1229}1229}
...@@ -1413,12 +1413,12 @@ test "custom" {...@@ -1413,12 +1413,12 @@ test "custom" {
1413 self: SelfType,1413 self: SelfType,
1414 comptime fmt: []const u8,1414 comptime fmt: []const u8,
1415 options: FormatOptions,1415 options: FormatOptions,
1416 out_stream: var,1416 writer: var,
1417 ) !void {1417 ) !void {
1418 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {1418 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
1419 return std.fmt.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });1419 return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y });
1420 } else if (comptime std.mem.eql(u8, fmt, "d")) {1420 } else if (comptime std.mem.eql(u8, fmt, "d")) {
1421 return std.fmt.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });1421 return std.fmt.format(writer, "{d:.3}x{d:.3}", .{ self.x, self.y });
1422 } else {1422 } else {
1423 @compileError("Unknown format character: '" ++ fmt ++ "'");1423 @compileError("Unknown format character: '" ++ fmt ++ "'");
1424 }1424 }
...@@ -1604,7 +1604,7 @@ test "formatIntValue with comptime_int" {...@@ -1604,7 +1604,7 @@ test "formatIntValue with comptime_int" {
16041604
1605 var buf: [20]u8 = undefined;1605 var buf: [20]u8 = undefined;
1606 var fbs = std.io.fixedBufferStream(&buf);1606 var fbs = std.io.fixedBufferStream(&buf);
1607 try formatIntValue(value, "", FormatOptions{}, fbs.outStream());1607 try formatIntValue(value, "", FormatOptions{}, fbs.writer());
1608 std.testing.expect(mem.eql(u8, fbs.getWritten(), "123456789123456789"));1608 std.testing.expect(mem.eql(u8, fbs.getWritten(), "123456789123456789"));
1609}1609}
16101610
...@@ -1613,7 +1613,7 @@ test "formatFloatValue with comptime_float" {...@@ -1613,7 +1613,7 @@ test "formatFloatValue with comptime_float" {
16131613
1614 var buf: [20]u8 = undefined;1614 var buf: [20]u8 = undefined;
1615 var fbs = std.io.fixedBufferStream(&buf);1615 var fbs = std.io.fixedBufferStream(&buf);
1616 try formatFloatValue(value, "", FormatOptions{}, fbs.outStream());1616 try formatFloatValue(value, "", FormatOptions{}, fbs.writer());
1617 std.testing.expect(mem.eql(u8, fbs.getWritten(), "1.0e+00"));1617 std.testing.expect(mem.eql(u8, fbs.getWritten(), "1.0e+00"));
16181618
1619 try testFmt("1.0e+00", "{}", .{value});1619 try testFmt("1.0e+00", "{}", .{value});
...@@ -1630,10 +1630,10 @@ test "formatType max_depth" {...@@ -1630,10 +1630,10 @@ test "formatType max_depth" {
1630 self: SelfType,1630 self: SelfType,
1631 comptime fmt: []const u8,1631 comptime fmt: []const u8,
1632 options: FormatOptions,1632 options: FormatOptions,
1633 out_stream: var,1633 writer: var,
1634 ) !void {1634 ) !void {
1635 if (fmt.len == 0) {1635 if (fmt.len == 0) {
1636 return std.fmt.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });1636 return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y });
1637 } else {1637 } else {
1638 @compileError("Unknown format string: '" ++ fmt ++ "'");1638 @compileError("Unknown format string: '" ++ fmt ++ "'");
1639 }1639 }
...@@ -1669,19 +1669,19 @@ test "formatType max_depth" {...@@ -1669,19 +1669,19 @@ test "formatType max_depth" {
16691669
1670 var buf: [1000]u8 = undefined;1670 var buf: [1000]u8 = undefined;
1671 var fbs = std.io.fixedBufferStream(&buf);1671 var fbs = std.io.fixedBufferStream(&buf);
1672 try formatType(inst, "", FormatOptions{}, fbs.outStream(), 0);1672 try formatType(inst, "", FormatOptions{}, fbs.writer(), 0);
1673 std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ ... }"));1673 std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ ... }"));
16741674
1675 fbs.reset();1675 fbs.reset();
1676 try formatType(inst, "", FormatOptions{}, fbs.outStream(), 1);1676 try formatType(inst, "", FormatOptions{}, fbs.writer(), 1);
1677 std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));1677 std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
16781678
1679 fbs.reset();1679 fbs.reset();
1680 try formatType(inst, "", FormatOptions{}, fbs.outStream(), 2);1680 try formatType(inst, "", FormatOptions{}, fbs.writer(), 2);
1681 std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));1681 std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
16821682
1683 fbs.reset();1683 fbs.reset();
1684 try formatType(inst, "", FormatOptions{}, fbs.outStream(), 3);1684 try formatType(inst, "", FormatOptions{}, fbs.writer(), 3);
1685 std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));1685 std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
1686}1686}
16871687
lib/std/fs.zig+17-21
...@@ -261,17 +261,7 @@ pub const Dir = struct {...@@ -261,17 +261,7 @@ pub const Dir = struct {
261 name: []const u8,261 name: []const u8,
262 kind: Kind,262 kind: Kind,
263263
264 pub const Kind = enum {264 pub const Kind = File.Kind;
265 BlockDevice,
266 CharacterDevice,
267 Directory,
268 NamedPipe,
269 SymLink,
270 File,
271 UnixDomainSocket,
272 Whiteout,
273 Unknown,
274 };
275 };265 };
276266
277 const IteratorError = error{AccessDenied} || os.UnexpectedError;267 const IteratorError = error{AccessDenied} || os.UnexpectedError;
...@@ -1229,14 +1219,9 @@ pub const Dir = struct {...@@ -1229,14 +1219,9 @@ pub const Dir = struct {
1229 var file = try self.openFile(file_path, .{});1219 var file = try self.openFile(file_path, .{});
1230 defer file.close();1220 defer file.close();
12311221
1232 const size = math.cast(usize, try file.getEndPos()) catch math.maxInt(usize);1222 const stat_size = try file.getEndPos();
1233 if (size > max_bytes) return error.FileTooBig;
1234
1235 const buf = try allocator.allocWithOptions(u8, size, alignment, optional_sentinel);
1236 errdefer allocator.free(buf);
12371223
1238 try file.inStream().readNoEof(buf);1224 return file.readAllAllocOptions(allocator, stat_size, max_bytes, alignment, optional_sentinel);
1239 return buf;
1240 }1225 }
12411226
1242 pub const DeleteTreeError = error{1227 pub const DeleteTreeError = error{
...@@ -1532,9 +1517,9 @@ pub const Dir = struct {...@@ -1532,9 +1517,9 @@ pub const Dir = struct {
15321517
1533 var size: ?u64 = null;1518 var size: ?u64 = null;
1534 const mode = options.override_mode orelse blk: {1519 const mode = options.override_mode orelse blk: {
1535 const stat = try in_file.stat();1520 const st = try in_file.stat();
1536 size = stat.size;1521 size = st.size;
1537 break :blk stat.mode;1522 break :blk st.mode;
1538 };1523 };
15391524
1540 var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode });1525 var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode });
...@@ -1560,6 +1545,17 @@ pub const Dir = struct {...@@ -1560,6 +1545,17 @@ pub const Dir = struct {
1560 return AtomicFile.init(dest_path, options.mode, self, false);1545 return AtomicFile.init(dest_path, options.mode, self, false);
1561 }1546 }
1562 }1547 }
1548
1549 pub const Stat = File.Stat;
1550 pub const StatError = File.StatError;
1551
1552 pub fn stat(self: Dir) StatError!Stat {
1553 const file: File = .{
1554 .handle = self.fd,
1555 .capable_io_mode = .blocking,
1556 };
1557 return file.stat();
1558 }
1563};1559};
15641560
1565/// Returns an handle to the current working directory. It is not opened with iteration capability.1561/// Returns an handle to the current working directory. It is not opened with iteration capability.
lib/std/fs/file.zig+64-2
...@@ -29,6 +29,18 @@ pub const File = struct {...@@ -29,6 +29,18 @@ pub const File = struct {
29 pub const Mode = os.mode_t;29 pub const Mode = os.mode_t;
30 pub const INode = os.ino_t;30 pub const INode = os.ino_t;
3131
32 pub const Kind = enum {
33 BlockDevice,
34 CharacterDevice,
35 Directory,
36 NamedPipe,
37 SymLink,
38 File,
39 UnixDomainSocket,
40 Whiteout,
41 Unknown,
42 };
43
32 pub const default_mode = switch (builtin.os.tag) {44 pub const default_mode = switch (builtin.os.tag) {
33 .windows => 0,45 .windows => 0,
34 .wasi => 0,46 .wasi => 0,
...@@ -209,7 +221,7 @@ pub const File = struct {...@@ -209,7 +221,7 @@ pub const File = struct {
209 /// TODO: integrate with async I/O221 /// TODO: integrate with async I/O
210 pub fn mode(self: File) ModeError!Mode {222 pub fn mode(self: File) ModeError!Mode {
211 if (builtin.os.tag == .windows) {223 if (builtin.os.tag == .windows) {
212 return {};224 return 0;
213 }225 }
214 return (try self.stat()).mode;226 return (try self.stat()).mode;
215 }227 }
...@@ -219,13 +231,14 @@ pub const File = struct {...@@ -219,13 +231,14 @@ pub const File = struct {
219 /// unique across time, as some file systems may reuse an inode after its file has been deleted.231 /// unique across time, as some file systems may reuse an inode after its file has been deleted.
220 /// Some systems may change the inode of a file over time.232 /// Some systems may change the inode of a file over time.
221 ///233 ///
222 /// On Linux, the inode _is_ structure that stores the metadata, and the inode _number_ is what234 /// On Linux, the inode is a structure that stores the metadata, and the inode _number_ is what
223 /// you see here: the index number of the inode.235 /// you see here: the index number of the inode.
224 ///236 ///
225 /// The FileIndex on Windows is similar. It is a number for a file that is unique to each filesystem.237 /// The FileIndex on Windows is similar. It is a number for a file that is unique to each filesystem.
226 inode: INode,238 inode: INode,
227 size: u64,239 size: u64,
228 mode: Mode,240 mode: Mode,
241 kind: Kind,
229242
230 /// Access time in nanoseconds, relative to UTC 1970-01-01.243 /// Access time in nanoseconds, relative to UTC 1970-01-01.
231 atime: i128,244 atime: i128,
...@@ -254,6 +267,7 @@ pub const File = struct {...@@ -254,6 +267,7 @@ pub const File = struct {
254 .inode = info.InternalInformation.IndexNumber,267 .inode = info.InternalInformation.IndexNumber,
255 .size = @bitCast(u64, info.StandardInformation.EndOfFile),268 .size = @bitCast(u64, info.StandardInformation.EndOfFile),
256 .mode = 0,269 .mode = 0,
270 .kind = if (info.StandardInformation.Directory == 0) .File else .Directory,
257 .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime),271 .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime),
258 .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime),272 .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime),
259 .ctime = windows.fromSysTime(info.BasicInformation.CreationTime),273 .ctime = windows.fromSysTime(info.BasicInformation.CreationTime),
...@@ -268,6 +282,27 @@ pub const File = struct {...@@ -268,6 +282,27 @@ pub const File = struct {
268 .inode = st.ino,282 .inode = st.ino,
269 .size = @bitCast(u64, st.size),283 .size = @bitCast(u64, st.size),
270 .mode = st.mode,284 .mode = st.mode,
285 .kind = switch (builtin.os.tag) {
286 .wasi => switch (st.filetype) {
287 os.FILETYPE_BLOCK_DEVICE => Kind.BlockDevice,
288 os.FILETYPE_CHARACTER_DEVICE => Kind.CharacterDevice,
289 os.FILETYPE_DIRECTORY => Kind.Directory,
290 os.FILETYPE_SYMBOLIC_LINK => Kind.SymLink,
291 os.FILETYPE_REGULAR_FILE => Kind.File,
292 os.FILETYPE_SOCKET_STREAM, os.FILETYPE_SOCKET_DGRAM => Kind.UnixDomainSocket,
293 else => Kind.Unknown,
294 },
295 else => switch (st.mode & os.S_IFMT) {
296 os.S_IFBLK => Kind.BlockDevice,
297 os.S_IFCHR => Kind.CharacterDevice,
298 os.S_IFDIR => Kind.Directory,
299 os.S_IFIFO => Kind.NamedPipe,
300 os.S_IFLNK => Kind.SymLink,
301 os.S_IFREG => Kind.File,
302 os.S_IFSOCK => Kind.UnixDomainSocket,
303 else => Kind.Unknown,
304 },
305 },
271 .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,306 .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
272 .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,307 .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
273 .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,308 .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
...@@ -306,6 +341,33 @@ pub const File = struct {...@@ -306,6 +341,33 @@ pub const File = struct {
306 try os.futimens(self.handle, &times);341 try os.futimens(self.handle, &times);
307 }342 }
308343
344 /// On success, caller owns returned buffer.
345 /// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
346 pub fn readAllAlloc(self: File, allocator: *mem.Allocator, stat_size: u64, max_bytes: usize) ![]u8 {
347 return self.readAllAllocOptions(allocator, stat_size, max_bytes, @alignOf(u8), null);
348 }
349
350 /// On success, caller owns returned buffer.
351 /// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
352 /// Allows specifying alignment and a sentinel value.
353 pub fn readAllAllocOptions(
354 self: File,
355 allocator: *mem.Allocator,
356 stat_size: u64,
357 max_bytes: usize,
358 comptime alignment: u29,
359 comptime optional_sentinel: ?u8,
360 ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) {
361 const size = math.cast(usize, stat_size) catch math.maxInt(usize);
362 if (size > max_bytes) return error.FileTooBig;
363
364 const buf = try allocator.allocWithOptions(u8, size, alignment, optional_sentinel);
365 errdefer allocator.free(buf);
366
367 try self.reader().readNoEof(buf);
368 return buf;
369 }
370
309 pub const ReadError = os.ReadError;371 pub const ReadError = os.ReadError;
310 pub const PReadError = os.PReadError;372 pub const PReadError = os.PReadError;
311373
lib/std/fs/test.zig+40-3
...@@ -1,7 +1,44 @@...@@ -1,7 +1,44 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const testing = std.testing;
2const builtin = std.builtin;3const builtin = std.builtin;
3const fs = std.fs;4const fs = std.fs;
5const mem = std.mem;
6
4const File = std.fs.File;7const File = std.fs.File;
8const tmpDir = testing.tmpDir;
9
10test "readAllAlloc" {
11 var tmp_dir = tmpDir(.{});
12 defer tmp_dir.cleanup();
13
14 var file = try tmp_dir.dir.createFile("test_file", .{ .read = true });
15 defer file.close();
16
17 const buf1 = try file.readAllAlloc(testing.allocator, 0, 1024);
18 defer testing.allocator.free(buf1);
19 testing.expect(buf1.len == 0);
20
21 const write_buf: []const u8 = "this is a test.\nthis is a test.\nthis is a test.\nthis is a test.\n";
22 try file.writeAll(write_buf);
23 try file.seekTo(0);
24 const file_size = try file.getEndPos();
25
26 // max_bytes > file_size
27 const buf2 = try file.readAllAlloc(testing.allocator, file_size, 1024);
28 defer testing.allocator.free(buf2);
29 testing.expectEqual(write_buf.len, buf2.len);
30 testing.expect(std.mem.eql(u8, write_buf, buf2));
31 try file.seekTo(0);
32
33 // max_bytes == file_size
34 const buf3 = try file.readAllAlloc(testing.allocator, file_size, write_buf.len);
35 defer testing.allocator.free(buf3);
36 testing.expectEqual(write_buf.len, buf3.len);
37 testing.expect(std.mem.eql(u8, write_buf, buf3));
38
39 // max_bytes < file_size
40 testing.expectError(error.FileTooBig, file.readAllAlloc(testing.allocator, file_size, write_buf.len - 1));
41}
542
6test "openSelfExe" {43test "openSelfExe" {
7 if (builtin.os.tag == .wasi) return error.SkipZigTest;44 if (builtin.os.tag == .wasi) return error.SkipZigTest;
...@@ -116,7 +153,7 @@ test "create file, lock and read from multiple process at once" {...@@ -116,7 +153,7 @@ test "create file, lock and read from multiple process at once" {
116test "open file with exclusive nonblocking lock twice (absolute paths)" {153test "open file with exclusive nonblocking lock twice (absolute paths)" {
117 if (builtin.os.tag == .wasi) return error.SkipZigTest;154 if (builtin.os.tag == .wasi) return error.SkipZigTest;
118155
119 const allocator = std.testing.allocator;156 const allocator = testing.allocator;
120157
121 const file_paths: [1][]const u8 = .{"zig-test-absolute-paths.txt"};158 const file_paths: [1][]const u8 = .{"zig-test-absolute-paths.txt"};
122 const filename = try fs.path.resolve(allocator, &file_paths);159 const filename = try fs.path.resolve(allocator, &file_paths);
...@@ -126,7 +163,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {...@@ -126,7 +163,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
126163
127 const file2 = fs.createFileAbsolute(filename, .{ .lock = .Exclusive, .lock_nonblocking = true });164 const file2 = fs.createFileAbsolute(filename, .{ .lock = .Exclusive, .lock_nonblocking = true });
128 file1.close();165 file1.close();
129 std.testing.expectError(error.WouldBlock, file2);166 testing.expectError(error.WouldBlock, file2);
130167
131 try fs.deleteFileAbsolute(filename);168 try fs.deleteFileAbsolute(filename);
132}169}
...@@ -187,7 +224,7 @@ const FileLockTestContext = struct {...@@ -187,7 +224,7 @@ const FileLockTestContext = struct {
187};224};
188225
189fn run_lock_file_test(contexts: []FileLockTestContext) !void {226fn run_lock_file_test(contexts: []FileLockTestContext) !void {
190 var threads = std.ArrayList(*std.Thread).init(std.testing.allocator);227 var threads = std.ArrayList(*std.Thread).init(testing.allocator);
191 defer {228 defer {
192 for (threads.items) |thread| {229 for (threads.items) |thread| {
193 thread.wait();230 thread.wait();
lib/std/io/buffered_out_stream.zig+1-1
...@@ -2,4 +2,4 @@...@@ -2,4 +2,4 @@
2pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter;2pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter;
33
4/// Deprecated: use `std.io.buffered_writer.bufferedWriter`4/// Deprecated: use `std.io.buffered_writer.bufferedWriter`
5pub const bufferedOutStream = @import("./buffered_writer.zig").bufferedWriter5pub const bufferedOutStream = @import("./buffered_writer.zig").bufferedWriter;
lib/std/io/reader.zig+1-2
...@@ -40,8 +40,7 @@ pub fn Reader(...@@ -40,8 +40,7 @@ pub fn Reader(
40 return index;40 return index;
41 }41 }
4242
43 /// Returns the number of bytes read. If the number read would be smaller than buf.len,43 /// If the number read would be smaller than `buf.len`, `error.EndOfStream` is returned instead.
44 /// error.EndOfStream is returned instead.
45 pub fn readNoEof(self: Self, buf: []u8) !void {44 pub fn readNoEof(self: Self, buf: []u8) !void {
46 const amt_read = try self.readAll(buf);45 const amt_read = try self.readAll(buf);
47 if (amt_read < buf.len) return error.EndOfStream;46 if (amt_read < buf.len) return error.EndOfStream;
lib/std/json.zig+4-5
...@@ -1535,7 +1535,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:...@@ -1535,7 +1535,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
1535 const allocator = options.allocator orelse return error.AllocatorRequired;1535 const allocator = options.allocator orelse return error.AllocatorRequired;
1536 switch (ptrInfo.size) {1536 switch (ptrInfo.size) {
1537 .One => {1537 .One => {
1538 const r: T = allocator.create(ptrInfo.child);1538 const r: T = try allocator.create(ptrInfo.child);
1539 r.* = try parseInternal(ptrInfo.child, token, tokens, options);1539 r.* = try parseInternal(ptrInfo.child, token, tokens, options);
1540 return r;1540 return r;
1541 },1541 },
...@@ -1629,7 +1629,7 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void {...@@ -1629,7 +1629,7 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void {
1629 switch (ptrInfo.size) {1629 switch (ptrInfo.size) {
1630 .One => {1630 .One => {
1631 parseFree(ptrInfo.child, value.*, options);1631 parseFree(ptrInfo.child, value.*, options);
1632 allocator.destroy(v);1632 allocator.destroy(value);
1633 },1633 },
1634 .Slice => {1634 .Slice => {
1635 for (value) |v| {1635 for (value) |v| {
...@@ -2576,8 +2576,8 @@ pub fn stringify(...@@ -2576,8 +2576,8 @@ pub fn stringify(
2576 },2576 },
2577 .Array => return stringify(&value, options, out_stream),2577 .Array => return stringify(&value, options, out_stream),
2578 .Vector => |info| {2578 .Vector => |info| {
2579 const array: [info.len]info.child = value;2579 const array: [info.len]info.child = value;
2580 return stringify(&array, options, out_stream);2580 return stringify(&array, options, out_stream);
2581 },2581 },
2582 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),2582 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
2583 }2583 }
...@@ -2770,4 +2770,3 @@ test "stringify struct with custom stringifier" {...@@ -2770,4 +2770,3 @@ test "stringify struct with custom stringifier" {
2770test "stringify vector" {2770test "stringify vector" {
2771 try teststringify("[1,1]", @splat(2, @as(u32, 1)), StringifyOptions{});2771 try teststringify("[1,1]", @splat(2, @as(u32, 1)), StringifyOptions{});
2772}2772}
2773
lib/std/log.zig created+202
...@@ -0,0 +1,202 @@
1const std = @import("std.zig");
2const builtin = std.builtin;
3const root = @import("root");
4
5//! std.log is standardized interface for logging which allows for the logging
6//! of programs and libraries using this interface to be formatted and filtered
7//! by the implementer of the root.log function.
8//!
9//! The scope parameter should be used to give context to the logging. For
10//! example, a library called 'libfoo' might use .libfoo as its scope.
11//!
12//! An example root.log might look something like this:
13//!
14//! ```
15//! const std = @import("std");
16//!
17//! // Set the log level to warning
18//! pub const log_level: std.log.Level = .warn;
19//!
20//! // Define root.log to override the std implementation
21//! pub fn log(
22//! comptime level: std.log.Level,
23//! comptime scope: @TypeOf(.EnumLiteral),
24//! comptime format: []const u8,
25//! args: var,
26//! ) void {
27//! // Ignore all non-critical logging from sources other than
28//! // .my_project and .nice_library
29//! const scope_prefix = "(" ++ switch (scope) {
30//! .my_project, .nice_library => @tagName(scope),
31//! else => if (@enumToInt(level) <= @enumToInt(std.log.Level.crit))
32//! @tagName(scope)
33//! else
34//! return,
35//! } ++ "): ";
36//!
37//! const prefix = "[" ++ @tagName(level) ++ "] " ++ scope_prefix;
38//!
39//! // Print the message to stderr, silently ignoring any errors
40//! const held = std.debug.getStderrMutex().acquire();
41//! defer held.release();
42//! const stderr = std.debug.getStderrStream();
43//! nosuspend stderr.print(prefix ++ format, args) catch return;
44//! }
45//!
46//! pub fn main() void {
47//! // Won't be printed as log_level is .warn
48//! std.log.info(.my_project, "Starting up.\n", .{});
49//! std.log.err(.nice_library, "Something went very wrong, sorry.\n", .{});
50//! // Won't be printed as it gets filtered out by our log function
51//! std.log.err(.lib_that_logs_too_much, "Added 1 + 1\n", .{});
52//! }
53//! ```
54//! Which produces the following output:
55//! ```
56//! [err] (nice_library): Something went very wrong, sorry.
57//! ```
58
59pub const Level = enum {
60 /// Emergency: a condition that cannot be handled, usually followed by a
61 /// panic.
62 emerg,
63 /// Alert: a condition that should be corrected immediately (e.g. database
64 /// corruption).
65 alert,
66 /// Critical: A bug has been detected or something has gone wrong and it
67 /// will have an effect on the operation of the program.
68 crit,
69 /// Error: A bug has been detected or something has gone wrong but it is
70 /// recoverable.
71 err,
72 /// Warning: it is uncertain if something has gone wrong or not, but the
73 /// circumstances would be worth investigating.
74 warn,
75 /// Notice: non-error but significant conditions.
76 notice,
77 /// Informational: general messages about the state of the program.
78 info,
79 /// Debug: messages only useful for debugging.
80 debug,
81};
82
83/// The default log level is based on build mode. Note that in ReleaseSmall
84/// builds the default level is emerg but no messages will be stored/logged
85/// by the default logger to save space.
86pub const default_level: Level = switch (builtin.mode) {
87 .Debug => .debug,
88 .ReleaseSafe => .notice,
89 .ReleaseFast => .err,
90 .ReleaseSmall => .emerg,
91};
92
93/// The current log level. This is set to root.log_level if present, otherwise
94/// log.default_level.
95pub const level: Level = if (@hasDecl(root, "log_level"))
96 root.log_level
97else
98 default_level;
99
100fn log(
101 comptime message_level: Level,
102 comptime scope: @Type(.EnumLiteral),
103 comptime format: []const u8,
104 args: var,
105) void {
106 if (@enumToInt(message_level) <= @enumToInt(level)) {
107 if (@hasDecl(root, "log")) {
108 root.log(message_level, scope, format, args);
109 } else if (builtin.mode != .ReleaseSmall) {
110 const held = std.debug.getStderrMutex().acquire();
111 defer held.release();
112 const stderr = std.io.getStdErr().writer();
113 nosuspend stderr.print(format, args) catch return;
114 }
115 }
116}
117
118/// Log an emergency message to stderr. This log level is intended to be used
119/// for conditions that cannot be handled and is usually followed by a panic.
120pub fn emerg(
121 comptime scope: @Type(.EnumLiteral),
122 comptime format: []const u8,
123 args: var,
124) void {
125 @setCold(true);
126 log(.emerg, scope, format, args);
127}
128
129/// Log an alert message to stderr. This log level is intended to be used for
130/// conditions that should be corrected immediately (e.g. database corruption).
131pub fn alert(
132 comptime scope: @Type(.EnumLiteral),
133 comptime format: []const u8,
134 args: var,
135) void {
136 @setCold(true);
137 log(.alert, scope, format, args);
138}
139
140/// Log a critical message to stderr. This log level is intended to be used
141/// when a bug has been detected or something has gone wrong and it will have
142/// an effect on the operation of the program.
143pub fn crit(
144 comptime scope: @Type(.EnumLiteral),
145 comptime format: []const u8,
146 args: var,
147) void {
148 @setCold(true);
149 log(.crit, scope, format, args);
150}
151
152/// Log an error message to stderr. This log level is intended to be used when
153/// a bug has been detected or something has gone wrong but it is recoverable.
154pub fn err(
155 comptime scope: @Type(.EnumLiteral),
156 comptime format: []const u8,
157 args: var,
158) void {
159 @setCold(true);
160 log(.err, scope, format, args);
161}
162
163/// Log a warning message to stderr. This log level is intended to be used if
164/// it is uncertain whether something has gone wrong or not, but the
165/// circumstances would be worth investigating.
166pub fn warn(
167 comptime scope: @Type(.EnumLiteral),
168 comptime format: []const u8,
169 args: var,
170) void {
171 log(.warn, scope, format, args);
172}
173
174/// Log a notice message to stderr. This log level is intended to be used for
175/// non-error but significant conditions.
176pub fn notice(
177 comptime scope: @Type(.EnumLiteral),
178 comptime format: []const u8,
179 args: var,
180) void {
181 log(.notice, scope, format, args);
182}
183
184/// Log an info message to stderr. This log level is intended to be used for
185/// general messages about the state of the program.
186pub fn info(
187 comptime scope: @Type(.EnumLiteral),
188 comptime format: []const u8,
189 args: var,
190) void {
191 log(.info, scope, format, args);
192}
193
194/// Log a debug message to stderr. This log level is intended to be used for
195/// messages which are only useful for debugging.
196pub fn debug(
197 comptime scope: @Type(.EnumLiteral),
198 comptime format: []const u8,
199 args: var,
200) void {
201 log(.debug, scope, format, args);
202}
lib/std/math.zig+5
...@@ -122,6 +122,11 @@ pub fn forceEval(value: var) void {...@@ -122,6 +122,11 @@ pub fn forceEval(value: var) void {
122 const p = @ptrCast(*volatile f64, &x);122 const p = @ptrCast(*volatile f64, &x);
123 p.* = x;123 p.* = x;
124 },124 },
125 f128 => {
126 var x: f128 = undefined;
127 const p = @ptrCast(*volatile f128, &x);
128 p.* = x;
129 },
125 else => {130 else => {
126 @compileError("forceEval not implemented for " ++ @typeName(T));131 @compileError("forceEval not implemented for " ++ @typeName(T));
127 },132 },
lib/std/math/ceil.zig+43
...@@ -20,6 +20,7 @@ pub fn ceil(x: var) @TypeOf(x) {...@@ -20,6 +20,7 @@ pub fn ceil(x: var) @TypeOf(x) {
20 return switch (T) {20 return switch (T) {
21 f32 => ceil32(x),21 f32 => ceil32(x),
22 f64 => ceil64(x),22 f64 => ceil64(x),
23 f128 => ceil128(x),
23 else => @compileError("ceil not implemented for " ++ @typeName(T)),24 else => @compileError("ceil not implemented for " ++ @typeName(T)),
24 };25 };
25}26}
...@@ -86,9 +87,37 @@ fn ceil64(x: f64) f64 {...@@ -86,9 +87,37 @@ fn ceil64(x: f64) f64 {
86 }87 }
87}88}
8889
90fn ceil128(x: f128) f128 {
91 const u = @bitCast(u128, x);
92 const e = (u >> 112) & 0x7FFF;
93 var y: f128 = undefined;
94
95 if (e >= 0x3FFF + 112 or x == 0) return x;
96
97 if (u >> 127 != 0) {
98 y = x - math.f128_toint + math.f128_toint - x;
99 } else {
100 y = x + math.f128_toint - math.f128_toint - x;
101 }
102
103 if (e <= 0x3FFF - 1) {
104 math.forceEval(y);
105 if (u >> 127 != 0) {
106 return -0.0;
107 } else {
108 return 1.0;
109 }
110 } else if (y < 0) {
111 return x + y + 1;
112 } else {
113 return x + y;
114 }
115}
116
89test "math.ceil" {117test "math.ceil" {
90 expect(ceil(@as(f32, 0.0)) == ceil32(0.0));118 expect(ceil(@as(f32, 0.0)) == ceil32(0.0));
91 expect(ceil(@as(f64, 0.0)) == ceil64(0.0));119 expect(ceil(@as(f64, 0.0)) == ceil64(0.0));
120 expect(ceil(@as(f128, 0.0)) == ceil128(0.0));
92}121}
93122
94test "math.ceil32" {123test "math.ceil32" {
...@@ -103,6 +132,12 @@ test "math.ceil64" {...@@ -103,6 +132,12 @@ test "math.ceil64" {
103 expect(ceil64(0.2) == 1.0);132 expect(ceil64(0.2) == 1.0);
104}133}
105134
135test "math.ceil128" {
136 expect(ceil128(1.3) == 2.0);
137 expect(ceil128(-1.3) == -1.0);
138 expect(ceil128(0.2) == 1.0);
139}
140
106test "math.ceil32.special" {141test "math.ceil32.special" {
107 expect(ceil32(0.0) == 0.0);142 expect(ceil32(0.0) == 0.0);
108 expect(ceil32(-0.0) == -0.0);143 expect(ceil32(-0.0) == -0.0);
...@@ -118,3 +153,11 @@ test "math.ceil64.special" {...@@ -118,3 +153,11 @@ test "math.ceil64.special" {
118 expect(math.isNegativeInf(ceil64(-math.inf(f64))));153 expect(math.isNegativeInf(ceil64(-math.inf(f64))));
119 expect(math.isNan(ceil64(math.nan(f64))));154 expect(math.isNan(ceil64(math.nan(f64))));
120}155}
156
157test "math.ceil128.special" {
158 expect(ceil128(0.0) == 0.0);
159 expect(ceil128(-0.0) == -0.0);
160 expect(math.isPositiveInf(ceil128(math.inf(f128))));
161 expect(math.isNegativeInf(ceil128(-math.inf(f128))));
162 expect(math.isNan(ceil128(math.nan(f128))));
163}
lib/std/math/floor.zig+43
...@@ -21,6 +21,7 @@ pub fn floor(x: var) @TypeOf(x) {...@@ -21,6 +21,7 @@ pub fn floor(x: var) @TypeOf(x) {
21 f16 => floor16(x),21 f16 => floor16(x),
22 f32 => floor32(x),22 f32 => floor32(x),
23 f64 => floor64(x),23 f64 => floor64(x),
24 f128 => floor128(x),
24 else => @compileError("floor not implemented for " ++ @typeName(T)),25 else => @compileError("floor not implemented for " ++ @typeName(T)),
25 };26 };
26}27}
...@@ -122,10 +123,38 @@ fn floor64(x: f64) f64 {...@@ -122,10 +123,38 @@ fn floor64(x: f64) f64 {
122 }123 }
123}124}
124125
126fn floor128(x: f128) f128 {
127 const u = @bitCast(u128, x);
128 const e = (u >> 112) & 0x7FFF;
129 var y: f128 = undefined;
130
131 if (e >= 0x3FFF + 112 or x == 0) return x;
132
133 if (u >> 127 != 0) {
134 y = x - math.f128_toint + math.f128_toint - x;
135 } else {
136 y = x + math.f128_toint - math.f128_toint - x;
137 }
138
139 if (e <= 0x3FFF - 1) {
140 math.forceEval(y);
141 if (u >> 127 != 0) {
142 return -1.0;
143 } else {
144 return 0.0;
145 }
146 } else if (y > 0) {
147 return x + y - 1;
148 } else {
149 return x + y;
150 }
151}
152
125test "math.floor" {153test "math.floor" {
126 expect(floor(@as(f16, 1.3)) == floor16(1.3));154 expect(floor(@as(f16, 1.3)) == floor16(1.3));
127 expect(floor(@as(f32, 1.3)) == floor32(1.3));155 expect(floor(@as(f32, 1.3)) == floor32(1.3));
128 expect(floor(@as(f64, 1.3)) == floor64(1.3));156 expect(floor(@as(f64, 1.3)) == floor64(1.3));
157 expect(floor(@as(f128, 1.3)) == floor128(1.3));
129}158}
130159
131test "math.floor16" {160test "math.floor16" {
...@@ -146,6 +175,12 @@ test "math.floor64" {...@@ -146,6 +175,12 @@ test "math.floor64" {
146 expect(floor64(0.2) == 0.0);175 expect(floor64(0.2) == 0.0);
147}176}
148177
178test "math.floor128" {
179 expect(floor128(1.3) == 1.0);
180 expect(floor128(-1.3) == -2.0);
181 expect(floor128(0.2) == 0.0);
182}
183
149test "math.floor16.special" {184test "math.floor16.special" {
150 expect(floor16(0.0) == 0.0);185 expect(floor16(0.0) == 0.0);
151 expect(floor16(-0.0) == -0.0);186 expect(floor16(-0.0) == -0.0);
...@@ -169,3 +204,11 @@ test "math.floor64.special" {...@@ -169,3 +204,11 @@ test "math.floor64.special" {
169 expect(math.isNegativeInf(floor64(-math.inf(f64))));204 expect(math.isNegativeInf(floor64(-math.inf(f64))));
170 expect(math.isNan(floor64(math.nan(f64))));205 expect(math.isNan(floor64(math.nan(f64))));
171}206}
207
208test "math.floor128.special" {
209 expect(floor128(0.0) == 0.0);
210 expect(floor128(-0.0) == -0.0);
211 expect(math.isPositiveInf(floor128(math.inf(f128))));
212 expect(math.isNegativeInf(floor128(-math.inf(f128))));
213 expect(math.isNan(floor128(math.nan(f128))));
214}
lib/std/math/round.zig+50
...@@ -20,6 +20,7 @@ pub fn round(x: var) @TypeOf(x) {...@@ -20,6 +20,7 @@ pub fn round(x: var) @TypeOf(x) {
20 return switch (T) {20 return switch (T) {
21 f32 => round32(x),21 f32 => round32(x),
22 f64 => round64(x),22 f64 => round64(x),
23 f128 => round128(x),
23 else => @compileError("round not implemented for " ++ @typeName(T)),24 else => @compileError("round not implemented for " ++ @typeName(T)),
24 };25 };
25}26}
...@@ -90,9 +91,43 @@ fn round64(x_: f64) f64 {...@@ -90,9 +91,43 @@ fn round64(x_: f64) f64 {
90 }91 }
91}92}
9293
94fn round128(x_: f128) f128 {
95 var x = x_;
96 const u = @bitCast(u128, x);
97 const e = (u >> 112) & 0x7FFF;
98 var y: f128 = undefined;
99
100 if (e >= 0x3FFF + 112) {
101 return x;
102 }
103 if (u >> 127 != 0) {
104 x = -x;
105 }
106 if (e < 0x3FFF - 1) {
107 math.forceEval(x + math.f64_toint);
108 return 0 * @bitCast(f128, u);
109 }
110
111 y = x + math.f128_toint - math.f128_toint - x;
112 if (y > 0.5) {
113 y = y + x - 1;
114 } else if (y <= -0.5) {
115 y = y + x + 1;
116 } else {
117 y = y + x;
118 }
119
120 if (u >> 127 != 0) {
121 return -y;
122 } else {
123 return y;
124 }
125}
126
93test "math.round" {127test "math.round" {
94 expect(round(@as(f32, 1.3)) == round32(1.3));128 expect(round(@as(f32, 1.3)) == round32(1.3));
95 expect(round(@as(f64, 1.3)) == round64(1.3));129 expect(round(@as(f64, 1.3)) == round64(1.3));
130 expect(round(@as(f128, 1.3)) == round128(1.3));
96}131}
97132
98test "math.round32" {133test "math.round32" {
...@@ -109,6 +144,13 @@ test "math.round64" {...@@ -109,6 +144,13 @@ test "math.round64" {
109 expect(round64(1.8) == 2.0);144 expect(round64(1.8) == 2.0);
110}145}
111146
147test "math.round128" {
148 expect(round128(1.3) == 1.0);
149 expect(round128(-1.3) == -1.0);
150 expect(round128(0.2) == 0.0);
151 expect(round128(1.8) == 2.0);
152}
153
112test "math.round32.special" {154test "math.round32.special" {
113 expect(round32(0.0) == 0.0);155 expect(round32(0.0) == 0.0);
114 expect(round32(-0.0) == -0.0);156 expect(round32(-0.0) == -0.0);
...@@ -124,3 +166,11 @@ test "math.round64.special" {...@@ -124,3 +166,11 @@ test "math.round64.special" {
124 expect(math.isNegativeInf(round64(-math.inf(f64))));166 expect(math.isNegativeInf(round64(-math.inf(f64))));
125 expect(math.isNan(round64(math.nan(f64))));167 expect(math.isNan(round64(math.nan(f64))));
126}168}
169
170test "math.round128.special" {
171 expect(round128(0.0) == 0.0);
172 expect(round128(-0.0) == -0.0);
173 expect(math.isPositiveInf(round128(math.inf(f128))));
174 expect(math.isNegativeInf(round128(-math.inf(f128))));
175 expect(math.isNan(round128(math.nan(f128))));
176}
lib/std/math/trunc.zig+37
...@@ -20,6 +20,7 @@ pub fn trunc(x: var) @TypeOf(x) {...@@ -20,6 +20,7 @@ pub fn trunc(x: var) @TypeOf(x) {
20 return switch (T) {20 return switch (T) {
21 f32 => trunc32(x),21 f32 => trunc32(x),
22 f64 => trunc64(x),22 f64 => trunc64(x),
23 f128 => trunc128(x),
23 else => @compileError("trunc not implemented for " ++ @typeName(T)),24 else => @compileError("trunc not implemented for " ++ @typeName(T)),
24 };25 };
25}26}
...@@ -66,9 +67,31 @@ fn trunc64(x: f64) f64 {...@@ -66,9 +67,31 @@ fn trunc64(x: f64) f64 {
66 }67 }
67}68}
6869
70fn trunc128(x: f128) f128 {
71 const u = @bitCast(u128, x);
72 var e = @intCast(i32, ((u >> 112) & 0x7FFF)) - 0x3FFF + 16;
73 var m: u128 = undefined;
74
75 if (e >= 112 + 16) {
76 return x;
77 }
78 if (e < 16) {
79 e = 1;
80 }
81
82 m = @as(u128, maxInt(u128)) >> @intCast(u7, e);
83 if (u & m == 0) {
84 return x;
85 } else {
86 math.forceEval(x + 0x1p120);
87 return @bitCast(f128, u & ~m);
88 }
89}
90
69test "math.trunc" {91test "math.trunc" {
70 expect(trunc(@as(f32, 1.3)) == trunc32(1.3));92 expect(trunc(@as(f32, 1.3)) == trunc32(1.3));
71 expect(trunc(@as(f64, 1.3)) == trunc64(1.3));93 expect(trunc(@as(f64, 1.3)) == trunc64(1.3));
94 expect(trunc(@as(f128, 1.3)) == trunc128(1.3));
72}95}
7396
74test "math.trunc32" {97test "math.trunc32" {
...@@ -83,6 +106,12 @@ test "math.trunc64" {...@@ -83,6 +106,12 @@ test "math.trunc64" {
83 expect(trunc64(0.2) == 0.0);106 expect(trunc64(0.2) == 0.0);
84}107}
85108
109test "math.trunc128" {
110 expect(trunc128(1.3) == 1.0);
111 expect(trunc128(-1.3) == -1.0);
112 expect(trunc128(0.2) == 0.0);
113}
114
86test "math.trunc32.special" {115test "math.trunc32.special" {
87 expect(trunc32(0.0) == 0.0); // 0x3F800000116 expect(trunc32(0.0) == 0.0); // 0x3F800000
88 expect(trunc32(-0.0) == -0.0);117 expect(trunc32(-0.0) == -0.0);
...@@ -98,3 +127,11 @@ test "math.trunc64.special" {...@@ -98,3 +127,11 @@ test "math.trunc64.special" {
98 expect(math.isNegativeInf(trunc64(-math.inf(f64))));127 expect(math.isNegativeInf(trunc64(-math.inf(f64))));
99 expect(math.isNan(trunc64(math.nan(f64))));128 expect(math.isNan(trunc64(math.nan(f64))));
100}129}
130
131test "math.trunc128.special" {
132 expect(trunc128(0.0) == 0.0);
133 expect(trunc128(-0.0) == -0.0);
134 expect(math.isPositiveInf(trunc128(math.inf(f128))));
135 expect(math.isNegativeInf(trunc128(-math.inf(f128))));
136 expect(math.isNan(trunc128(math.nan(f128))));
137}
lib/std/meta.zig+88-6
...@@ -250,7 +250,7 @@ test "std.meta.containerLayout" {...@@ -250,7 +250,7 @@ test "std.meta.containerLayout" {
250 testing.expect(containerLayout(U3) == .Extern);250 testing.expect(containerLayout(U3) == .Extern);
251}251}
252252
253pub fn declarations(comptime T: type) []TypeInfo.Declaration {253pub fn declarations(comptime T: type) []const TypeInfo.Declaration {
254 return switch (@typeInfo(T)) {254 return switch (@typeInfo(T)) {
255 .Struct => |info| info.decls,255 .Struct => |info| info.decls,
256 .Enum => |info| info.decls,256 .Enum => |info| info.decls,
...@@ -274,7 +274,7 @@ test "std.meta.declarations" {...@@ -274,7 +274,7 @@ test "std.meta.declarations" {
274 fn a() void {}274 fn a() void {}
275 };275 };
276276
277 const decls = comptime [_][]TypeInfo.Declaration{277 const decls = comptime [_][]const TypeInfo.Declaration{
278 declarations(E1),278 declarations(E1),
279 declarations(S1),279 declarations(S1),
280 declarations(U1),280 declarations(U1),
...@@ -323,10 +323,10 @@ test "std.meta.declarationInfo" {...@@ -323,10 +323,10 @@ test "std.meta.declarationInfo" {
323}323}
324324
325pub fn fields(comptime T: type) switch (@typeInfo(T)) {325pub fn fields(comptime T: type) switch (@typeInfo(T)) {
326 .Struct => []TypeInfo.StructField,326 .Struct => []const TypeInfo.StructField,
327 .Union => []TypeInfo.UnionField,327 .Union => []const TypeInfo.UnionField,
328 .ErrorSet => []TypeInfo.Error,328 .ErrorSet => []const TypeInfo.Error,
329 .Enum => []TypeInfo.EnumField,329 .Enum => []const TypeInfo.EnumField,
330 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),330 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
331} {331} {
332 return switch (@typeInfo(T)) {332 return switch (@typeInfo(T)) {
...@@ -693,3 +693,85 @@ pub fn Vector(comptime len: u32, comptime child: type) type {...@@ -693,3 +693,85 @@ pub fn Vector(comptime len: u32, comptime child: type) type {
693 },693 },
694 });694 });
695}695}
696
697/// Given a type and value, cast the value to the type as c would.
698/// This is for translate-c and is not intended for general use.
699pub fn cast(comptime DestType: type, target: var) DestType {
700 const TargetType = @TypeOf(target);
701 switch (@typeInfo(DestType)) {
702 .Pointer => {
703 switch (@typeInfo(TargetType)) {
704 .Int, .ComptimeInt => {
705 return @intToPtr(DestType, target);
706 },
707 .Pointer => |ptr| {
708 return @ptrCast(DestType, @alignCast(ptr.alignment, target));
709 },
710 .Optional => |opt| {
711 if (@typeInfo(opt.child) == .Pointer) {
712 return @ptrCast(DestType, @alignCast(@alignOf(opt.child.Child), target));
713 }
714 },
715 else => {},
716 }
717 },
718 .Optional => |opt| {
719 if (@typeInfo(opt.child) == .Pointer) {
720 switch (@typeInfo(TargetType)) {
721 .Int, .ComptimeInt => {
722 return @intToPtr(DestType, target);
723 },
724 .Pointer => |ptr| {
725 return @ptrCast(DestType, @alignCast(ptr.alignment, target));
726 },
727 .Optional => |target_opt| {
728 if (@typeInfo(target_opt.child) == .Pointer) {
729 return @ptrCast(DestType, @alignCast(@alignOf(target_opt.child.Child), target));
730 }
731 },
732 else => {},
733 }
734 }
735 },
736 .Enum, .EnumLiteral => {
737 if (@typeInfo(TargetType) == .Int or @typeInfo(TargetType) == .ComptimeInt) {
738 return @intToEnum(DestType, target);
739 }
740 },
741 .Int, .ComptimeInt => {
742 switch (@typeInfo(TargetType)) {
743 .Pointer => {
744 return @as(DestType, @ptrToInt(target));
745 },
746 .Optional => |opt| {
747 if (@typeInfo(opt.child) == .Pointer) {
748 return @as(DestType, @ptrToInt(target));
749 }
750 },
751 .Enum, .EnumLiteral => {
752 return @as(DestType, @enumToInt(target));
753 },
754 else => {},
755 }
756 },
757 else => {},
758 }
759 return @as(DestType, target);
760}
761
762test "std.meta.cast" {
763 const E = enum(u2) {
764 Zero,
765 One,
766 Two,
767 };
768
769 var i = @as(i64, 10);
770
771 testing.expect(cast(?*c_void, 0) == @intToPtr(?*c_void, 0));
772 testing.expect(cast(*u8, 16) == @intToPtr(*u8, 16));
773 testing.expect(cast(u64, @as(u32, 10)) == @as(u64, 10));
774 testing.expect(cast(E, 1) == .One);
775 testing.expect(cast(u8, E.Two) == 2);
776 testing.expect(cast(*u64, &i).* == @as(u64, 10));
777}
lib/std/os.zig+100-6
...@@ -1520,15 +1520,17 @@ pub const SymLinkError = error{...@@ -1520,15 +1520,17 @@ pub const SymLinkError = error{
1520/// If `sym_link_path` exists, it will not be overwritten.1520/// If `sym_link_path` exists, it will not be overwritten.
1521/// See also `symlinkC` and `symlinkW`.1521/// See also `symlinkC` and `symlinkW`.
1522pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void {1522pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void {
1523 if (builtin.os.tag == .wasi) {
1524 @compileError("symlink is not supported in WASI; use symlinkat instead");
1525 }
1523 if (builtin.os.tag == .windows) {1526 if (builtin.os.tag == .windows) {
1524 const target_path_w = try windows.sliceToPrefixedFileW(target_path);1527 const target_path_w = try windows.sliceToPrefixedFileW(target_path);
1525 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);1528 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
1526 return windows.CreateSymbolicLinkW(sym_link_path_w.span().ptr, target_path_w.span().ptr, 0);1529 return windows.CreateSymbolicLinkW(sym_link_path_w.span().ptr, target_path_w.span().ptr, 0);
1527 } else {
1528 const target_path_c = try toPosixPath(target_path);
1529 const sym_link_path_c = try toPosixPath(sym_link_path);
1530 return symlinkZ(&target_path_c, &sym_link_path_c);
1531 }1530 }
1531 const target_path_c = try toPosixPath(target_path);
1532 const sym_link_path_c = try toPosixPath(sym_link_path);
1533 return symlinkZ(&target_path_c, &sym_link_path_c);
1532}1534}
15331535
1534pub const symlinkC = @compileError("deprecated: renamed to symlinkZ");1536pub const symlinkC = @compileError("deprecated: renamed to symlinkZ");
...@@ -1561,15 +1563,65 @@ pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLin...@@ -1561,15 +1563,65 @@ pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLin
1561 }1563 }
1562}1564}
15631565
1566/// Similar to `symlink`, however, creates a symbolic link named `sym_link_path` which contains the string
1567/// `target_path` **relative** to `newdirfd` directory handle.
1568/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent
1569/// one; the latter case is known as a dangling link.
1570/// If `sym_link_path` exists, it will not be overwritten.
1571/// See also `symlinkatWasi`, `symlinkatZ` and `symlinkatW`.
1564pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkError!void {1572pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkError!void {
1573 if (builtin.os.tag == .wasi) {
1574 return symlinkatWasi(target_path, newdirfd, sym_link_path);
1575 }
1576 if (builtin.os.tag == .windows) {
1577 const target_path_w = try windows.sliceToPrefixedFileW(target_path);
1578 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
1579 return symlinkatW(target_path_w.span().ptr, newdirfd, sym_link_path_w.span().ptr);
1580 }
1565 const target_path_c = try toPosixPath(target_path);1581 const target_path_c = try toPosixPath(target_path);
1566 const sym_link_path_c = try toPosixPath(sym_link_path);1582 const sym_link_path_c = try toPosixPath(sym_link_path);
1567 return symlinkatZ(target_path_c, newdirfd, sym_link_path_c);1583 return symlinkatZ(&target_path_c, newdirfd, &sym_link_path_c);
1568}1584}
15691585
1570pub const symlinkatC = @compileError("deprecated: renamed to symlinkatZ");1586pub const symlinkatC = @compileError("deprecated: renamed to symlinkatZ");
15711587
1588/// WASI-only. The same as `symlinkat` but targeting WASI.
1589/// See also `symlinkat`.
1590pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkError!void {
1591 switch (wasi.path_symlink(target_path.ptr, target_path.len, newdirfd, sym_link_path.ptr, sym_link_path.len)) {
1592 wasi.ESUCCESS => {},
1593 wasi.EFAULT => unreachable,
1594 wasi.EINVAL => unreachable,
1595 wasi.EACCES => return error.AccessDenied,
1596 wasi.EPERM => return error.AccessDenied,
1597 wasi.EDQUOT => return error.DiskQuota,
1598 wasi.EEXIST => return error.PathAlreadyExists,
1599 wasi.EIO => return error.FileSystem,
1600 wasi.ELOOP => return error.SymLinkLoop,
1601 wasi.ENAMETOOLONG => return error.NameTooLong,
1602 wasi.ENOENT => return error.FileNotFound,
1603 wasi.ENOTDIR => return error.NotDir,
1604 wasi.ENOMEM => return error.SystemResources,
1605 wasi.ENOSPC => return error.NoSpaceLeft,
1606 wasi.EROFS => return error.ReadOnlyFileSystem,
1607 else => |err| return unexpectedErrno(err),
1608 }
1609}
1610
1611/// Windows-only. The same as `symlinkat` except the paths are null-terminated, WTF-16 encoded.
1612/// See also `symlinkat`.
1613pub fn symlinkatW(target_path: [*:0]const u16, newdirfd: fd_t, sym_link_path: [*:0]const u16) SymlinkError!void {
1614 @compileError("TODO implement on Windows");
1615}
1616
1617/// The same as `symlinkat` except the parameters are null-terminated pointers.
1618/// See also `symlinkat`.
1572pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:0]const u8) SymLinkError!void {1619pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:0]const u8) SymLinkError!void {
1620 if (builtin.os.tag == .windows) {
1621 const target_path_w = try windows.cStrToPrefixedFileW(target_path);
1622 const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);
1623 return symlinkatW(target_path_w.span().ptr, newdirfd, sym_link_path.span().ptr);
1624 }
1573 switch (errno(system.symlinkat(target_path, newdirfd, sym_link_path))) {1625 switch (errno(system.symlinkat(target_path, newdirfd, sym_link_path))) {
1574 0 => return,1626 0 => return,
1575 EFAULT => unreachable,1627 EFAULT => unreachable,
...@@ -2291,12 +2343,54 @@ pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8...@@ -2291,12 +2343,54 @@ pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8
2291 }2343 }
2292}2344}
22932345
2346/// Similar to `readlink` except reads value of a symbolink link **relative** to `dirfd` directory handle.
2347/// The return value is a slice of `out_buffer` from index 0.
2348/// See also `readlinkatWasi`, `realinkatZ` and `realinkatW`.
2349pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
2350 if (builtin.os.tag == .wasi) {
2351 return readlinkatWasi(dirfd, file_path, out_buffer);
2352 }
2353 if (builtin.os.tag == .windows) {
2354 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
2355 return readlinkatW(dirfd, file_path.span().ptr, out_buffer);
2356 }
2357 const file_path_c = try toPosixPath(file_path);
2358 return readlinkatZ(dirfd, &file_path_c, out_buffer);
2359}
2360
2294pub const readlinkatC = @compileError("deprecated: renamed to readlinkatZ");2361pub const readlinkatC = @compileError("deprecated: renamed to readlinkatZ");
22952362
2363/// WASI-only. Same as `readlinkat` but targets WASI.
2364/// See also `readlinkat`.
2365pub fn readlinkatWasi(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
2366 var bufused: usize = undefined;
2367 switch (wasi.path_readlink(dirfd, file_path.ptr, file_path.len, out_buffer.ptr, out_buffer.len, &bufused)) {
2368 wasi.ESUCCESS => return out_buffer[0..bufused],
2369 wasi.EACCES => return error.AccessDenied,
2370 wasi.EFAULT => unreachable,
2371 wasi.EINVAL => unreachable,
2372 wasi.EIO => return error.FileSystem,
2373 wasi.ELOOP => return error.SymLinkLoop,
2374 wasi.ENAMETOOLONG => return error.NameTooLong,
2375 wasi.ENOENT => return error.FileNotFound,
2376 wasi.ENOMEM => return error.SystemResources,
2377 wasi.ENOTDIR => return error.NotDir,
2378 else => |err| return unexpectedErrno(err),
2379 }
2380}
2381
2382/// Windows-only. Same as `readlinkat` except `file_path` is null-terminated, WTF16 encoded.
2383/// See also `readlinkat`.
2384pub fn readlinkatW(dirfd: fd_t, file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8 {
2385 @compileError("TODO implement on Windows");
2386}
2387
2388/// Same as `readlinkat` except `file_path` is null-terminated.
2389/// See also `readlinkat`.
2296pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {2390pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
2297 if (builtin.os.tag == .windows) {2391 if (builtin.os.tag == .windows) {
2298 const file_path_w = try windows.cStrToPrefixedFileW(file_path);2392 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
2299 @compileError("TODO implement readlink for Windows");2393 return readlinkatW(dirfd, file_path_w.span().ptr, out_buffer);
2300 }2394 }
2301 const rc = system.readlinkat(dirfd, file_path, out_buffer.ptr, out_buffer.len);2395 const rc = system.readlinkat(dirfd, file_path, out_buffer.ptr, out_buffer.len);
2302 switch (errno(rc)) {2396 switch (errno(rc)) {
lib/std/os/test.zig+19
...@@ -18,6 +18,25 @@ const AtomicOrder = builtin.AtomicOrder;...@@ -18,6 +18,25 @@ const AtomicOrder = builtin.AtomicOrder;
18const tmpDir = std.testing.tmpDir;18const tmpDir = std.testing.tmpDir;
19const Dir = std.fs.Dir;19const Dir = std.fs.Dir;
2020
21test "readlinkat" {
22 // enable when `readlinkat` and `symlinkat` are implemented on Windows
23 if (builtin.os.tag == .windows) return error.SkipZigTest;
24
25 var tmp = tmpDir(.{});
26 defer tmp.cleanup();
27
28 // create file
29 try tmp.dir.writeFile("file.txt", "nonsense");
30
31 // create a symbolic link
32 try os.symlinkat("file.txt", tmp.dir.fd, "link");
33
34 // read the link
35 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
36 const read_link = try os.readlinkat(tmp.dir.fd, "link", buffer[0..]);
37 expect(mem.eql(u8, "file.txt", read_link));
38}
39
21test "makePath, put some files in it, deleteTree" {40test "makePath, put some files in it, deleteTree" {
22 var tmp = tmpDir(.{});41 var tmp = tmpDir(.{});
23 defer tmp.cleanup();42 defer tmp.cleanup();
lib/std/os/windows.zig+10-1
...@@ -901,7 +901,13 @@ pub fn WSAStartup(majorVersion: u8, minorVersion: u8) !ws2_32.WSADATA {...@@ -901,7 +901,13 @@ pub fn WSAStartup(majorVersion: u8, minorVersion: u8) !ws2_32.WSADATA {
901 var wsadata: ws2_32.WSADATA = undefined;901 var wsadata: ws2_32.WSADATA = undefined;
902 return switch (ws2_32.WSAStartup((@as(WORD, minorVersion) << 8) | majorVersion, &wsadata)) {902 return switch (ws2_32.WSAStartup((@as(WORD, minorVersion) << 8) | majorVersion, &wsadata)) {
903 0 => wsadata,903 0 => wsadata,
904 else => |err| unexpectedWSAError(@intToEnum(ws2_32.WinsockError, @intCast(u16, err))),904 else => |err_int| switch (@intToEnum(ws2_32.WinsockError, @intCast(u16, err_int))) {
905 .WSASYSNOTREADY => return error.SystemNotAvailable,
906 .WSAVERNOTSUPPORTED => return error.VersionNotSupported,
907 .WSAEINPROGRESS => return error.BlockingOperationInProgress,
908 .WSAEPROCLIM => return error.SystemResources,
909 else => |err| return unexpectedWSAError(err),
910 },
905 };911 };
906}912}
907913
...@@ -909,6 +915,9 @@ pub fn WSACleanup() !void {...@@ -909,6 +915,9 @@ pub fn WSACleanup() !void {
909 return switch (ws2_32.WSACleanup()) {915 return switch (ws2_32.WSACleanup()) {
910 0 => {},916 0 => {},
911 ws2_32.SOCKET_ERROR => switch (ws2_32.WSAGetLastError()) {917 ws2_32.SOCKET_ERROR => switch (ws2_32.WSAGetLastError()) {
918 .WSANOTINITIALISED => return error.NotInitialized,
919 .WSAENETDOWN => return error.NetworkNotAvailable,
920 .WSAEINPROGRESS => return error.BlockingOperationInProgress,
912 else => |err| return unexpectedWSAError(err),921 else => |err| return unexpectedWSAError(err),
913 },922 },
914 else => unreachable,923 else => unreachable,
lib/std/os/windows/ws2_32.zig+9-9
...@@ -163,16 +163,16 @@ pub const IPPROTO_UDP = 17;...@@ -163,16 +163,16 @@ pub const IPPROTO_UDP = 17;
163pub const IPPROTO_ICMPV6 = 58;163pub const IPPROTO_ICMPV6 = 58;
164pub const IPPROTO_RM = 113;164pub const IPPROTO_RM = 113;
165165
166pub const AI_PASSIVE = 0x00001;166pub const AI_PASSIVE = 0x00001;
167pub const AI_CANONNAME = 0x00002;167pub const AI_CANONNAME = 0x00002;
168pub const AI_NUMERICHOST = 0x00004;168pub const AI_NUMERICHOST = 0x00004;
169pub const AI_NUMERICSERV = 0x00008;169pub const AI_NUMERICSERV = 0x00008;
170pub const AI_ADDRCONFIG = 0x00400;170pub const AI_ADDRCONFIG = 0x00400;
171pub const AI_V4MAPPED = 0x00800;171pub const AI_V4MAPPED = 0x00800;
172pub const AI_NON_AUTHORITATIVE = 0x04000;172pub const AI_NON_AUTHORITATIVE = 0x04000;
173pub const AI_SECURE = 0x08000;173pub const AI_SECURE = 0x08000;
174pub const AI_RETURN_PREFERRED_NAMES = 0x10000;174pub const AI_RETURN_PREFERRED_NAMES = 0x10000;
175pub const AI_DISABLE_IDN_ENCODING = 0x80000;175pub const AI_DISABLE_IDN_ENCODING = 0x80000;
176176
177pub const FIONBIO = -2147195266;177pub const FIONBIO = -2147195266;
178178
lib/std/process.zig+7-34
...@@ -281,9 +281,6 @@ pub const ArgIteratorWasi = struct {...@@ -281,9 +281,6 @@ pub const ArgIteratorWasi = struct {
281pub const ArgIteratorWindows = struct {281pub const ArgIteratorWindows = struct {
282 index: usize,282 index: usize,
283 cmd_line: [*]const u8,283 cmd_line: [*]const u8,
284 in_quote: bool,
285 quote_count: usize,
286 seen_quote_count: usize,
287284
288 pub const NextError = error{OutOfMemory};285 pub const NextError = error{OutOfMemory};
289286
...@@ -295,9 +292,6 @@ pub const ArgIteratorWindows = struct {...@@ -295,9 +292,6 @@ pub const ArgIteratorWindows = struct {
295 return ArgIteratorWindows{292 return ArgIteratorWindows{
296 .index = 0,293 .index = 0,
297 .cmd_line = cmd_line,294 .cmd_line = cmd_line,
298 .in_quote = false,
299 .quote_count = countQuotes(cmd_line),
300 .seen_quote_count = 0,
301 };295 };
302 }296 }
303297
...@@ -328,6 +322,7 @@ pub const ArgIteratorWindows = struct {...@@ -328,6 +322,7 @@ pub const ArgIteratorWindows = struct {
328 }322 }
329323
330 var backslash_count: usize = 0;324 var backslash_count: usize = 0;
325 var in_quote = false;
331 while (true) : (self.index += 1) {326 while (true) : (self.index += 1) {
332 const byte = self.cmd_line[self.index];327 const byte = self.cmd_line[self.index];
333 switch (byte) {328 switch (byte) {
...@@ -335,14 +330,14 @@ pub const ArgIteratorWindows = struct {...@@ -335,14 +330,14 @@ pub const ArgIteratorWindows = struct {
335 '"' => {330 '"' => {
336 const quote_is_real = backslash_count % 2 == 0;331 const quote_is_real = backslash_count % 2 == 0;
337 if (quote_is_real) {332 if (quote_is_real) {
338 self.seen_quote_count += 1;333 in_quote = !in_quote;
339 }334 }
340 },335 },
341 '\\' => {336 '\\' => {
342 backslash_count += 1;337 backslash_count += 1;
343 },338 },
344 ' ', '\t' => {339 ' ', '\t' => {
345 if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {340 if (!in_quote) {
346 return true;341 return true;
347 }342 }
348 backslash_count = 0;343 backslash_count = 0;
...@@ -360,6 +355,7 @@ pub const ArgIteratorWindows = struct {...@@ -360,6 +355,7 @@ pub const ArgIteratorWindows = struct {
360 defer buf.deinit();355 defer buf.deinit();
361356
362 var backslash_count: usize = 0;357 var backslash_count: usize = 0;
358 var in_quote = false;
363 while (true) : (self.index += 1) {359 while (true) : (self.index += 1) {
364 const byte = self.cmd_line[self.index];360 const byte = self.cmd_line[self.index];
365 switch (byte) {361 switch (byte) {
...@@ -370,10 +366,7 @@ pub const ArgIteratorWindows = struct {...@@ -370,10 +366,7 @@ pub const ArgIteratorWindows = struct {
370 backslash_count = 0;366 backslash_count = 0;
371367
372 if (quote_is_real) {368 if (quote_is_real) {
373 self.seen_quote_count += 1;369 in_quote = !in_quote;
374 if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
375 try buf.append('"');
376 }
377 } else {370 } else {
378 try buf.append('"');371 try buf.append('"');
379 }372 }
...@@ -384,7 +377,7 @@ pub const ArgIteratorWindows = struct {...@@ -384,7 +377,7 @@ pub const ArgIteratorWindows = struct {
384 ' ', '\t' => {377 ' ', '\t' => {
385 try self.emitBackslashes(&buf, backslash_count);378 try self.emitBackslashes(&buf, backslash_count);
386 backslash_count = 0;379 backslash_count = 0;
387 if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {380 if (in_quote) {
388 try buf.append(byte);381 try buf.append(byte);
389 } else {382 } else {
390 return buf.toOwnedSlice();383 return buf.toOwnedSlice();
...@@ -405,26 +398,6 @@ pub const ArgIteratorWindows = struct {...@@ -405,26 +398,6 @@ pub const ArgIteratorWindows = struct {
405 try buf.append('\\');398 try buf.append('\\');
406 }399 }
407 }400 }
408
409 fn countQuotes(cmd_line: [*]const u8) usize {
410 var result: usize = 0;
411 var backslash_count: usize = 0;
412 var index: usize = 0;
413 while (true) : (index += 1) {
414 const byte = cmd_line[index];
415 switch (byte) {
416 0 => return result,
417 '\\' => backslash_count += 1,
418 '"' => {
419 result += 1 - (backslash_count % 2);
420 backslash_count = 0;
421 },
422 else => {
423 backslash_count = 0;
424 },
425 }
426 }
427 }
428};401};
429402
430pub const ArgIterator = struct {403pub const ArgIterator = struct {
...@@ -578,7 +551,7 @@ test "windows arg parsing" {...@@ -578,7 +551,7 @@ test "windows arg parsing" {
578 testWindowsCmdLine("a\\\\\\b d\"e f\"g h", &[_][]const u8{ "a\\\\\\b", "de fg", "h" });551 testWindowsCmdLine("a\\\\\\b d\"e f\"g h", &[_][]const u8{ "a\\\\\\b", "de fg", "h" });
579 testWindowsCmdLine("a\\\\\\\"b c d", &[_][]const u8{ "a\\\"b", "c", "d" });552 testWindowsCmdLine("a\\\\\\\"b c d", &[_][]const u8{ "a\\\"b", "c", "d" });
580 testWindowsCmdLine("a\\\\\\\\\"b c\" d e", &[_][]const u8{ "a\\\\b c", "d", "e" });553 testWindowsCmdLine("a\\\\\\\\\"b c\" d e", &[_][]const u8{ "a\\\\b c", "d", "e" });
581 testWindowsCmdLine("a b\tc \"d f", &[_][]const u8{ "a", "b", "c", "\"d", "f" });554 testWindowsCmdLine("a b\tc \"d f", &[_][]const u8{ "a", "b", "c", "d f" });
582555
583 testWindowsCmdLine("\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", &[_][]const u8{556 testWindowsCmdLine("\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", &[_][]const u8{
584 ".\\..\\zig-cache\\build",557 ".\\..\\zig-cache\\build",
lib/std/std.zig+1
...@@ -49,6 +49,7 @@ pub const heap = @import("heap.zig");...@@ -49,6 +49,7 @@ pub const heap = @import("heap.zig");
49pub const http = @import("http.zig");49pub const http = @import("http.zig");
50pub const io = @import("io.zig");50pub const io = @import("io.zig");
51pub const json = @import("json.zig");51pub const json = @import("json.zig");
52pub const log = @import("log.zig");
52pub const macho = @import("macho.zig");53pub const macho = @import("macho.zig");
53pub const math = @import("math.zig");54pub const math = @import("math.zig");
54pub const mem = @import("mem.zig");55pub const mem = @import("mem.zig");
lib/std/unicode.zig+41
...@@ -235,6 +235,22 @@ pub const Utf8Iterator = struct {...@@ -235,6 +235,22 @@ pub const Utf8Iterator = struct {
235 else => unreachable,235 else => unreachable,
236 }236 }
237 }237 }
238
239 /// Look ahead at the next n codepoints without advancing the iterator.
240 /// If fewer than n codepoints are available, then return the remainder of the string.
241 pub fn peek(it: *Utf8Iterator, n: usize) []const u8 {
242 const original_i = it.i;
243 defer it.i = original_i;
244
245 var end_ix = original_i;
246 var found: usize = 0;
247 while (found < n) : (found += 1) {
248 const next_codepoint = it.nextCodepointSlice() orelse return it.bytes[original_i..];
249 end_ix += next_codepoint.len;
250 }
251
252 return it.bytes[original_i..end_ix];
253 }
238};254};
239255
240pub const Utf16LeIterator = struct {256pub const Utf16LeIterator = struct {
...@@ -451,6 +467,31 @@ fn testMiscInvalidUtf8() void {...@@ -451,6 +467,31 @@ fn testMiscInvalidUtf8() void {
451 testValid("\xee\x80\x80", 0xe000);467 testValid("\xee\x80\x80", 0xe000);
452}468}
453469
470test "utf8 iterator peeking" {
471 comptime testUtf8Peeking();
472 testUtf8Peeking();
473}
474
475fn testUtf8Peeking() void {
476 const s = Utf8View.initComptime("noël");
477 var it = s.iterator();
478
479 testing.expect(std.mem.eql(u8, "n", it.nextCodepointSlice().?));
480
481 testing.expect(std.mem.eql(u8, "o", it.peek(1)));
482 testing.expect(std.mem.eql(u8, "oë", it.peek(2)));
483 testing.expect(std.mem.eql(u8, "oël", it.peek(3)));
484 testing.expect(std.mem.eql(u8, "oël", it.peek(4)));
485 testing.expect(std.mem.eql(u8, "oël", it.peek(10)));
486
487 testing.expect(std.mem.eql(u8, "o", it.nextCodepointSlice().?));
488 testing.expect(std.mem.eql(u8, "ë", it.nextCodepointSlice().?));
489 testing.expect(std.mem.eql(u8, "l", it.nextCodepointSlice().?));
490 testing.expect(it.nextCodepointSlice() == null);
491
492 testing.expect(std.mem.eql(u8, &[_]u8{}, it.peek(1)));
493}
494
454fn testError(bytes: []const u8, expected_err: anyerror) void {495fn testError(bytes: []const u8, expected_err: anyerror) void {
455 testing.expectError(expected_err, testDecode(bytes));496 testing.expectError(expected_err, testDecode(bytes));
456}497}
lib/std/zig/parse.zig-1
...@@ -937,7 +937,6 @@ const Parser = struct {...@@ -937,7 +937,6 @@ const Parser = struct {
937 return node;937 return node;
938 }938 }
939939
940
941 while_prefix.body = try p.expectNode(parseAssignExpr, .{940 while_prefix.body = try p.expectNode(parseAssignExpr, .{
942 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },941 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
943 });942 });
src-self-hosted/main.zig+93-43
...@@ -546,8 +546,9 @@ const Fmt = struct {...@@ -546,8 +546,9 @@ const Fmt = struct {
546 any_error: bool,546 any_error: bool,
547 color: Color,547 color: Color,
548 gpa: *Allocator,548 gpa: *Allocator,
549 out_buffer: std.ArrayList(u8),
549550
550 const SeenMap = std.BufSet;551 const SeenMap = std.AutoHashMap(fs.File.INode, void);
551};552};
552553
553pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {554pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
...@@ -641,10 +642,20 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {...@@ -641,10 +642,20 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
641 .seen = Fmt.SeenMap.init(gpa),642 .seen = Fmt.SeenMap.init(gpa),
642 .any_error = false,643 .any_error = false,
643 .color = color,644 .color = color,
645 .out_buffer = std.ArrayList(u8).init(gpa),
644 };646 };
647 defer fmt.seen.deinit();
648 defer fmt.out_buffer.deinit();
645649
646 for (input_files.span()) |file_path| {650 for (input_files.span()) |file_path| {
647 try fmtPath(&fmt, file_path, check_flag);651 // Get the real path here to avoid Windows failing on relative file paths with . or .. in them.
652 const real_path = fs.realpathAlloc(gpa, file_path) catch |err| {
653 std.debug.warn("unable to open '{}': {}\n", .{ file_path, err });
654 process.exit(1);
655 };
656 defer gpa.free(real_path);
657
658 try fmtPath(&fmt, file_path, check_flag, fs.cwd(), real_path);
648 }659 }
649 if (fmt.any_error) {660 if (fmt.any_error) {
650 process.exit(1);661 process.exit(1);
...@@ -670,48 +681,82 @@ const FmtError = error{...@@ -670,48 +681,82 @@ const FmtError = error{
670 ReadOnlyFileSystem,681 ReadOnlyFileSystem,
671 LinkQuotaExceeded,682 LinkQuotaExceeded,
672 FileBusy,683 FileBusy,
684 EndOfStream,
673} || fs.File.OpenError;685} || fs.File.OpenError;
674686
675fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {687fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
676 // get the real path here to avoid Windows failing on relative file paths with . or .. in them688 fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
677 var real_path = fs.realpathAlloc(fmt.gpa, file_path) catch |err| {689 error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
678 std.debug.warn("unable to open '{}': {}\n", .{ file_path, err });
679 fmt.any_error = true;
680 return;
681 };
682 defer fmt.gpa.free(real_path);
683
684 if (fmt.seen.exists(real_path)) return;
685 try fmt.seen.put(real_path);
686
687 const source_code = fs.cwd().readFileAlloc(fmt.gpa, real_path, max_src_size) catch |err| switch (err) {
688 error.IsDir, error.AccessDenied => {
689 var dir = try fs.cwd().openDir(file_path, .{ .iterate = true });
690 defer dir.close();
691
692 var dir_it = dir.iterate();
693
694 while (try dir_it.next()) |entry| {
695 if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) {
696 const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
697 try fmtPath(fmt, full_path, check_mode);
698 }
699 }
700 return;
701 },
702 else => {690 else => {
703 std.debug.warn("unable to open '{}': {}\n", .{ file_path, err });691 std.debug.warn("unable to format '{}': {}\n", .{ file_path, err });
704 fmt.any_error = true;692 fmt.any_error = true;
705 return;693 return;
706 },694 },
707 };695 };
708 defer fmt.gpa.free(source_code);696}
709697
710 const tree = std.zig.parse(fmt.gpa, source_code) catch |err| {698fn fmtPathDir(
711 std.debug.warn("error parsing file '{}': {}\n", .{ file_path, err });699 fmt: *Fmt,
712 fmt.any_error = true;700 file_path: []const u8,
713 return;701 check_mode: bool,
702 parent_dir: fs.Dir,
703 parent_sub_path: []const u8,
704) FmtError!void {
705 var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
706 defer dir.close();
707
708 const stat = try dir.stat();
709 if (try fmt.seen.put(stat.inode, {})) |_| return;
710
711 var dir_it = dir.iterate();
712 while (try dir_it.next()) |entry| {
713 const is_dir = entry.kind == .Directory;
714 if (is_dir or mem.endsWith(u8, entry.name, ".zig")) {
715 const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
716 defer fmt.gpa.free(full_path);
717
718 if (is_dir) {
719 try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
720 } else {
721 fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
722 std.debug.warn("unable to format '{}': {}\n", .{ full_path, err });
723 fmt.any_error = true;
724 return;
725 };
726 }
727 }
728 }
729}
730
731fn fmtPathFile(
732 fmt: *Fmt,
733 file_path: []const u8,
734 check_mode: bool,
735 dir: fs.Dir,
736 sub_path: []const u8,
737) FmtError!void {
738 const source_file = try dir.openFile(sub_path, .{});
739 var file_closed = false;
740 errdefer if (!file_closed) source_file.close();
741
742 const stat = try source_file.stat();
743
744 if (stat.kind == .Directory)
745 return error.IsDir;
746
747 const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) {
748 error.ConnectionResetByPeer => unreachable,
749 error.ConnectionTimedOut => unreachable,
750 else => |e| return e,
714 };751 };
752 source_file.close();
753 file_closed = true;
754 defer fmt.gpa.free(source_code);
755
756 // Add to set after no longer possible to get error.IsDir.
757 if (try fmt.seen.put(stat.inode, {})) |_| return;
758
759 const tree = try std.zig.parse(fmt.gpa, source_code);
715 defer tree.deinit();760 defer tree.deinit();
716761
717 for (tree.errors) |parse_error| {762 for (tree.errors) |parse_error| {
...@@ -729,14 +774,19 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {...@@ -729,14 +774,19 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
729 fmt.any_error = true;774 fmt.any_error = true;
730 }775 }
731 } else {776 } else {
732 const baf = try io.BufferedAtomicFile.create(fmt.gpa, fs.cwd(), real_path, .{});777 // As a heuristic, we make enough capacity for the same as the input source.
733 defer baf.destroy();778 try fmt.out_buffer.ensureCapacity(source_code.len);
734779 fmt.out_buffer.items.len = 0;
735 const anything_changed = try std.zig.render(fmt.gpa, baf.stream(), tree);780 const anything_changed = try std.zig.render(fmt.gpa, fmt.out_buffer.writer(), tree);
736 if (anything_changed) {781 if (!anything_changed)
737 std.debug.warn("{}\n", .{file_path});782 return; // Good thing we didn't waste any file system access on this.
738 try baf.finish();783
739 }784 var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
785 defer af.deinit();
786
787 try af.file.writeAll(fmt.out_buffer.items);
788 try af.finish();
789 std.debug.warn("{}\n", .{file_path});
740 }790 }
741}791}
742792
src-self-hosted/translate_c.zig+13-151
...@@ -5668,161 +5668,23 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5668,161 +5668,23 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56685668
5669 const lparen = try appendToken(c, .LParen, "(");5669 const lparen = try appendToken(c, .LParen, "(");
56705670
5671 if (saw_integer_literal) {5671 //(@import("std").meta.cast(dest, x))
5672 //( if (@typeInfo(dest) == .Pointer))5672 const import_fn_call = try c.createBuiltinCall("@import", 1);
5673 // @intToPtr(dest, x)5673 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
5674 //else5674 import_fn_call.params()[0] = std_node;
5675 // @as(dest, x) )5675 import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
5676 const if_node = try transCreateNodeIf(c);5676 const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "meta");
5677 const type_info_node = try c.createBuiltinCall("@typeInfo", 1);5677 const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "cast");
5678 type_info_node.params()[0] = inner_node;5678
5679 type_info_node.rparen_token = try appendToken(c, .LParen, ")");5679 const cast_fn_call = try c.createCall(outer_field_access, 2);
5680 const cmp_node = try c.arena.create(ast.Node.InfixOp);5680 cast_fn_call.params()[0] = inner_node;
5681 cmp_node.* = .{5681 cast_fn_call.params()[1] = node_to_cast;
5682 .op_token = try appendToken(c, .EqualEqual, "=="),5682 cast_fn_call.rtoken = try appendToken(c, .RParen, ")");
5683 .lhs = &type_info_node.base,
5684 .op = .EqualEqual,
5685 .rhs = try transCreateNodeEnumLiteral(c, "Pointer"),
5686 };
5687 if_node.condition = &cmp_node.base;
5688 _ = try appendToken(c, .RParen, ")");
5689
5690 const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2);
5691 int_to_ptr.params()[0] = inner_node;
5692 int_to_ptr.params()[1] = node_to_cast;
5693 int_to_ptr.rparen_token = try appendToken(c, .RParen, ")");
5694 if_node.body = &int_to_ptr.base;
5695
5696 const else_node = try transCreateNodeElse(c);
5697 if_node.@"else" = else_node;
5698
5699 const as_node = try c.createBuiltinCall("@as", 2);
5700 as_node.params()[0] = inner_node;
5701 as_node.params()[1] = node_to_cast;
5702 as_node.rparen_token = try appendToken(c, .RParen, ")");
5703 else_node.body = &as_node.base;
5704
5705 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5706 group_node.* = .{
5707 .lparen = lparen,
5708 .expr = &if_node.base,
5709 .rparen = try appendToken(c, .RParen, ")"),
5710 };
5711 return &group_node.base;
5712 }
5713
5714 //( if (@typeInfo(@TypeOf(x)) == .Pointer)
5715 // @ptrCast(dest, @alignCast(@alignOf(dest.Child), x))
5716 //else if (@typeInfo(@TypeOf(x)) == .Int and @typeInfo(dest) == .Pointer))
5717 // @intToPtr(dest, x)
5718 //else
5719 // @as(dest, x) )
5720
5721 const if_1 = try transCreateNodeIf(c);
5722 const type_info_1 = try c.createBuiltinCall("@typeInfo", 1);
5723 const type_of_1 = try c.createBuiltinCall("@TypeOf", 1);
5724 type_info_1.params()[0] = &type_of_1.base;
5725 type_of_1.params()[0] = node_to_cast;
5726 type_of_1.rparen_token = try appendToken(c, .RParen, ")");
5727 type_info_1.rparen_token = try appendToken(c, .RParen, ")");
5728
5729 const cmp_1 = try c.arena.create(ast.Node.InfixOp);
5730 cmp_1.* = .{
5731 .op_token = try appendToken(c, .EqualEqual, "=="),
5732 .lhs = &type_info_1.base,
5733 .op = .EqualEqual,
5734 .rhs = try transCreateNodeEnumLiteral(c, "Pointer"),
5735 };
5736 if_1.condition = &cmp_1.base;
5737 _ = try appendToken(c, .RParen, ")");
5738
5739 const period_tok = try appendToken(c, .Period, ".");
5740 const child_ident = try transCreateNodeIdentifier(c, "Child");
5741 const inner_node_child = try c.arena.create(ast.Node.InfixOp);
5742 inner_node_child.* = .{
5743 .op_token = period_tok,
5744 .lhs = inner_node,
5745 .op = .Period,
5746 .rhs = child_ident,
5747 };
5748
5749 const align_of = try c.createBuiltinCall("@alignOf", 1);
5750 align_of.params()[0] = &inner_node_child.base;
5751 align_of.rparen_token = try appendToken(c, .RParen, ")");
5752 // hack to get zig fmt to render a comma in builtin calls
5753 _ = try appendToken(c, .Comma, ",");
5754
5755 const align_cast = try c.createBuiltinCall("@alignCast", 2);
5756 align_cast.params()[0] = &align_of.base;
5757 align_cast.params()[1] = node_to_cast;
5758 align_cast.rparen_token = try appendToken(c, .RParen, ")");
5759
5760 const ptr_cast = try c.createBuiltinCall("@ptrCast", 2);
5761 ptr_cast.params()[0] = inner_node;
5762 ptr_cast.params()[1] = &align_cast.base;
5763 ptr_cast.rparen_token = try appendToken(c, .RParen, ")");
5764 if_1.body = &ptr_cast.base;
5765
5766 const else_1 = try transCreateNodeElse(c);
5767 if_1.@"else" = else_1;
5768
5769 const if_2 = try transCreateNodeIf(c);
5770 const type_info_2 = try c.createBuiltinCall("@typeInfo", 1);
5771 const type_of_2 = try c.createBuiltinCall("@TypeOf", 1);
5772 type_info_2.params()[0] = &type_of_2.base;
5773 type_of_2.params()[0] = node_to_cast;
5774 type_of_2.rparen_token = try appendToken(c, .RParen, ")");
5775 type_info_2.rparen_token = try appendToken(c, .RParen, ")");
5776
5777 const cmp_2 = try c.arena.create(ast.Node.InfixOp);
5778 cmp_2.* = .{
5779 .op_token = try appendToken(c, .EqualEqual, "=="),
5780 .lhs = &type_info_2.base,
5781 .op = .EqualEqual,
5782 .rhs = try transCreateNodeEnumLiteral(c, "Int"),
5783 };
5784 if_2.condition = &cmp_2.base;
5785 const cmp_4 = try c.arena.create(ast.Node.InfixOp);
5786 cmp_4.* = .{
5787 .op_token = try appendToken(c, .Keyword_and, "and"),
5788 .lhs = &cmp_2.base,
5789 .op = .BoolAnd,
5790 .rhs = undefined,
5791 };
5792 const type_info_3 = try c.createBuiltinCall("@typeInfo", 1);
5793 type_info_3.params()[0] = inner_node;
5794 type_info_3.rparen_token = try appendToken(c, .LParen, ")");
5795 const cmp_3 = try c.arena.create(ast.Node.InfixOp);
5796 cmp_3.* = .{
5797 .op_token = try appendToken(c, .EqualEqual, "=="),
5798 .lhs = &type_info_3.base,
5799 .op = .EqualEqual,
5800 .rhs = try transCreateNodeEnumLiteral(c, "Pointer"),
5801 };
5802 cmp_4.rhs = &cmp_3.base;
5803 if_2.condition = &cmp_4.base;
5804 else_1.body = &if_2.base;
5805 _ = try appendToken(c, .RParen, ")");
5806
5807 const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2);
5808 int_to_ptr.params()[0] = inner_node;
5809 int_to_ptr.params()[1] = node_to_cast;
5810 int_to_ptr.rparen_token = try appendToken(c, .RParen, ")");
5811 if_2.body = &int_to_ptr.base;
5812
5813 const else_2 = try transCreateNodeElse(c);
5814 if_2.@"else" = else_2;
5815
5816 const as = try c.createBuiltinCall("@as", 2);
5817 as.params()[0] = inner_node;
5818 as.params()[1] = node_to_cast;
5819 as.rparen_token = try appendToken(c, .RParen, ")");
5820 else_2.body = &as.base;
58215683
5822 const group_node = try c.arena.create(ast.Node.GroupedExpression);5684 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5823 group_node.* = .{5685 group_node.* = .{
5824 .lparen = lparen,5686 .lparen = lparen,
5825 .expr = &if_1.base,5687 .expr = &cast_fn_call.base,
5826 .rparen = try appendToken(c, .RParen, ")"),5688 .rparen = try appendToken(c, .RParen, ")"),
5827 };5689 };
5828 return &group_node.base;5690 return &group_node.base;
src/analyze.cpp+13
...@@ -6012,6 +6012,19 @@ ZigValue *create_const_null(CodeGen *g, ZigType *type) {...@@ -6012,6 +6012,19 @@ ZigValue *create_const_null(CodeGen *g, ZigType *type) {
6012 return const_val;6012 return const_val;
6013}6013}
60146014
6015void init_const_fn(ZigValue *const_val, ZigFn *fn) {
6016 const_val->special = ConstValSpecialStatic;
6017 const_val->type = fn->type_entry;
6018 const_val->data.x_ptr.special = ConstPtrSpecialFunction;
6019 const_val->data.x_ptr.data.fn.fn_entry = fn;
6020}
6021
6022ZigValue *create_const_fn(CodeGen *g, ZigFn *fn) {
6023 ZigValue *const_val = g->pass1_arena->create<ZigValue>();
6024 init_const_fn(const_val, fn);
6025 return const_val;
6026}
6027
6015void init_const_float(ZigValue *const_val, ZigType *type, double value) {6028void init_const_float(ZigValue *const_val, ZigType *type, double value) {
6016 const_val->special = ConstValSpecialStatic;6029 const_val->special = ConstValSpecialStatic;
6017 const_val->type = type;6030 const_val->type = type;
src/analyze.hpp+3
...@@ -180,6 +180,9 @@ ZigValue *create_const_slice(CodeGen *g, ZigValue *array_val, size_t start, size...@@ -180,6 +180,9 @@ ZigValue *create_const_slice(CodeGen *g, ZigValue *array_val, size_t start, size
180void init_const_null(ZigValue *const_val, ZigType *type);180void init_const_null(ZigValue *const_val, ZigType *type);
181ZigValue *create_const_null(CodeGen *g, ZigType *type);181ZigValue *create_const_null(CodeGen *g, ZigType *type);
182182
183void init_const_fn(ZigValue *const_val, ZigFn *fn);
184ZigValue *create_const_fn(CodeGen *g, ZigFn *fn);
185
183ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count);186ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count);
184ZigValue **realloc_const_vals_ptrs(CodeGen *g, ZigValue **ptr, size_t old_count, size_t new_count);187ZigValue **realloc_const_vals_ptrs(CodeGen *g, ZigValue **ptr, size_t old_count, size_t new_count);
185188
src/codegen.cpp+6-6
...@@ -3540,7 +3540,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl...@@ -3540,7 +3540,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl
35403540
3541 for (size_t field_i = 0; field_i < field_count; field_i += 1) {3541 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
3542 TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i];3542 TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i];
3543 3543
3544 Buf *name = type_enum_field->name;3544 Buf *name = type_enum_field->name;
3545 auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);3545 auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
3546 if (entry != nullptr) {3546 if (entry != nullptr) {
...@@ -3654,7 +3654,7 @@ static LLVMValueRef ir_gen_negation(CodeGen *g, IrInstGen *inst, IrInstGen *oper...@@ -3654,7 +3654,7 @@ static LLVMValueRef ir_gen_negation(CodeGen *g, IrInstGen *inst, IrInstGen *oper
3654 } else if (scalar_type->data.integral.is_signed) {3654 } else if (scalar_type->data.integral.is_signed) {
3655 return LLVMBuildNSWNeg(g->builder, llvm_operand, "");3655 return LLVMBuildNSWNeg(g->builder, llvm_operand, "");
3656 } else {3656 } else {
3657 return LLVMBuildNUWNeg(g->builder, llvm_operand, "");3657 zig_unreachable();
3658 }3658 }
3659 } else {3659 } else {
3660 zig_unreachable();3660 zig_unreachable();
...@@ -3984,7 +3984,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutableGen *executable,...@@ -3984,7 +3984,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutableGen *executable,
3984 assert(array_type->data.pointer.child_type->id == ZigTypeIdArray);3984 assert(array_type->data.pointer.child_type->id == ZigTypeIdArray);
3985 array_type = array_type->data.pointer.child_type;3985 array_type = array_type->data.pointer.child_type;
3986 }3986 }
3987 3987
3988 assert(array_type->data.array.len != 0 || array_type->data.array.sentinel != nullptr);3988 assert(array_type->data.array.len != 0 || array_type->data.array.sentinel != nullptr);
39893989
3990 if (safety_check_on) {3990 if (safety_check_on) {
...@@ -5258,7 +5258,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {...@@ -5258,7 +5258,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
52585258
5259 for (size_t field_i = 0; field_i < field_count; field_i += 1) {5259 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
5260 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];5260 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
5261 5261
5262 Buf *name = type_enum_field->name;5262 Buf *name = type_enum_field->name;
5263 auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);5263 auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
5264 if (entry != nullptr) {5264 if (entry != nullptr) {
...@@ -5471,7 +5471,7 @@ static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {...@@ -5471,7 +5471,7 @@ static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {
5471 }5471 }
5472 auto bit_count = operand_type->data.integral.bit_count;5472 auto bit_count = operand_type->data.integral.bit_count;
5473 bool is_signed = operand_type->data.integral.is_signed;5473 bool is_signed = operand_type->data.integral.is_signed;
5474 5474
5475 ir_assert(bit_count != 0, instruction);5475 ir_assert(bit_count != 0, instruction);
5476 if (bit_count == 1 || !is_power_of_2(bit_count)) {5476 if (bit_count == 1 || !is_power_of_2(bit_count)) {
5477 return get_llvm_type(g, get_int_type(g, is_signed, operand_type->abi_size * 8));5477 return get_llvm_type(g, get_int_type(g, is_signed, operand_type->abi_size * 8));
...@@ -9275,7 +9275,7 @@ static void init(CodeGen *g) {...@@ -9275,7 +9275,7 @@ static void init(CodeGen *g) {
9275 abi_name = (g->zig_target->arch == ZigLLVM_riscv32) ? "ilp32" : "lp64";9275 abi_name = (g->zig_target->arch == ZigLLVM_riscv32) ? "ilp32" : "lp64";
9276 }9276 }
9277 }9277 }
9278 9278
9279 g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str),9279 g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str),
9280 target_specific_cpu_args, target_specific_features, opt_level, reloc_mode,9280 target_specific_cpu_args, target_specific_features, opt_level, reloc_mode,
9281 to_llvm_code_model(g), g->function_sections, float_abi, abi_name);9281 to_llvm_code_model(g), g->function_sections, float_abi, abi_name);
src/ir.cpp+133-27
...@@ -13,6 +13,7 @@...@@ -13,6 +13,7 @@
13#include "os.hpp"13#include "os.hpp"
14#include "range_set.hpp"14#include "range_set.hpp"
15#include "softfloat.hpp"15#include "softfloat.hpp"
16#include "softfloat_ext.hpp"
16#include "util.hpp"17#include "util.hpp"
17#include "mem_list.hpp"18#include "mem_list.hpp"
18#include "all_types.hpp"19#include "all_types.hpp"
...@@ -825,12 +826,11 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_...@@ -825,12 +826,11 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_
825 ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;826 ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
826 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;827 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
827828
828 // TODO handle sentinel terminated arrays
829 expand_undef_array(g, array_val);829 expand_undef_array(g, array_val);
830 result = g->pass1_arena->create<ZigValue>();830 result = g->pass1_arena->create<ZigValue>();
831 result->special = array_val->special;831 result->special = array_val->special;
832 result->type = get_array_type(g, array_val->type->data.array.child_type,832 result->type = get_array_type(g, array_val->type->data.array.child_type,
833 array_val->type->data.array.len - elem_index, nullptr);833 array_val->type->data.array.len - elem_index, array_val->type->data.array.sentinel);
834 result->data.x_array.special = ConstArraySpecialNone;834 result->data.x_array.special = ConstArraySpecialNone;
835 result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index];835 result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index];
836 result->parent.id = ConstParentIdArray;836 result->parent.id = ConstParentIdArray;
...@@ -12601,28 +12601,28 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT...@@ -12601,28 +12601,28 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
12601 if (prev_type->id == ZigTypeIdPointer &&12601 if (prev_type->id == ZigTypeIdPointer &&
12602 prev_type->data.pointer.ptr_len == PtrLenSingle &&12602 prev_type->data.pointer.ptr_len == PtrLenSingle &&
12603 prev_type->data.pointer.child_type->id == ZigTypeIdArray &&12603 prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
12604 ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown))) 12604 ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown)))
12605 {12605 {
12606 prev_inst = cur_inst; 12606 prev_inst = cur_inst;
1260712607
12608 if (prev_type->data.pointer.is_const && !cur_type->data.pointer.is_const) {12608 if (prev_type->data.pointer.is_const && !cur_type->data.pointer.is_const) {
12609 // const array pointer and non-const unknown pointer12609 // const array pointer and non-const unknown pointer
12610 make_the_pointer_const = true;12610 make_the_pointer_const = true;
12611 }12611 }
12612 continue; 12612 continue;
12613 }12613 }
1261412614
12615 // *[N]T to [*]T12615 // *[N]T to [*]T
12616 if (cur_type->id == ZigTypeIdPointer &&12616 if (cur_type->id == ZigTypeIdPointer &&
12617 cur_type->data.pointer.ptr_len == PtrLenSingle &&12617 cur_type->data.pointer.ptr_len == PtrLenSingle &&
12618 cur_type->data.pointer.child_type->id == ZigTypeIdArray &&12618 cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
12619 ((prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenUnknown))) 12619 ((prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenUnknown)))
12620 {12620 {
12621 if (cur_type->data.pointer.is_const && !prev_type->data.pointer.is_const) {12621 if (cur_type->data.pointer.is_const && !prev_type->data.pointer.is_const) {
12622 // const array pointer and non-const unknown pointer12622 // const array pointer and non-const unknown pointer
12623 make_the_pointer_const = true;12623 make_the_pointer_const = true;
12624 }12624 }
12625 continue; 12625 continue;
12626 }12626 }
1262712627
12628 // *[N]T to []T12628 // *[N]T to []T
...@@ -20986,17 +20986,24 @@ static IrInstGen *ir_analyze_negation(IrAnalyze *ira, IrInstSrcUnOp *instruction...@@ -20986,17 +20986,24 @@ static IrInstGen *ir_analyze_negation(IrAnalyze *ira, IrInstSrcUnOp *instruction
20986 if (type_is_invalid(expr_type))20986 if (type_is_invalid(expr_type))
20987 return ira->codegen->invalid_inst_gen;20987 return ira->codegen->invalid_inst_gen;
2098820988
20989 if (!(expr_type->id == ZigTypeIdInt || expr_type->id == ZigTypeIdComptimeInt ||
20990 expr_type->id == ZigTypeIdFloat || expr_type->id == ZigTypeIdComptimeFloat ||
20991 expr_type->id == ZigTypeIdVector))
20992 {
20993 ir_add_error(ira, &instruction->base.base,
20994 buf_sprintf("negation of type '%s'", buf_ptr(&expr_type->name)));
20995 return ira->codegen->invalid_inst_gen;
20996 }
20997
20998 bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap);20989 bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap);
2099920990
20991 switch (expr_type->id) {
20992 case ZigTypeIdComptimeInt:
20993 case ZigTypeIdFloat:
20994 case ZigTypeIdComptimeFloat:
20995 case ZigTypeIdVector:
20996 break;
20997 case ZigTypeIdInt:
20998 if (is_wrap_op || expr_type->data.integral.is_signed)
20999 break;
21000 ZIG_FALLTHROUGH;
21001 default:
21002 ir_add_error(ira, &instruction->base.base,
21003 buf_sprintf("negation of type '%s'", buf_ptr(&expr_type->name)));
21004 return ira->codegen->invalid_inst_gen;
21005 }
21006
21000 ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;21007 ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
2100121008
21002 if (instr_is_comptime(value)) {21009 if (instr_is_comptime(value)) {
...@@ -25609,9 +25616,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy...@@ -25609,9 +25616,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
25609 break;25616 break;
25610 }25617 }
25611 case ZigTypeIdFnFrame:25618 case ZigTypeIdFnFrame:
25612 ir_add_error(ira, source_instr,25619 {
25613 buf_sprintf("compiler bug: TODO @typeInfo for async function frames. https://github.com/ziglang/zig/issues/3066"));25620 result = ira->codegen->pass1_arena->create<ZigValue>();
25614 return ErrorSemanticAnalyzeFail;25621 result->special = ConstValSpecialStatic;
25622 result->type = ir_type_info_get_type(ira, "Frame", nullptr);
25623 ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 1);
25624 result->data.x_struct.fields = fields;
25625 ZigFn *fn = type_entry->data.frame.fn;
25626 // function: var
25627 ensure_field_index(result->type, "function", 0);
25628 fields[0] = create_const_fn(ira->codegen, fn);
25629 break;
25630 }
25615 }25631 }
2561625632
25617 assert(result != nullptr);25633 assert(result != nullptr);
...@@ -25880,10 +25896,90 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI...@@ -25880,10 +25896,90 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
25880 ZigType *child_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "child", 0);25896 ZigType *child_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "child", 0);
25881 return get_any_frame_type(ira->codegen, child_type);25897 return get_any_frame_type(ira->codegen, child_type);
25882 }25898 }
25883 case ZigTypeIdErrorSet:
25884 case ZigTypeIdEnum:
25885 case ZigTypeIdFnFrame:
25886 case ZigTypeIdEnumLiteral:25899 case ZigTypeIdEnumLiteral:
25900 return ira->codegen->builtin_types.entry_enum_literal;
25901 case ZigTypeIdFnFrame: {
25902 assert(payload->special == ConstValSpecialStatic);
25903 assert(payload->type == ir_type_info_get_type(ira, "Frame", nullptr));
25904 ZigValue *function = get_const_field(ira, source_instr->source_node, payload, "function", 0);
25905 assert(function->type->id == ZigTypeIdFn);
25906 ZigFn *fn = function->data.x_ptr.data.fn.fn_entry;
25907 return get_fn_frame_type(ira->codegen, fn);
25908 }
25909 case ZigTypeIdErrorSet: {
25910 assert(payload->special == ConstValSpecialStatic);
25911 assert(payload->type->id == ZigTypeIdOptional);
25912 ZigValue *slice = payload->data.x_optional;
25913 if (slice == nullptr)
25914 return ira->codegen->builtin_types.entry_global_error_set;
25915 assert(slice->special == ConstValSpecialStatic);
25916 assert(is_slice(slice->type));
25917 ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
25918 Buf bare_name = BUF_INIT;
25919 buf_init_from_buf(&err_set_type->name, get_anon_type_name(ira->codegen, ira->old_irb.exec, "error", source_instr->scope, source_instr->source_node, &bare_name));
25920 err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits;
25921 err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align;
25922 err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size;
25923 ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index];
25924 assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);;
25925 assert(ptr->data.x_ptr.data.base_array.elem_index == 0);
25926 ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val;
25927 assert(arr->special == ConstValSpecialStatic);
25928 assert(arr->data.x_array.special == ConstArraySpecialNone);
25929 ZigValue *len = slice->data.x_struct.fields[slice_len_index];
25930 size_t count = bigint_as_usize(&len->data.x_bigint);
25931 err_set_type->data.error_set.err_count = count;
25932 err_set_type->data.error_set.errors = heap::c_allocator.allocate<ErrorTableEntry *>(count);
25933 bool *already_set = heap::c_allocator.allocate<bool>(ira->codegen->errors_by_index.length + count);
25934 for (size_t i = 0; i < count; i++) {
25935 ZigValue *error = &arr->data.x_array.data.s_none.elements[i];
25936 assert(error->type == ir_type_info_get_type(ira, "Error", nullptr));
25937 ErrorTableEntry *err_entry = heap::c_allocator.create<ErrorTableEntry>();
25938 err_entry->decl_node = source_instr->source_node;
25939 ZigValue *name_slice = get_const_field(ira, source_instr->source_node, error, "name", 0);
25940 ZigValue *name_ptr = name_slice->data.x_struct.fields[slice_ptr_index];
25941 ZigValue *name_len = name_slice->data.x_struct.fields[slice_len_index];
25942 assert(name_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
25943 assert(name_ptr->data.x_ptr.data.base_array.elem_index == 0);
25944 ZigValue *name_arr = name_ptr->data.x_ptr.data.base_array.array_val;
25945 assert(name_arr->special == ConstValSpecialStatic);
25946 switch (name_arr->data.x_array.special) {
25947 case ConstArraySpecialUndef:
25948 return ira->codegen->invalid_inst_gen->value->type;
25949 case ConstArraySpecialNone: {
25950 buf_resize(&err_entry->name, 0);
25951 size_t name_count = bigint_as_usize(&name_len->data.x_bigint);
25952 for (size_t j = 0; j < name_count; j++) {
25953 ZigValue *ch_val = &name_arr->data.x_array.data.s_none.elements[j];
25954 unsigned ch = bigint_as_u32(&ch_val->data.x_bigint);
25955 buf_append_char(&err_entry->name, ch);
25956 }
25957 break;
25958 }
25959 case ConstArraySpecialBuf:
25960 buf_init_from_buf(&err_entry->name, name_arr->data.x_array.data.s_buf);
25961 break;
25962 }
25963 auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry);
25964 if (existing_entry) {
25965 err_entry->value = existing_entry->value->value;
25966 } else {
25967 size_t error_value_count = ira->codegen->errors_by_index.length;
25968 assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count));
25969 err_entry->value = error_value_count;
25970 ira->codegen->errors_by_index.append(err_entry);
25971 }
25972 if (already_set[err_entry->value]) {
25973 ir_add_error(ira, source_instr, buf_sprintf("duplicate error: %s", buf_ptr(&err_entry->name)));
25974 return ira->codegen->invalid_inst_gen->value->type;
25975 } else {
25976 already_set[err_entry->value] = true;
25977 }
25978 err_set_type->data.error_set.errors[i] = err_entry;
25979 }
25980 return err_set_type;
25981 }
25982 case ZigTypeIdEnum:
25887 ir_add_error(ira, source_instr, buf_sprintf(25983 ir_add_error(ira, source_instr, buf_sprintf(
25888 "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));25984 "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));
25889 return ira->codegen->invalid_inst_gen->value->type;25985 return ira->codegen->invalid_inst_gen->value->type;
...@@ -30278,6 +30374,21 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF...@@ -30278,6 +30374,21 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF
30278 case BuiltinFnIdSqrt:30374 case BuiltinFnIdSqrt:
30279 f128M_sqrt(in, out);30375 f128M_sqrt(in, out);
30280 break;30376 break;
30377 case BuiltinFnIdFabs:
30378 f128M_abs(in, out);
30379 break;
30380 case BuiltinFnIdFloor:
30381 f128M_roundToInt(in, softfloat_round_min, false, out);
30382 break;
30383 case BuiltinFnIdCeil:
30384 f128M_roundToInt(in, softfloat_round_max, false, out);
30385 break;
30386 case BuiltinFnIdTrunc:
30387 f128M_trunc(in, out);
30388 break;
30389 case BuiltinFnIdRound:
30390 f128M_roundToInt(in, softfloat_round_near_maxMag, false, out);
30391 break;
30281 case BuiltinFnIdNearbyInt:30392 case BuiltinFnIdNearbyInt:
30282 case BuiltinFnIdSin:30393 case BuiltinFnIdSin:
30283 case BuiltinFnIdCos:30394 case BuiltinFnIdCos:
...@@ -30286,11 +30397,6 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF...@@ -30286,11 +30397,6 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF
30286 case BuiltinFnIdLog:30397 case BuiltinFnIdLog:
30287 case BuiltinFnIdLog10:30398 case BuiltinFnIdLog10:
30288 case BuiltinFnIdLog2:30399 case BuiltinFnIdLog2:
30289 case BuiltinFnIdFabs:
30290 case BuiltinFnIdFloor:
30291 case BuiltinFnIdCeil:
30292 case BuiltinFnIdTrunc:
30293 case BuiltinFnIdRound:
30294 return ir_add_error(ira, source_instr,30400 return ir_add_error(ira, source_instr,
30295 buf_sprintf("compiler bug: TODO: implement '%s' for type '%s'. See https://github.com/ziglang/zig/issues/4026",30401 buf_sprintf("compiler bug: TODO: implement '%s' for type '%s'. See https://github.com/ziglang/zig/issues/4026",
30296 float_op_to_name(fop), buf_ptr(&float_type->name)));30402 float_op_to_name(fop), buf_ptr(&float_type->name)));
src/softfloat_ext.cpp created+25
...@@ -0,0 +1,25 @@
1#include "softfloat_ext.hpp"
2
3extern "C" {
4 #include "softfloat.h"
5}
6
7void f128M_abs(const float128_t *aPtr, float128_t *zPtr) {
8 float128_t zero_float;
9 ui32_to_f128M(0, &zero_float);
10 if (f128M_lt(aPtr, &zero_float)) {
11 f128M_sub(&zero_float, aPtr, zPtr);
12 } else {
13 *zPtr = *aPtr;
14 }
15}
16
17void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) {
18 float128_t zero_float;
19 ui32_to_f128M(0, &zero_float);
20 if (f128M_lt(aPtr, &zero_float)) {
21 f128M_roundToInt(aPtr, softfloat_round_max, false, zPtr);
22 } else {
23 f128M_roundToInt(aPtr, softfloat_round_min, false, zPtr);
24 }
25}
\ No newline at end of file
src/softfloat_ext.hpp created+9
...@@ -0,0 +1,9 @@
1#ifndef ZIG_SOFTFLOAT_EXT_HPP
2#define ZIG_SOFTFLOAT_EXT_HPP
3
4#include "softfloat_types.h"
5
6void f128M_abs(const float128_t *aPtr, float128_t *zPtr);
7void f128M_trunc(const float128_t *aPtr, float128_t *zPtr);
8
9#endif
\ No newline at end of file
test/cli.zig+27
...@@ -34,6 +34,7 @@ pub fn main() !void {...@@ -34,6 +34,7 @@ pub fn main() !void {
34 testZigInitExe,34 testZigInitExe,
35 testGodboltApi,35 testGodboltApi,
36 testMissingOutputPath,36 testMissingOutputPath,
37 testZigFmt,
37 };38 };
38 for (test_fns) |testFn| {39 for (test_fns) |testFn| {
39 try fs.cwd().deleteTree(dir_path);40 try fs.cwd().deleteTree(dir_path);
...@@ -143,3 +144,29 @@ fn testMissingOutputPath(zig_exe: []const u8, dir_path: []const u8) !void {...@@ -143,3 +144,29 @@ fn testMissingOutputPath(zig_exe: []const u8, dir_path: []const u8) !void {
143 zig_exe, "build-exe", source_path, "--output-dir", output_path,144 zig_exe, "build-exe", source_path, "--output-dir", output_path,
144 });145 });
145}146}
147
148fn testZigFmt(zig_exe: []const u8, dir_path: []const u8) !void {
149 _ = try exec(dir_path, &[_][]const u8{ zig_exe, "init-exe" });
150
151 const unformatted_code = " // no reason for indent";
152
153 const fmt1_zig_path = try fs.path.join(a, &[_][]const u8{ dir_path, "fmt1.zig" });
154 try fs.cwd().writeFile(fmt1_zig_path, unformatted_code);
155
156 const run_result1 = try exec(dir_path, &[_][]const u8{ zig_exe, "fmt", fmt1_zig_path });
157 // stderr should be file path + \n
158 testing.expect(std.mem.startsWith(u8, run_result1.stderr, fmt1_zig_path));
159 testing.expect(run_result1.stderr.len == fmt1_zig_path.len + 1 and run_result1.stderr[run_result1.stderr.len - 1] == '\n');
160
161 const fmt2_zig_path = try fs.path.join(a, &[_][]const u8{ dir_path, "fmt2.zig" });
162 try fs.cwd().writeFile(fmt2_zig_path, unformatted_code);
163
164 const run_result2 = try exec(dir_path, &[_][]const u8{ zig_exe, "fmt", dir_path });
165 // running it on the dir, only the new file should be changed
166 testing.expect(std.mem.startsWith(u8, run_result2.stderr, fmt2_zig_path));
167 testing.expect(run_result2.stderr.len == fmt2_zig_path.len + 1 and run_result2.stderr[run_result2.stderr.len - 1] == '\n');
168
169 const run_result3 = try exec(dir_path, &[_][]const u8{ zig_exe, "fmt", dir_path });
170 // both files have been formatted, nothing should change now
171 testing.expect(run_result3.stderr.len == 0);
172}
test/compile_errors.zig+9
...@@ -7530,4 +7530,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -7530,4 +7530,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
7530 , &[_][]const u8{7530 , &[_][]const u8{
7531 "tmp.zig:2:9: error: @wasmMemoryGrow is a wasm32 feature only",7531 "tmp.zig:2:9: error: @wasmMemoryGrow is a wasm32 feature only",
7532 });7532 });
7533
7534 cases.add("Issue #5586: Make unary minus for unsigned types a compile error",
7535 \\export fn f(x: u32) u32 {
7536 \\ const y = -%x;
7537 \\ return -y;
7538 \\}
7539 , &[_][]const u8{
7540 "tmp.zig:3:12: error: negation of type 'u32'"
7541 });
7533}7542}
test/stage1/behavior/math.zig+122
...@@ -634,6 +634,128 @@ fn testSqrt(comptime T: type, x: T) void {...@@ -634,6 +634,128 @@ fn testSqrt(comptime T: type, x: T) void {
634 expect(@sqrt(x * x) == x);634 expect(@sqrt(x * x) == x);
635}635}
636636
637test "@fabs" {
638 testFabs(f128, 12.0);
639 comptime testFabs(f128, 12.0);
640 testFabs(f64, 12.0);
641 comptime testFabs(f64, 12.0);
642 testFabs(f32, 12.0);
643 comptime testFabs(f32, 12.0);
644 testFabs(f16, 12.0);
645 comptime testFabs(f16, 12.0);
646
647 const x = 14.0;
648 const y = -x;
649 const z = @fabs(y);
650 comptime expectEqual(x, z);
651}
652
653fn testFabs(comptime T: type, x: T) void {
654 const y = -x;
655 const z = @fabs(y);
656 expectEqual(x, z);
657}
658
659test "@floor" {
660 // FIXME: Generates a floorl function call
661 // testFloor(f128, 12.0);
662 comptime testFloor(f128, 12.0);
663 testFloor(f64, 12.0);
664 comptime testFloor(f64, 12.0);
665 testFloor(f32, 12.0);
666 comptime testFloor(f32, 12.0);
667 testFloor(f16, 12.0);
668 comptime testFloor(f16, 12.0);
669
670 const x = 14.0;
671 const y = x + 0.7;
672 const z = @floor(y);
673 comptime expectEqual(x, z);
674}
675
676fn testFloor(comptime T: type, x: T) void {
677 const y = x + 0.6;
678 const z = @floor(y);
679 expectEqual(x, z);
680}
681
682test "@ceil" {
683 // FIXME: Generates a ceill function call
684 //testCeil(f128, 12.0);
685 comptime testCeil(f128, 12.0);
686 testCeil(f64, 12.0);
687 comptime testCeil(f64, 12.0);
688 testCeil(f32, 12.0);
689 comptime testCeil(f32, 12.0);
690 testCeil(f16, 12.0);
691 comptime testCeil(f16, 12.0);
692
693 const x = 14.0;
694 const y = x - 0.7;
695 const z = @ceil(y);
696 comptime expectEqual(x, z);
697}
698
699fn testCeil(comptime T: type, x: T) void {
700 const y = x - 0.8;
701 const z = @ceil(y);
702 expectEqual(x, z);
703}
704
705test "@trunc" {
706 // FIXME: Generates a truncl function call
707 //testTrunc(f128, 12.0);
708 comptime testTrunc(f128, 12.0);
709 testTrunc(f64, 12.0);
710 comptime testTrunc(f64, 12.0);
711 testTrunc(f32, 12.0);
712 comptime testTrunc(f32, 12.0);
713 testTrunc(f16, 12.0);
714 comptime testTrunc(f16, 12.0);
715
716 const x = 14.0;
717 const y = x + 0.7;
718 const z = @trunc(y);
719 comptime expectEqual(x, z);
720}
721
722fn testTrunc(comptime T: type, x: T) void {
723 {
724 const y = x + 0.8;
725 const z = @trunc(y);
726 expectEqual(x, z);
727 }
728
729 {
730 const y = -x - 0.8;
731 const z = @trunc(y);
732 expectEqual(-x, z);
733 }
734}
735
736test "@round" {
737 // FIXME: Generates a roundl function call
738 //testRound(f128, 12.0);
739 comptime testRound(f128, 12.0);
740 testRound(f64, 12.0);
741 comptime testRound(f64, 12.0);
742 testRound(f32, 12.0);
743 comptime testRound(f32, 12.0);
744 testRound(f16, 12.0);
745 comptime testRound(f16, 12.0);
746
747 const x = 14.0;
748 const y = x + 0.4;
749 const z = @round(y);
750 comptime expectEqual(x, z);
751}
752
753fn testRound(comptime T: type, x: T) void {
754 const y = x - 0.5;
755 const z = @round(y);
756 expectEqual(x, z);
757}
758
637test "comptime_int param and return" {759test "comptime_int param and return" {
638 const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);760 const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
639 expect(a == 137114567242441932203689521744947848950);761 expect(a == 137114567242441932203689521744947848950);
test/stage1/behavior/slice.zig+5
...@@ -280,6 +280,11 @@ test "slice syntax resulting in pointer-to-array" {...@@ -280,6 +280,11 @@ test "slice syntax resulting in pointer-to-array" {
280 expect(slice[0] == 5);280 expect(slice[0] == 5);
281 comptime expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8);281 comptime expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8);
282 }282 }
283
284 fn testConcatStrLiterals() void {
285 expectEqualSlices("a"[0..] ++ "b"[0..], "ab");
286 expectEqualSlices("a"[0..:0] ++ "b"[0..:0], "ab");
287 }
283 };288 };
284289
285 S.doTheTest();290 S.doTheTest();
test/stage1/behavior/type.zig+23
...@@ -213,3 +213,26 @@ test "Type.AnyFrame" {...@@ -213,3 +213,26 @@ test "Type.AnyFrame" {
213 anyframe->anyframe->u8,213 anyframe->anyframe->u8,
214 });214 });
215}215}
216
217test "Type.EnumLiteral" {
218 testTypes(&[_]type{
219 @TypeOf(.Dummy),
220 });
221}
222
223fn add(a: i32, b: i32) i32 {
224 return a + b;
225}
226
227test "Type.Frame" {
228 testTypes(&[_]type{
229 @Frame(add),
230 });
231}
232
233test "Type.ErrorSet" {
234 // error sets don't compare equal so just check if they compile
235 _ = @Type(@typeInfo(error{}));
236 _ = @Type(@typeInfo(error{A}));
237 _ = @Type(@typeInfo(error{ A, B, C }));
238}
test/stage1/behavior/type_info.zig+14-1
...@@ -202,7 +202,7 @@ fn testUnion() void {...@@ -202,7 +202,7 @@ fn testUnion() void {
202 expect(typeinfo_info.Union.fields[4].enum_field != null);202 expect(typeinfo_info.Union.fields[4].enum_field != null);
203 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);203 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
204 expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));204 expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
205 expect(typeinfo_info.Union.decls.len == 20);205 expect(typeinfo_info.Union.decls.len == 21);
206206
207 const TestNoTagUnion = union {207 const TestNoTagUnion = union {
208 Foo: void,208 Foo: void,
...@@ -389,3 +389,16 @@ test "defaut value for a var-typed field" {...@@ -389,3 +389,16 @@ test "defaut value for a var-typed field" {
389 const S = struct { x: var };389 const S = struct { x: var };
390 expect(@typeInfo(S).Struct.fields[0].default_value == null);390 expect(@typeInfo(S).Struct.fields[0].default_value == null);
391}391}
392
393fn add(a: i32, b: i32) i32 {
394 return a + b;
395}
396
397test "type info for async frames" {
398 switch (@typeInfo(@Frame(add))) {
399 .Frame => |frame| {
400 expect(frame.function == add);
401 },
402 else => unreachable,
403 }
404}
test/translate_c.zig+8-8
...@@ -1473,7 +1473,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1473,7 +1473,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1473 cases.add("macro pointer cast",1473 cases.add("macro pointer cast",
1474 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)1474 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
1475 , &[_][]const u8{1475 , &[_][]const u8{
1476 \\pub const NRF_GPIO = (if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, @alignCast(@alignOf([*c]NRF_GPIO_Type.Child), NRF_GPIO_BASE)) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int and @typeInfo([*c]NRF_GPIO_Type) == .Pointer) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE));1476 \\pub const NRF_GPIO = (@import("std").meta.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
1477 });1477 });
14781478
1479 cases.add("basic macro function",1479 cases.add("basic macro function",
...@@ -2683,11 +2683,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2683,11 +2683,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2683 \\#define FOO(bar) baz((void *)(baz))2683 \\#define FOO(bar) baz((void *)(baz))
2684 \\#define BAR (void*) a2684 \\#define BAR (void*) a
2685 , &[_][]const u8{2685 , &[_][]const u8{
2686 \\pub inline fn FOO(bar: var) @TypeOf(baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(?*c_void, @alignCast(@alignOf(?*c_void.Child), baz)) else if (@typeInfo(@TypeOf(baz)) == .Int and @typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, baz) else @as(?*c_void, baz)))) {2686 \\pub inline fn FOO(bar: var) @TypeOf(baz((@import("std").meta.cast(?*c_void, baz)))) {
2687 \\ return baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(?*c_void, @alignCast(@alignOf(?*c_void.Child), baz)) else if (@typeInfo(@TypeOf(baz)) == .Int and @typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, baz) else @as(?*c_void, baz)));2687 \\ return baz((@import("std").meta.cast(?*c_void, baz)));
2688 \\}2688 \\}
2689 ,2689 ,
2690 \\pub const BAR = (if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(?*c_void, @alignCast(@alignOf(?*c_void.Child), a)) else if (@typeInfo(@TypeOf(a)) == .Int and @typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, a) else @as(?*c_void, a));2690 \\pub const BAR = (@import("std").meta.cast(?*c_void, a));
2691 });2691 });
26922692
2693 cases.add("macro conditional operator",2693 cases.add("macro conditional operator",
...@@ -2905,8 +2905,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2905,8 +2905,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2905 \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)2905 \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
2906 \\2906 \\
2907 , &[_][]const u8{2907 , &[_][]const u8{
2908 \\pub inline fn DefaultScreen(dpy: var) @TypeOf((if (@typeInfo(@TypeOf(dpy)) == .Pointer) @ptrCast(_XPrivDisplay, @alignCast(@alignOf(_XPrivDisplay.Child), dpy)) else if (@typeInfo(@TypeOf(dpy)) == .Int and @typeInfo(_XPrivDisplay) == .Pointer) @intToPtr(_XPrivDisplay, dpy) else @as(_XPrivDisplay, dpy)).*.default_screen) {2908 \\pub inline fn DefaultScreen(dpy: var) @TypeOf((@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen) {
2909 \\ return (if (@typeInfo(@TypeOf(dpy)) == .Pointer) @ptrCast(_XPrivDisplay, @alignCast(@alignOf(_XPrivDisplay.Child), dpy)) else if (@typeInfo(@TypeOf(dpy)) == .Int and @typeInfo(_XPrivDisplay) == .Pointer) @intToPtr(_XPrivDisplay, dpy) else @as(_XPrivDisplay, dpy)).*.default_screen;2909 \\ return (@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen;
2910 \\}2910 \\}
2911 });2911 });
29122912
...@@ -2914,9 +2914,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2914,9 +2914,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2914 \\#define NULL ((void*)0)2914 \\#define NULL ((void*)0)
2915 \\#define FOO ((int)0x8000)2915 \\#define FOO ((int)0x8000)
2916 , &[_][]const u8{2916 , &[_][]const u8{
2917 \\pub const NULL = (if (@typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, 0) else @as(?*c_void, 0));2917 \\pub const NULL = (@import("std").meta.cast(?*c_void, 0));
2918 ,2918 ,
2919 \\pub const FOO = (if (@typeInfo(c_int) == .Pointer) @intToPtr(c_int, 0x8000) else @as(c_int, 0x8000));2919 \\pub const FOO = (@import("std").meta.cast(c_int, 0x8000));
2920 });2920 });
29212921
2922 if (std.Target.current.abi == .msvc) {2922 if (std.Target.current.abi == .msvc) {