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
288288 "${CMAKE_SOURCE_DIR}/src/target.cpp"
289289 "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
290290 "${CMAKE_SOURCE_DIR}/src/util.cpp"
291 "${CMAKE_SOURCE_DIR}/src/softfloat_ext.cpp"
291292 "${ZIG_SOURCES_MEM_PROFILE}"
292293)
293294set(OPTIMIZED_C_SOURCES
build.zig+4-1
......@@ -139,7 +139,10 @@ pub fn build(b: *Builder) !void {
139139 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
140140 test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));
141141 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);
143146 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
144147 test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
145148 test_step.dependOn(tests.addTranslateCTests(b, test_filter));
doc/langref.html.in+79-80
......@@ -236,19 +236,18 @@ pub fn main() !void {
236236}
237237 {#code_end#}
238238 <p>
239 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 want
241 to emit. For that you can use a simpler API:
239 Usually you don't want to write to stdout. You want to write to stderr, and you
240 don't care if it fails. For that you can use a simpler API:
242241 </p>
243242 {#code_begin|exe|hello#}
244const warn = @import("std").debug.warn;
243const print = @import("std").debug.print;
245244
246245pub fn main() void {
247 warn("Hello, world!\n", .{});
246 print("Hello, world!\n", .{});
248247}
249248 {#code_end#}
250249 <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.
252251 </p>
253252 {#see_also|Values|@import|Errors|Root Source File#}
254253 {#header_close#}
......@@ -307,7 +306,7 @@ const Timestamp = struct {
307306 {#header_open|Values#}
308307 {#code_begin|exe|values#}
309308// Top-level declarations are order-independent:
310const warn = std.debug.warn;
309const print = std.debug.print;
311310const std = @import("std");
312311const os = std.os;
313312const assert = std.debug.assert;
......@@ -315,14 +314,14 @@ const assert = std.debug.assert;
315314pub fn main() void {
316315 // integers
317316 const one_plus_one: i32 = 1 + 1;
318 warn("1 + 1 = {}\n", .{one_plus_one});
317 print("1 + 1 = {}\n", .{one_plus_one});
319318
320319 // floats
321320 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
324323 // boolean
325 warn("{}\n{}\n{}\n", .{
324 print("{}\n{}\n{}\n", .{
326325 true and false,
327326 true or false,
328327 !true,
......@@ -332,7 +331,7 @@ pub fn main() void {
332331 var optional_value: ?[]const u8 = null;
333332 assert(optional_value == null);
334333
335 warn("\noptional 1\ntype: {}\nvalue: {}\n", .{
334 print("\noptional 1\ntype: {}\nvalue: {}\n", .{
336335 @typeName(@TypeOf(optional_value)),
337336 optional_value,
338337 });
......@@ -340,7 +339,7 @@ pub fn main() void {
340339 optional_value = "hi";
341340 assert(optional_value != null);
342341
343 warn("\noptional 2\ntype: {}\nvalue: {}\n", .{
342 print("\noptional 2\ntype: {}\nvalue: {}\n", .{
344343 @typeName(@TypeOf(optional_value)),
345344 optional_value,
346345 });
......@@ -348,14 +347,14 @@ pub fn main() void {
348347 // error union
349348 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", .{
352351 @typeName(@TypeOf(number_or_error)),
353352 number_or_error,
354353 });
355354
356355 number_or_error = 1234;
357356
358 warn("\nerror union 2\ntype: {}\nvalue: {}\n", .{
357 print("\nerror union 2\ntype: {}\nvalue: {}\n", .{
359358 @typeName(@TypeOf(number_or_error)),
360359 number_or_error,
361360 });
......@@ -994,15 +993,15 @@ export fn foo_optimized(x: f64) f64 {
994993 which operates in strict mode.</p>
995994 {#code_begin|exe|float_mode#}
996995 {#code_link_object|foo#}
997const warn = @import("std").debug.warn;
996const print = @import("std").debug.print;
998997
999998extern fn foo_strict(x: f64) f64;
1000999extern fn foo_optimized(x: f64) f64;
10011000
10021001pub fn main() void {
10031002 const x = 0.001;
1004 warn("optimized = {}\n", .{foo_optimized(x)});
1005 warn("strict = {}\n", .{foo_strict(x)});
1003 print("optimized = {}\n", .{foo_optimized(x)});
1004 print("strict = {}\n", .{foo_strict(x)});
10061005}
10071006 {#code_end#}
10081007 {#see_also|@setFloatMode|Division by Zero#}
......@@ -2668,9 +2667,9 @@ const std = @import("std");
26682667
26692668pub fn main() void {
26702669 const Foo = struct {};
2671 std.debug.warn("variable: {}\n", .{@typeName(Foo)});
2672 std.debug.warn("anonymous: {}\n", .{@typeName(struct {})});
2673 std.debug.warn("function: {}\n", .{@typeName(List(i32))});
2670 std.debug.print("variable: {}\n", .{@typeName(Foo)});
2671 std.debug.print("anonymous: {}\n", .{@typeName(struct {})});
2672 std.debug.print("function: {}\n", .{@typeName(List(i32))});
26742673}
26752674
26762675fn List(comptime T: type) type {
......@@ -3869,7 +3868,7 @@ test "if error union" {
38693868 {#code_begin|test|defer#}
38703869const std = @import("std");
38713870const assert = std.debug.assert;
3872const warn = std.debug.warn;
3871const print = std.debug.print;
38733872
38743873// defer will execute an expression at the end of the current scope.
38753874fn deferExample() usize {
......@@ -3892,18 +3891,18 @@ test "defer basics" {
38923891// If multiple defer statements are specified, they will be executed in
38933892// the reverse order they were run.
38943893fn deferUnwindExample() void {
3895 warn("\n", .{});
3894 print("\n", .{});
38963895
38973896 defer {
3898 warn("1 ", .{});
3897 print("1 ", .{});
38993898 }
39003899 defer {
3901 warn("2 ", .{});
3900 print("2 ", .{});
39023901 }
39033902 if (false) {
39043903 // defers are not run if they are never executed.
39053904 defer {
3906 warn("3 ", .{});
3905 print("3 ", .{});
39073906 }
39083907 }
39093908}
......@@ -3918,15 +3917,15 @@ test "defer unwinding" {
39183917// This is especially useful in allowing a function to clean up properly
39193918// on error, and replaces goto error handling tactics as seen in c.
39203919fn deferErrorExample(is_error: bool) !void {
3921 warn("\nstart of function\n", .{});
3920 print("\nstart of function\n", .{});
39223921
39233922 // This will always be executed on exit
39243923 defer {
3925 warn("end of function\n", .{});
3924 print("end of function\n", .{});
39263925 }
39273926
39283927 errdefer {
3929 warn("encountered an error!\n", .{});
3928 print("encountered an error!\n", .{});
39303929 }
39313930
39323931 if (is_error) {
......@@ -5925,13 +5924,13 @@ const Node = struct {
59255924 Putting all of this together, let's see how {#syntax#}printf{#endsyntax#} works in Zig.
59265925 </p>
59275926 {#code_begin|exe|printf#}
5928const warn = @import("std").debug.warn;
5927const print = @import("std").debug.print;
59295928
59305929const a_number: i32 = 1234;
59315930const a_string = "foobar";
59325931
59335932pub 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});
59355934}
59365935 {#code_end#}
59375936
......@@ -6045,13 +6044,13 @@ pub fn printValue(self: *OutStream, value: var) !void {
60456044 And now, what happens if we give too many arguments to {#syntax#}printf{#endsyntax#}?
60466045 </p>
60476046 {#code_begin|test_err|Unused arguments#}
6048const warn = @import("std").debug.warn;
6047const print = @import("std").debug.print;
60496048
60506049const a_number: i32 = 1234;
60516050const a_string = "foobar";
60526051
60536052test "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", .{
60556054 a_string,
60566055 a_number,
60576056 a_number,
......@@ -6066,14 +6065,14 @@ test "printf too many arguments" {
60666065 only that it is a compile-time known value that can be coerced to a {#syntax#}[]const u8{#endsyntax#}:
60676066 </p>
60686067 {#code_begin|exe|printf#}
6069const warn = @import("std").debug.warn;
6068const print = @import("std").debug.print;
60706069
60716070const a_number: i32 = 1234;
60726071const a_string = "foobar";
60736072const fmt = "here is a string: '{}' here is a number: {}\n";
60746073
60756074pub fn main() void {
6076 warn(fmt, .{a_string, a_number});
6075 print(fmt, .{a_string, a_number});
60776076}
60786077 {#code_end#}
60796078 <p>
......@@ -6511,7 +6510,7 @@ pub fn main() void {
65116510
65126511fn amainWrap() void {
65136512 amain() catch |e| {
6514 std.debug.warn("{}\n", .{e});
6513 std.debug.print("{}\n", .{e});
65156514 if (@errorReturnTrace()) |trace| {
65166515 std.debug.dumpStackTrace(trace.*);
65176516 }
......@@ -6541,8 +6540,8 @@ fn amain() !void {
65416540 const download_text = try await download_frame;
65426541 defer allocator.free(download_text);
65436542
6544 std.debug.warn("download_text: {}\n", .{download_text});
6545 std.debug.warn("file_text: {}\n", .{file_text});
6543 std.debug.print("download_text: {}\n", .{download_text});
6544 std.debug.print("file_text: {}\n", .{file_text});
65466545}
65476546
65486547var global_download_frame: anyframe = undefined;
......@@ -6552,7 +6551,7 @@ fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
65526551 suspend {
65536552 global_download_frame = @frame();
65546553 }
6555 std.debug.warn("fetchUrl returning\n", .{});
6554 std.debug.print("fetchUrl returning\n", .{});
65566555 return result;
65576556}
65586557
......@@ -6563,7 +6562,7 @@ fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
65636562 suspend {
65646563 global_file_frame = @frame();
65656564 }
6566 std.debug.warn("readFile returning\n", .{});
6565 std.debug.print("readFile returning\n", .{});
65676566 return result;
65686567}
65696568 {#code_end#}
......@@ -6581,7 +6580,7 @@ pub fn main() void {
65816580
65826581fn amainWrap() void {
65836582 amain() catch |e| {
6584 std.debug.warn("{}\n", .{e});
6583 std.debug.print("{}\n", .{e});
65856584 if (@errorReturnTrace()) |trace| {
65866585 std.debug.dumpStackTrace(trace.*);
65876586 }
......@@ -6611,21 +6610,21 @@ fn amain() !void {
66116610 const download_text = try await download_frame;
66126611 defer allocator.free(download_text);
66136612
6614 std.debug.warn("download_text: {}\n", .{download_text});
6615 std.debug.warn("file_text: {}\n", .{file_text});
6613 std.debug.print("download_text: {}\n", .{download_text});
6614 std.debug.print("file_text: {}\n", .{file_text});
66166615}
66176616
66186617fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
66196618 const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");
66206619 errdefer allocator.free(result);
6621 std.debug.warn("fetchUrl returning\n", .{});
6620 std.debug.print("fetchUrl returning\n", .{});
66226621 return result;
66236622}
66246623
66256624fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
66266625 const result = try std.mem.dupe(allocator, u8, "this is the file contents");
66276626 errdefer allocator.free(result);
6628 std.debug.warn("readFile returning\n", .{});
6627 std.debug.print("readFile returning\n", .{});
66296628 return result;
66306629}
66316630 {#code_end#}
......@@ -7121,7 +7120,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
71217120 compile-time executing code.
71227121 </p>
71237122 {#code_begin|test_err|found compile log statement#}
7124const warn = @import("std").debug.warn;
7123const print = @import("std").debug.print;
71257124
71267125const num1 = blk: {
71277126 var val1: i32 = 99;
......@@ -7133,7 +7132,7 @@ const num1 = blk: {
71337132test "main" {
71347133 @compileLog("comptime in main");
71357134
7136 warn("Runtime in main, num1 = {}.\n", .{num1});
7135 print("Runtime in main, num1 = {}.\n", .{num1});
71377136}
71387137 {#code_end#}
71397138 <p>
......@@ -7145,7 +7144,7 @@ test "main" {
71457144 program compiles successfully and the generated executable prints:
71467145 </p>
71477146 {#code_begin|test#}
7148const warn = @import("std").debug.warn;
7147const print = @import("std").debug.print;
71497148
71507149const num1 = blk: {
71517150 var val1: i32 = 99;
......@@ -7154,7 +7153,7 @@ const num1 = blk: {
71547153};
71557154
71567155test "main" {
7157 warn("Runtime in main, num1 = {}.\n", .{num1});
7156 print("Runtime in main, num1 = {}.\n", .{num1});
71587157}
71597158 {#code_end#}
71607159 {#header_close#}
......@@ -8205,7 +8204,7 @@ test "vector @splat" {
82058204 {#header_open|@This#}
82068205 <pre>{#syntax#}@This() type{#endsyntax#}</pre>
82078206 <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.
82098208 This can be useful for an anonymous struct that needs to refer to itself:
82108209 </p>
82118210 {#code_begin|test#}
......@@ -8555,7 +8554,7 @@ const std = @import("std");
85558554pub fn main() void {
85568555 var value: i32 = -1;
85578556 var unsigned = @intCast(u32, value);
8558 std.debug.warn("value: {}\n", .{unsigned});
8557 std.debug.print("value: {}\n", .{unsigned});
85598558}
85608559 {#code_end#}
85618560 <p>
......@@ -8577,7 +8576,7 @@ const std = @import("std");
85778576pub fn main() void {
85788577 var spartan_count: u16 = 300;
85798578 const byte = @intCast(u8, spartan_count);
8580 std.debug.warn("value: {}\n", .{byte});
8579 std.debug.print("value: {}\n", .{byte});
85818580}
85828581 {#code_end#}
85838582 <p>
......@@ -8611,7 +8610,7 @@ const std = @import("std");
86118610pub fn main() void {
86128611 var byte: u8 = 255;
86138612 byte += 1;
8614 std.debug.warn("value: {}\n", .{byte});
8613 std.debug.print("value: {}\n", .{byte});
86158614}
86168615 {#code_end#}
86178616 {#header_close#}
......@@ -8629,16 +8628,16 @@ pub fn main() void {
86298628 <p>Example of catching an overflow for addition:</p>
86308629 {#code_begin|exe_err#}
86318630const math = @import("std").math;
8632const warn = @import("std").debug.warn;
8631const print = @import("std").debug.print;
86338632pub fn main() !void {
86348633 var byte: u8 = 255;
86358634
86368635 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)});
86388637 return err;
86398638 };
86408639
8641 warn("result: {}\n", .{byte});
8640 print("result: {}\n", .{byte});
86428641}
86438642 {#code_end#}
86448643 {#header_close#}
......@@ -8657,15 +8656,15 @@ pub fn main() !void {
86578656 Example of {#link|@addWithOverflow#}:
86588657 </p>
86598658 {#code_begin|exe#}
8660const warn = @import("std").debug.warn;
8659const print = @import("std").debug.print;
86618660pub fn main() void {
86628661 var byte: u8 = 255;
86638662
86648663 var result: u8 = undefined;
86658664 if (@addWithOverflow(u8, byte, 10, &result)) {
8666 warn("overflowed result: {}\n", .{result});
8665 print("overflowed result: {}\n", .{result});
86678666 } else {
8668 warn("result: {}\n", .{result});
8667 print("result: {}\n", .{result});
86698668 }
86708669}
86718670 {#code_end#}
......@@ -8710,7 +8709,7 @@ const std = @import("std");
87108709pub fn main() void {
87118710 var x: u8 = 0b01010101;
87128711 var y = @shlExact(x, 2);
8713 std.debug.warn("value: {}\n", .{y});
8712 std.debug.print("value: {}\n", .{y});
87148713}
87158714 {#code_end#}
87168715 {#header_close#}
......@@ -8728,7 +8727,7 @@ const std = @import("std");
87288727pub fn main() void {
87298728 var x: u8 = 0b10101010;
87308729 var y = @shrExact(x, 2);
8731 std.debug.warn("value: {}\n", .{y});
8730 std.debug.print("value: {}\n", .{y});
87328731}
87338732 {#code_end#}
87348733 {#header_close#}
......@@ -8749,7 +8748,7 @@ pub fn main() void {
87498748 var a: u32 = 1;
87508749 var b: u32 = 0;
87518750 var c = a / b;
8752 std.debug.warn("value: {}\n", .{c});
8751 std.debug.print("value: {}\n", .{c});
87538752}
87548753 {#code_end#}
87558754 {#header_close#}
......@@ -8770,7 +8769,7 @@ pub fn main() void {
87708769 var a: u32 = 10;
87718770 var b: u32 = 0;
87728771 var c = a % b;
8773 std.debug.warn("value: {}\n", .{c});
8772 std.debug.print("value: {}\n", .{c});
87748773}
87758774 {#code_end#}
87768775 {#header_close#}
......@@ -8791,7 +8790,7 @@ pub fn main() void {
87918790 var a: u32 = 10;
87928791 var b: u32 = 3;
87938792 var c = @divExact(a, b);
8794 std.debug.warn("value: {}\n", .{c});
8793 std.debug.print("value: {}\n", .{c});
87958794}
87968795 {#code_end#}
87978796 {#header_close#}
......@@ -8810,20 +8809,20 @@ const std = @import("std");
88108809pub fn main() void {
88118810 var optional_number: ?i32 = null;
88128811 var number = optional_number.?;
8813 std.debug.warn("value: {}\n", .{number});
8812 std.debug.print("value: {}\n", .{number});
88148813}
88158814 {#code_end#}
88168815 <p>One way to avoid this crash is to test for null instead of assuming non-null, with
88178816 the {#syntax#}if{#endsyntax#} expression:</p>
88188817 {#code_begin|exe|test#}
8819const warn = @import("std").debug.warn;
8818const print = @import("std").debug.print;
88208819pub fn main() void {
88218820 const optional_number: ?i32 = null;
88228821
88238822 if (optional_number) |number| {
8824 warn("got number: {}\n", .{number});
8823 print("got number: {}\n", .{number});
88258824 } else {
8826 warn("it's null\n", .{});
8825 print("it's null\n", .{});
88278826 }
88288827}
88298828 {#code_end#}
......@@ -8846,7 +8845,7 @@ const std = @import("std");
88468845
88478846pub fn main() void {
88488847 const number = getNumberOrFail() catch unreachable;
8849 std.debug.warn("value: {}\n", .{number});
8848 std.debug.print("value: {}\n", .{number});
88508849}
88518850
88528851fn getNumberOrFail() !i32 {
......@@ -8856,15 +8855,15 @@ fn getNumberOrFail() !i32 {
88568855 <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with
88578856 the {#syntax#}if{#endsyntax#} expression:</p>
88588857 {#code_begin|exe#}
8859const warn = @import("std").debug.warn;
8858const print = @import("std").debug.print;
88608859
88618860pub fn main() void {
88628861 const result = getNumberOrFail();
88638862
88648863 if (result) |number| {
8865 warn("got number: {}\n", .{number});
8864 print("got number: {}\n", .{number});
88668865 } else |err| {
8867 warn("got error: {}\n", .{@errorName(err)});
8866 print("got error: {}\n", .{@errorName(err)});
88688867 }
88698868}
88708869
......@@ -8891,7 +8890,7 @@ pub fn main() void {
88918890 var err = error.AnError;
88928891 var number = @errorToInt(err) + 500;
88938892 var invalid_err = @intToError(number);
8894 std.debug.warn("value: {}\n", .{number});
8893 std.debug.print("value: {}\n", .{number});
88958894}
88968895 {#code_end#}
88978896 {#header_close#}
......@@ -8921,7 +8920,7 @@ const Foo = enum {
89218920pub fn main() void {
89228921 var a: u2 = 3;
89238922 var b = @intToEnum(Foo, a);
8924 std.debug.warn("value: {}\n", .{@tagName(b)});
8923 std.debug.print("value: {}\n", .{@tagName(b)});
89258924}
89268925 {#code_end#}
89278926 {#header_close#}
......@@ -8958,7 +8957,7 @@ pub fn main() void {
89588957}
89598958fn foo(set1: Set1) void {
89608959 const x = @errSetCast(Set2, set1);
8961 std.debug.warn("value: {}\n", .{x});
8960 std.debug.print("value: {}\n", .{x});
89628961}
89638962 {#code_end#}
89648963 {#header_close#}
......@@ -9015,7 +9014,7 @@ pub fn main() void {
90159014
90169015fn bar(f: *Foo) void {
90179016 f.float = 12.34;
9018 std.debug.warn("value: {}\n", .{f.float});
9017 std.debug.print("value: {}\n", .{f.float});
90199018}
90209019 {#code_end#}
90219020 <p>
......@@ -9039,7 +9038,7 @@ pub fn main() void {
90399038
90409039fn bar(f: *Foo) void {
90419040 f.* = Foo{ .float = 12.34 };
9042 std.debug.warn("value: {}\n", .{f.float});
9041 std.debug.print("value: {}\n", .{f.float});
90439042}
90449043 {#code_end#}
90459044 <p>
......@@ -9058,7 +9057,7 @@ pub fn main() void {
90589057 var f = Foo{ .int = 42 };
90599058 f = Foo{ .float = undefined };
90609059 bar(&f);
9061 std.debug.warn("value: {}\n", .{f.float});
9060 std.debug.print("value: {}\n", .{f.float});
90629061}
90639062
90649063fn bar(f: *Foo) void {
......@@ -9178,7 +9177,7 @@ pub fn main() !void {
91789177 const allocator = &arena.allocator;
91799178
91809179 const ptr = try allocator.create(i32);
9181 std.debug.warn("ptr={*}\n", .{ptr});
9180 std.debug.print("ptr={*}\n", .{ptr});
91829181}
91839182 {#code_end#}
91849183 When using this kind of allocator, there is no need to free anything manually. Everything
......@@ -9712,7 +9711,7 @@ pub fn main() !void {
97129711 defer std.process.argsFree(std.heap.page_allocator, args);
97139712
97149713 for (args) |arg, i| {
9715 std.debug.warn("{}: {}\n", .{i, arg});
9714 std.debug.print("{}: {}\n", .{i, arg});
97169715 }
97179716}
97189717 {#code_end#}
......@@ -9734,7 +9733,7 @@ pub fn main() !void {
97349733 try preopens.populate();
97359734
97369735 for (preopens.asSlice()) |preopen, i| {
9737 std.debug.warn("{}: {}\n", .{ i, preopen });
9736 std.debug.print("{}: {}\n", .{ i, preopen });
97389737 }
97399738}
97409739 {#code_end#}
lib/std/array_list.zig+1-1
......@@ -162,7 +162,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
162162 mem.copy(T, self.items[oldlen..], items);
163163 }
164164
165 pub usingnamespace if (T != u8) struct { } else struct {
165 pub usingnamespace if (T != u8) struct {} else struct {
166166 pub const Writer = std.io.Writer(*Self, error{OutOfMemory}, appendWrite);
167167
168168 /// Initializes a Writer which will append to the list.
lib/std/build.zig+7
......@@ -2559,3 +2559,10 @@ pub const InstalledFile = struct {
25592559 dir: InstallDir,
25602560 path: []const u8,
25612561};
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 {
215215 try emitRaw(builder.allocator, full_src_path, full_dest_path);
216216 }
217217};
218
219test "" {
220 std.meta.refAllDecls(InstallRawStep);
221}
lib/std/builtin.zig+17-10
......@@ -166,7 +166,7 @@ pub const TypeInfo = union(enum) {
166166 Fn: Fn,
167167 BoundFn: Fn,
168168 Opaque: void,
169 Frame: void,
169 Frame: Frame,
170170 AnyFrame: AnyFrame,
171171 Vector: Vector,
172172 EnumLiteral: void,
......@@ -244,8 +244,8 @@ pub const TypeInfo = union(enum) {
244244 /// therefore must be kept in sync with the compiler implementation.
245245 pub const Struct = struct {
246246 layout: ContainerLayout,
247 fields: []StructField,
248 decls: []Declaration,
247 fields: []const StructField,
248 decls: []const Declaration,
249249 };
250250
251251 /// This data structure is used by the Zig language code generation and
......@@ -265,12 +265,13 @@ pub const TypeInfo = union(enum) {
265265 /// therefore must be kept in sync with the compiler implementation.
266266 pub const Error = struct {
267267 name: []const u8,
268 /// This field is ignored when using @Type().
268269 value: comptime_int,
269270 };
270271
271272 /// This data structure is used by the Zig language code generation and
272273 /// therefore must be kept in sync with the compiler implementation.
273 pub const ErrorSet = ?[]Error;
274 pub const ErrorSet = ?[]const Error;
274275
275276 /// This data structure is used by the Zig language code generation and
276277 /// therefore must be kept in sync with the compiler implementation.
......@@ -284,8 +285,8 @@ pub const TypeInfo = union(enum) {
284285 pub const Enum = struct {
285286 layout: ContainerLayout,
286287 tag_type: type,
287 fields: []EnumField,
288 decls: []Declaration,
288 fields: []const EnumField,
289 decls: []const Declaration,
289290 is_exhaustive: bool,
290291 };
291292
......@@ -302,8 +303,8 @@ pub const TypeInfo = union(enum) {
302303 pub const Union = struct {
303304 layout: ContainerLayout,
304305 tag_type: ?type,
305 fields: []UnionField,
306 decls: []Declaration,
306 fields: []const UnionField,
307 decls: []const Declaration,
307308 };
308309
309310 /// This data structure is used by the Zig language code generation and
......@@ -321,7 +322,13 @@ pub const TypeInfo = union(enum) {
321322 is_generic: bool,
322323 is_var_args: bool,
323324 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,
325332 };
326333
327334 /// This data structure is used by the Zig language code generation and
......@@ -361,7 +368,7 @@ pub const TypeInfo = union(enum) {
361368 is_export: bool,
362369 lib_name: ?[]const u8,
363370 return_type: type,
364 arg_names: [][]const u8,
371 arg_names: []const []const u8,
365372
366373 /// This data structure is used by the Zig language code generation and
367374 /// 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;
102102pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int;
103103pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int;
104104pub 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;
105106pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int;
106107pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int;
107108pub 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 {
278278
279279 // TODO extensions
280280 pub const keywords = std.ComptimeStringMap(Id, .{
281 .{"auto", .Keyword_auto},
282 .{"break", .Keyword_break},
283 .{"case", .Keyword_case},
284 .{"char", .Keyword_char},
285 .{"const", .Keyword_const},
286 .{"continue", .Keyword_continue},
287 .{"default", .Keyword_default},
288 .{"do", .Keyword_do},
289 .{"double", .Keyword_double},
290 .{"else", .Keyword_else},
291 .{"enum", .Keyword_enum},
292 .{"extern", .Keyword_extern},
293 .{"float", .Keyword_float},
294 .{"for", .Keyword_for},
295 .{"goto", .Keyword_goto},
296 .{"if", .Keyword_if},
297 .{"int", .Keyword_int},
298 .{"long", .Keyword_long},
299 .{"register", .Keyword_register},
300 .{"return", .Keyword_return},
301 .{"short", .Keyword_short},
302 .{"signed", .Keyword_signed},
303 .{"sizeof", .Keyword_sizeof},
304 .{"static", .Keyword_static},
305 .{"struct", .Keyword_struct},
306 .{"switch", .Keyword_switch},
307 .{"typedef", .Keyword_typedef},
308 .{"union", .Keyword_union},
309 .{"unsigned", .Keyword_unsigned},
310 .{"void", .Keyword_void},
311 .{"volatile", .Keyword_volatile},
312 .{"while", .Keyword_while},
281 .{ "auto", .Keyword_auto },
282 .{ "break", .Keyword_break },
283 .{ "case", .Keyword_case },
284 .{ "char", .Keyword_char },
285 .{ "const", .Keyword_const },
286 .{ "continue", .Keyword_continue },
287 .{ "default", .Keyword_default },
288 .{ "do", .Keyword_do },
289 .{ "double", .Keyword_double },
290 .{ "else", .Keyword_else },
291 .{ "enum", .Keyword_enum },
292 .{ "extern", .Keyword_extern },
293 .{ "float", .Keyword_float },
294 .{ "for", .Keyword_for },
295 .{ "goto", .Keyword_goto },
296 .{ "if", .Keyword_if },
297 .{ "int", .Keyword_int },
298 .{ "long", .Keyword_long },
299 .{ "register", .Keyword_register },
300 .{ "return", .Keyword_return },
301 .{ "short", .Keyword_short },
302 .{ "signed", .Keyword_signed },
303 .{ "sizeof", .Keyword_sizeof },
304 .{ "static", .Keyword_static },
305 .{ "struct", .Keyword_struct },
306 .{ "switch", .Keyword_switch },
307 .{ "typedef", .Keyword_typedef },
308 .{ "union", .Keyword_union },
309 .{ "unsigned", .Keyword_unsigned },
310 .{ "void", .Keyword_void },
311 .{ "volatile", .Keyword_volatile },
312 .{ "while", .Keyword_while },
313313
314314 // ISO C99
315 .{"_Bool", .Keyword_bool},
316 .{"_Complex", .Keyword_complex},
317 .{"_Imaginary", .Keyword_imaginary},
318 .{"inline", .Keyword_inline},
319 .{"restrict", .Keyword_restrict},
315 .{ "_Bool", .Keyword_bool },
316 .{ "_Complex", .Keyword_complex },
317 .{ "_Imaginary", .Keyword_imaginary },
318 .{ "inline", .Keyword_inline },
319 .{ "restrict", .Keyword_restrict },
320320
321321 // ISO C11
322 .{"_Alignas", .Keyword_alignas},
323 .{"_Alignof", .Keyword_alignof},
324 .{"_Atomic", .Keyword_atomic},
325 .{"_Generic", .Keyword_generic},
326 .{"_Noreturn", .Keyword_noreturn},
327 .{"_Static_assert", .Keyword_static_assert},
328 .{"_Thread_local", .Keyword_thread_local},
322 .{ "_Alignas", .Keyword_alignas },
323 .{ "_Alignof", .Keyword_alignof },
324 .{ "_Atomic", .Keyword_atomic },
325 .{ "_Generic", .Keyword_generic },
326 .{ "_Noreturn", .Keyword_noreturn },
327 .{ "_Static_assert", .Keyword_static_assert },
328 .{ "_Thread_local", .Keyword_thread_local },
329329
330330 // Preprocessor directives
331 .{"include", .Keyword_include},
332 .{"define", .Keyword_define},
333 .{"ifdef", .Keyword_ifdef},
334 .{"ifndef", .Keyword_ifndef},
335 .{"error", .Keyword_error},
336 .{"pragma", .Keyword_pragma},
331 .{ "include", .Keyword_include },
332 .{ "define", .Keyword_define },
333 .{ "ifdef", .Keyword_ifdef },
334 .{ "ifndef", .Keyword_ifndef },
335 .{ "error", .Keyword_error },
336 .{ "pragma", .Keyword_pragma },
337337 });
338338
339339 // TODO do this in the preprocessor
lib/std/debug.zig+7-3
......@@ -52,9 +52,13 @@ pub const LineInfo = struct {
5252
5353var stderr_mutex = std.Mutex.init();
5454
55/// Tries to write to stderr, unbuffered, and ignores any error returned.
56/// Does not append a newline.
57pub fn warn(comptime fmt: []const u8, args: var) void {
55/// Deprecated. Use `std.log` functions for logging or `std.debug.print` for
56/// "printf debugging".
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 {
5862 const held = stderr_mutex.acquire();
5963 defer held.release();
6064 const stderr = io.getStdErr().writer();
lib/std/fmt.zig+175-175
......@@ -69,14 +69,14 @@ fn peekIsAlign(comptime fmt: []const u8) bool {
6969///
7070/// If a formatted user type contains a function of the type
7171/// ```
72/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void
72/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: var) !void
7373/// ```
7474/// with `?` being the type formatted, this function will be called instead of the default implementation.
7575/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
7676///
7777/// A user type may be a `struct`, `vector`, `union` or `enum` type.
7878pub fn format(
79 out_stream: var,
79 writer: var,
8080 comptime fmt: []const u8,
8181 args: var,
8282) !void {
......@@ -136,7 +136,7 @@ pub fn format(
136136 .Start => switch (c) {
137137 '{' => {
138138 if (start_index < i) {
139 try out_stream.writeAll(fmt[start_index..i]);
139 try writer.writeAll(fmt[start_index..i]);
140140 }
141141
142142 start_index = i;
......@@ -148,7 +148,7 @@ pub fn format(
148148 },
149149 '}' => {
150150 if (start_index < i) {
151 try out_stream.writeAll(fmt[start_index..i]);
151 try writer.writeAll(fmt[start_index..i]);
152152 }
153153 state = .CloseBrace;
154154 },
......@@ -183,7 +183,7 @@ pub fn format(
183183 args[arg_to_print],
184184 fmt[0..0],
185185 options,
186 out_stream,
186 writer,
187187 default_max_depth,
188188 );
189189
......@@ -214,7 +214,7 @@ pub fn format(
214214 args[arg_to_print],
215215 fmt[specifier_start..i],
216216 options,
217 out_stream,
217 writer,
218218 default_max_depth,
219219 );
220220 state = .Start;
......@@ -259,7 +259,7 @@ pub fn format(
259259 args[arg_to_print],
260260 fmt[specifier_start..specifier_end],
261261 options,
262 out_stream,
262 writer,
263263 default_max_depth,
264264 );
265265 state = .Start;
......@@ -285,7 +285,7 @@ pub fn format(
285285 args[arg_to_print],
286286 fmt[specifier_start..specifier_end],
287287 options,
288 out_stream,
288 writer,
289289 default_max_depth,
290290 );
291291 state = .Start;
......@@ -306,7 +306,7 @@ pub fn format(
306306 }
307307 }
308308 if (start_index < fmt.len) {
309 try out_stream.writeAll(fmt[start_index..]);
309 try writer.writeAll(fmt[start_index..]);
310310 }
311311}
312312
......@@ -314,140 +314,140 @@ pub fn formatType(
314314 value: var,
315315 comptime fmt: []const u8,
316316 options: FormatOptions,
317 out_stream: var,
317 writer: var,
318318 max_depth: usize,
319) @TypeOf(out_stream).Error!void {
319) @TypeOf(writer).Error!void {
320320 if (comptime std.mem.eql(u8, fmt, "*")) {
321 try out_stream.writeAll(@typeName(@TypeOf(value).Child));
322 try out_stream.writeAll("@");
323 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, out_stream);
321 try writer.writeAll(@typeName(@TypeOf(value).Child));
322 try writer.writeAll("@");
323 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
324324 return;
325325 }
326326
327327 const T = @TypeOf(value);
328328 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);
330330 }
331331
332332 switch (@typeInfo(T)) {
333333 .ComptimeInt, .Int, .ComptimeFloat, .Float => {
334 return formatValue(value, fmt, options, out_stream);
334 return formatValue(value, fmt, options, writer);
335335 },
336336 .Void => {
337 return formatBuf("void", options, out_stream);
337 return formatBuf("void", options, writer);
338338 },
339339 .Bool => {
340 return formatBuf(if (value) "true" else "false", options, out_stream);
340 return formatBuf(if (value) "true" else "false", options, writer);
341341 },
342342 .Optional => {
343343 if (value) |payload| {
344 return formatType(payload, fmt, options, out_stream, max_depth);
344 return formatType(payload, fmt, options, writer, max_depth);
345345 } else {
346 return formatBuf("null", options, out_stream);
346 return formatBuf("null", options, writer);
347347 }
348348 },
349349 .ErrorUnion => {
350350 if (value) |payload| {
351 return formatType(payload, fmt, options, out_stream, max_depth);
351 return formatType(payload, fmt, options, writer, max_depth);
352352 } else |err| {
353 return formatType(err, fmt, options, out_stream, max_depth);
353 return formatType(err, fmt, options, writer, max_depth);
354354 }
355355 },
356356 .ErrorSet => {
357 try out_stream.writeAll("error.");
358 return out_stream.writeAll(@errorName(value));
357 try writer.writeAll("error.");
358 return writer.writeAll(@errorName(value));
359359 },
360360 .Enum => |enumInfo| {
361 try out_stream.writeAll(@typeName(T));
361 try writer.writeAll(@typeName(T));
362362 if (enumInfo.is_exhaustive) {
363 try out_stream.writeAll(".");
364 try out_stream.writeAll(@tagName(value));
363 try writer.writeAll(".");
364 try writer.writeAll(@tagName(value));
365365 return;
366366 }
367367
368368 // Use @tagName only if value is one of known fields
369369 inline for (enumInfo.fields) |enumField| {
370370 if (@enumToInt(value) == enumField.value) {
371 try out_stream.writeAll(".");
372 try out_stream.writeAll(@tagName(value));
371 try writer.writeAll(".");
372 try writer.writeAll(@tagName(value));
373373 return;
374374 }
375375 }
376376
377 try out_stream.writeAll("(");
378 try formatType(@enumToInt(value), fmt, options, out_stream, max_depth);
379 try out_stream.writeAll(")");
377 try writer.writeAll("(");
378 try formatType(@enumToInt(value), fmt, options, writer, max_depth);
379 try writer.writeAll(")");
380380 },
381381 .Union => {
382 try out_stream.writeAll(@typeName(T));
382 try writer.writeAll(@typeName(T));
383383 if (max_depth == 0) {
384 return out_stream.writeAll("{ ... }");
384 return writer.writeAll("{ ... }");
385385 }
386386 const info = @typeInfo(T).Union;
387387 if (info.tag_type) |UnionTagType| {
388 try out_stream.writeAll("{ .");
389 try out_stream.writeAll(@tagName(@as(UnionTagType, value)));
390 try out_stream.writeAll(" = ");
388 try writer.writeAll("{ .");
389 try writer.writeAll(@tagName(@as(UnionTagType, value)));
390 try writer.writeAll(" = ");
391391 inline for (info.fields) |u_field| {
392392 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);
394394 }
395395 }
396 try out_stream.writeAll(" }");
396 try writer.writeAll(" }");
397397 } else {
398 try format(out_stream, "@{x}", .{@ptrToInt(&value)});
398 try format(writer, "@{x}", .{@ptrToInt(&value)});
399399 }
400400 },
401401 .Struct => |StructT| {
402 try out_stream.writeAll(@typeName(T));
402 try writer.writeAll(@typeName(T));
403403 if (max_depth == 0) {
404 return out_stream.writeAll("{ ... }");
404 return writer.writeAll("{ ... }");
405405 }
406 try out_stream.writeAll("{");
406 try writer.writeAll("{");
407407 inline for (StructT.fields) |f, i| {
408408 if (i == 0) {
409 try out_stream.writeAll(" .");
409 try writer.writeAll(" .");
410410 } else {
411 try out_stream.writeAll(", .");
411 try writer.writeAll(", .");
412412 }
413 try out_stream.writeAll(f.name);
414 try out_stream.writeAll(" = ");
415 try formatType(@field(value, f.name), fmt, options, out_stream, max_depth - 1);
413 try writer.writeAll(f.name);
414 try writer.writeAll(" = ");
415 try formatType(@field(value, f.name), fmt, options, writer, max_depth - 1);
416416 }
417 try out_stream.writeAll(" }");
417 try writer.writeAll(" }");
418418 },
419419 .Pointer => |ptr_info| switch (ptr_info.size) {
420420 .One => switch (@typeInfo(ptr_info.child)) {
421421 .Array => |info| {
422422 if (info.child == u8) {
423 return formatText(value, fmt, options, out_stream);
423 return formatText(value, fmt, options, writer);
424424 }
425 return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
425 return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
426426 },
427427 .Enum, .Union, .Struct => {
428 return formatType(value.*, fmt, options, out_stream, max_depth);
428 return formatType(value.*, fmt, options, writer, max_depth);
429429 },
430 else => return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
430 else => return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
431431 },
432432 .Many, .C => {
433433 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);
435435 }
436436 if (ptr_info.child == u8) {
437437 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);
439439 }
440440 }
441 return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
441 return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
442442 },
443443 .Slice => {
444444 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);
446446 }
447447 if (ptr_info.child == u8) {
448 return formatText(value, fmt, options, out_stream);
448 return formatText(value, fmt, options, writer);
449449 }
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) });
451451 },
452452 },
453453 .Array => |info| {
......@@ -462,27 +462,27 @@ pub fn formatType(
462462 .sentinel = null,
463463 },
464464 });
465 return formatType(@as(Slice, &value), fmt, options, out_stream, max_depth);
465 return formatType(@as(Slice, &value), fmt, options, writer, max_depth);
466466 },
467467 .Vector => {
468468 const len = @typeInfo(T).Vector.len;
469 try out_stream.writeAll("{ ");
469 try writer.writeAll("{ ");
470470 var i: usize = 0;
471471 while (i < len) : (i += 1) {
472 try formatValue(value[i], fmt, options, out_stream);
472 try formatValue(value[i], fmt, options, writer);
473473 if (i < len - 1) {
474 try out_stream.writeAll(", ");
474 try writer.writeAll(", ");
475475 }
476476 }
477 try out_stream.writeAll(" }");
477 try writer.writeAll(" }");
478478 },
479479 .Fn => {
480 return format(out_stream, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
480 return format(writer, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
481481 },
482 .Type => return out_stream.writeAll(@typeName(T)),
482 .Type => return writer.writeAll(@typeName(T)),
483483 .EnumLiteral => {
484484 const buffer = [_]u8{'.'} ++ @tagName(value);
485 return formatType(buffer, fmt, options, out_stream, max_depth);
485 return formatType(buffer, fmt, options, writer, max_depth);
486486 },
487487 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
488488 }
......@@ -492,19 +492,19 @@ fn formatValue(
492492 value: var,
493493 comptime fmt: []const u8,
494494 options: FormatOptions,
495 out_stream: var,
495 writer: var,
496496) !void {
497497 if (comptime std.mem.eql(u8, fmt, "B")) {
498 return formatBytes(value, options, 1000, out_stream);
498 return formatBytes(value, options, 1000, writer);
499499 } else if (comptime std.mem.eql(u8, fmt, "Bi")) {
500 return formatBytes(value, options, 1024, out_stream);
500 return formatBytes(value, options, 1024, writer);
501501 }
502502
503503 const T = @TypeOf(value);
504504 switch (@typeInfo(T)) {
505 .Float, .ComptimeFloat => return formatFloatValue(value, fmt, options, out_stream),
506 .Int, .ComptimeInt => return formatIntValue(value, fmt, options, out_stream),
507 .Bool => return formatBuf(if (value) "true" else "false", options, out_stream),
505 .Float, .ComptimeFloat => return formatFloatValue(value, fmt, options, writer),
506 .Int, .ComptimeInt => return formatIntValue(value, fmt, options, writer),
507 .Bool => return formatBuf(if (value) "true" else "false", options, writer),
508508 else => comptime unreachable,
509509 }
510510}
......@@ -513,7 +513,7 @@ pub fn formatIntValue(
513513 value: var,
514514 comptime fmt: []const u8,
515515 options: FormatOptions,
516 out_stream: var,
516 writer: var,
517517) !void {
518518 comptime var radix = 10;
519519 comptime var uppercase = false;
......@@ -529,7 +529,7 @@ pub fn formatIntValue(
529529 uppercase = false;
530530 } else if (comptime std.mem.eql(u8, fmt, "c")) {
531531 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);
533533 } else {
534534 @compileError("Cannot print integer that is larger than 8 bits as a ascii");
535535 }
......@@ -546,19 +546,19 @@ pub fn formatIntValue(
546546 @compileError("Unknown format string: '" ++ fmt ++ "'");
547547 }
548548
549 return formatInt(int_value, radix, uppercase, options, out_stream);
549 return formatInt(int_value, radix, uppercase, options, writer);
550550}
551551
552552fn formatFloatValue(
553553 value: var,
554554 comptime fmt: []const u8,
555555 options: FormatOptions,
556 out_stream: var,
556 writer: var,
557557) !void {
558558 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);
560560 } else if (comptime std.mem.eql(u8, fmt, "d")) {
561 return formatFloatDecimal(value, options, out_stream);
561 return formatFloatDecimal(value, options, writer);
562562 } else {
563563 @compileError("Unknown format string: '" ++ fmt ++ "'");
564564 }
......@@ -568,13 +568,13 @@ pub fn formatText(
568568 bytes: []const u8,
569569 comptime fmt: []const u8,
570570 options: FormatOptions,
571 out_stream: var,
571 writer: var,
572572) !void {
573573 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);
575575 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
576576 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);
578578 }
579579 return;
580580 } else {
......@@ -585,38 +585,38 @@ pub fn formatText(
585585pub fn formatAsciiChar(
586586 c: u8,
587587 options: FormatOptions,
588 out_stream: var,
588 writer: var,
589589) !void {
590 return out_stream.writeAll(@as(*const [1]u8, &c));
590 return writer.writeAll(@as(*const [1]u8, &c));
591591}
592592
593593pub fn formatBuf(
594594 buf: []const u8,
595595 options: FormatOptions,
596 out_stream: var,
596 writer: var,
597597) !void {
598598 const width = options.width orelse buf.len;
599599 var padding = if (width > buf.len) (width - buf.len) else 0;
600600 const pad_byte = [1]u8{options.fill};
601601 switch (options.alignment) {
602602 .Left => {
603 try out_stream.writeAll(buf);
603 try writer.writeAll(buf);
604604 while (padding > 0) : (padding -= 1) {
605 try out_stream.writeAll(&pad_byte);
605 try writer.writeAll(&pad_byte);
606606 }
607607 },
608608 .Center => {
609609 const padl = padding / 2;
610610 var i: usize = 0;
611 while (i < padl) : (i += 1) try out_stream.writeAll(&pad_byte);
612 try out_stream.writeAll(buf);
613 while (i < padding) : (i += 1) try out_stream.writeAll(&pad_byte);
611 while (i < padl) : (i += 1) try writer.writeAll(&pad_byte);
612 try writer.writeAll(buf);
613 while (i < padding) : (i += 1) try writer.writeAll(&pad_byte);
614614 },
615615 .Right => {
616616 while (padding > 0) : (padding -= 1) {
617 try out_stream.writeAll(&pad_byte);
617 try writer.writeAll(&pad_byte);
618618 }
619 try out_stream.writeAll(buf);
619 try writer.writeAll(buf);
620620 },
621621 }
622622}
......@@ -627,38 +627,38 @@ pub fn formatBuf(
627627pub fn formatFloatScientific(
628628 value: var,
629629 options: FormatOptions,
630 out_stream: var,
630 writer: var,
631631) !void {
632632 var x = @floatCast(f64, value);
633633
634634 // Errol doesn't handle these special cases.
635635 if (math.signbit(x)) {
636 try out_stream.writeAll("-");
636 try writer.writeAll("-");
637637 x = -x;
638638 }
639639
640640 if (math.isNan(x)) {
641 return out_stream.writeAll("nan");
641 return writer.writeAll("nan");
642642 }
643643 if (math.isPositiveInf(x)) {
644 return out_stream.writeAll("inf");
644 return writer.writeAll("inf");
645645 }
646646 if (x == 0.0) {
647 try out_stream.writeAll("0");
647 try writer.writeAll("0");
648648
649649 if (options.precision) |precision| {
650650 if (precision != 0) {
651 try out_stream.writeAll(".");
651 try writer.writeAll(".");
652652 var i: usize = 0;
653653 while (i < precision) : (i += 1) {
654 try out_stream.writeAll("0");
654 try writer.writeAll("0");
655655 }
656656 }
657657 } else {
658 try out_stream.writeAll(".0");
658 try writer.writeAll(".0");
659659 }
660660
661 try out_stream.writeAll("e+00");
661 try writer.writeAll("e+00");
662662 return;
663663 }
664664
......@@ -668,50 +668,50 @@ pub fn formatFloatScientific(
668668 if (options.precision) |precision| {
669669 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
673673 // {e0} case prints no `.`
674674 if (precision != 0) {
675 try out_stream.writeAll(".");
675 try writer.writeAll(".");
676676
677677 var printed: usize = 0;
678678 if (float_decimal.digits.len > 1) {
679679 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]);
681681 printed += num_digits - 1;
682682 }
683683
684684 while (printed < precision) : (printed += 1) {
685 try out_stream.writeAll("0");
685 try writer.writeAll("0");
686686 }
687687 }
688688 } else {
689 try out_stream.writeAll(float_decimal.digits[0..1]);
690 try out_stream.writeAll(".");
689 try writer.writeAll(float_decimal.digits[0..1]);
690 try writer.writeAll(".");
691691 if (float_decimal.digits.len > 1) {
692692 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]);
695695 } else {
696 try out_stream.writeAll("0");
696 try writer.writeAll("0");
697697 }
698698 }
699699
700 try out_stream.writeAll("e");
700 try writer.writeAll("e");
701701 const exp = float_decimal.exp - 1;
702702
703703 if (exp >= 0) {
704 try out_stream.writeAll("+");
704 try writer.writeAll("+");
705705 if (exp > -10 and exp < 10) {
706 try out_stream.writeAll("0");
706 try writer.writeAll("0");
707707 }
708 try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
708 try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, writer);
709709 } else {
710 try out_stream.writeAll("-");
710 try writer.writeAll("-");
711711 if (exp > -10 and exp < 10) {
712 try out_stream.writeAll("0");
712 try writer.writeAll("0");
713713 }
714 try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
714 try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, writer);
715715 }
716716}
717717
......@@ -720,34 +720,34 @@ pub fn formatFloatScientific(
720720pub fn formatFloatDecimal(
721721 value: var,
722722 options: FormatOptions,
723 out_stream: var,
723 writer: var,
724724) !void {
725725 var x = @as(f64, value);
726726
727727 // Errol doesn't handle these special cases.
728728 if (math.signbit(x)) {
729 try out_stream.writeAll("-");
729 try writer.writeAll("-");
730730 x = -x;
731731 }
732732
733733 if (math.isNan(x)) {
734 return out_stream.writeAll("nan");
734 return writer.writeAll("nan");
735735 }
736736 if (math.isPositiveInf(x)) {
737 return out_stream.writeAll("inf");
737 return writer.writeAll("inf");
738738 }
739739 if (x == 0.0) {
740 try out_stream.writeAll("0");
740 try writer.writeAll("0");
741741
742742 if (options.precision) |precision| {
743743 if (precision != 0) {
744 try out_stream.writeAll(".");
744 try writer.writeAll(".");
745745 var i: usize = 0;
746746 while (i < precision) : (i += 1) {
747 try out_stream.writeAll("0");
747 try writer.writeAll("0");
748748 }
749749 } else {
750 try out_stream.writeAll(".0");
750 try writer.writeAll(".0");
751751 }
752752 }
753753
......@@ -769,14 +769,14 @@ pub fn formatFloatDecimal(
769769
770770 if (num_digits_whole > 0) {
771771 // 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
774774 var i = num_digits_whole_no_pad;
775775 while (i < num_digits_whole) : (i += 1) {
776 try out_stream.writeAll("0");
776 try writer.writeAll("0");
777777 }
778778 } else {
779 try out_stream.writeAll("0");
779 try writer.writeAll("0");
780780 }
781781
782782 // {.0} special case doesn't want a trailing '.'
......@@ -784,7 +784,7 @@ pub fn formatFloatDecimal(
784784 return;
785785 }
786786
787 try out_stream.writeAll(".");
787 try writer.writeAll(".");
788788
789789 // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
790790 var printed: usize = 0;
......@@ -796,7 +796,7 @@ pub fn formatFloatDecimal(
796796
797797 var i: usize = 0;
798798 while (i < zeros_to_print) : (i += 1) {
799 try out_stream.writeAll("0");
799 try writer.writeAll("0");
800800 printed += 1;
801801 }
802802
......@@ -808,14 +808,14 @@ pub fn formatFloatDecimal(
808808 // Remaining fractional portion, zero-padding if insufficient.
809809 assert(precision >= printed);
810810 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]);
812812 return;
813813 } 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..]);
815815 printed += float_decimal.digits.len - num_digits_whole_no_pad;
816816
817817 while (printed < precision) : (printed += 1) {
818 try out_stream.writeAll("0");
818 try writer.writeAll("0");
819819 }
820820 }
821821 } else {
......@@ -827,14 +827,14 @@ pub fn formatFloatDecimal(
827827
828828 if (num_digits_whole > 0) {
829829 // 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
832832 var i = num_digits_whole_no_pad;
833833 while (i < num_digits_whole) : (i += 1) {
834 try out_stream.writeAll("0");
834 try writer.writeAll("0");
835835 }
836836 } else {
837 try out_stream.writeAll("0");
837 try writer.writeAll("0");
838838 }
839839
840840 // Omit `.` if no fractional portion
......@@ -842,7 +842,7 @@ pub fn formatFloatDecimal(
842842 return;
843843 }
844844
845 try out_stream.writeAll(".");
845 try writer.writeAll(".");
846846
847847 // Zero-fill until we reach significant digits or run out of precision.
848848 if (float_decimal.exp < 0) {
......@@ -850,11 +850,11 @@ pub fn formatFloatDecimal(
850850
851851 var i: usize = 0;
852852 while (i < zero_digit_count) : (i += 1) {
853 try out_stream.writeAll("0");
853 try writer.writeAll("0");
854854 }
855855 }
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..]);
858858 }
859859}
860860
......@@ -862,10 +862,10 @@ pub fn formatBytes(
862862 value: var,
863863 options: FormatOptions,
864864 comptime radix: usize,
865 out_stream: var,
865 writer: var,
866866) !void {
867867 if (value == 0) {
868 return out_stream.writeAll("0B");
868 return writer.writeAll("0B");
869869 }
870870
871871 const is_float = comptime std.meta.trait.is(.Float)(@TypeOf(value));
......@@ -885,10 +885,10 @@ pub fn formatBytes(
885885 else => unreachable,
886886 };
887887
888 try formatFloatDecimal(new_value, options, out_stream);
888 try formatFloatDecimal(new_value, options, writer);
889889
890890 if (suffix == ' ') {
891 return out_stream.writeAll("B");
891 return writer.writeAll("B");
892892 }
893893
894894 const buf = switch (radix) {
......@@ -896,7 +896,7 @@ pub fn formatBytes(
896896 1024 => &[_]u8{ suffix, 'i', 'B' },
897897 else => unreachable,
898898 };
899 return out_stream.writeAll(buf);
899 return writer.writeAll(buf);
900900}
901901
902902pub fn formatInt(
......@@ -904,7 +904,7 @@ pub fn formatInt(
904904 base: u8,
905905 uppercase: bool,
906906 options: FormatOptions,
907 out_stream: var,
907 writer: var,
908908) !void {
909909 const int_value = if (@TypeOf(value) == comptime_int) blk: {
910910 const Int = math.IntFittingRange(value, value);
......@@ -913,9 +913,9 @@ pub fn formatInt(
913913 value;
914914
915915 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);
917917 } else {
918 return formatIntUnsigned(int_value, base, uppercase, options, out_stream);
918 return formatIntUnsigned(int_value, base, uppercase, options, writer);
919919 }
920920}
921921
......@@ -924,7 +924,7 @@ fn formatIntSigned(
924924 base: u8,
925925 uppercase: bool,
926926 options: FormatOptions,
927 out_stream: var,
927 writer: var,
928928) !void {
929929 const new_options = FormatOptions{
930930 .width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
......@@ -934,15 +934,15 @@ fn formatIntSigned(
934934 const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
935935 const Uint = std.meta.Int(false, bit_count);
936936 if (value < 0) {
937 try out_stream.writeAll("-");
937 try writer.writeAll("-");
938938 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);
940940 } 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);
942942 } else {
943 try out_stream.writeAll("+");
943 try writer.writeAll("+");
944944 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);
946946 }
947947}
948948
......@@ -951,7 +951,7 @@ fn formatIntUnsigned(
951951 base: u8,
952952 uppercase: bool,
953953 options: FormatOptions,
954 out_stream: var,
954 writer: var,
955955) !void {
956956 assert(base >= 2);
957957 var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;
......@@ -976,22 +976,22 @@ fn formatIntUnsigned(
976976 const zero_byte: u8 = options.fill;
977977 var leftover_padding = padding - index;
978978 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..]);
980980 leftover_padding -= 1;
981981 if (leftover_padding == 0) break;
982982 }
983983 mem.set(u8, buf[0..index], options.fill);
984 return out_stream.writeAll(&buf);
984 return writer.writeAll(&buf);
985985 } else {
986986 const padded_buf = buf[index - padding ..];
987987 mem.set(u8, padded_buf[0..padding], options.fill);
988 return out_stream.writeAll(padded_buf);
988 return writer.writeAll(padded_buf);
989989 }
990990}
991991
992992pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {
993993 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;
995995 return fbs.pos;
996996}
997997
......@@ -1098,15 +1098,15 @@ pub const BufPrintError = error{
10981098};
10991099pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
11001100 var fbs = std.io.fixedBufferStream(buf);
1101 try format(fbs.outStream(), fmt, args);
1101 try format(fbs.writer(), fmt, args);
11021102 return fbs.getWritten();
11031103}
11041104
11051105// Count the characters needed for format. Useful for preallocating memory
11061106pub fn count(comptime fmt: []const u8, args: var) u64 {
1107 var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
1108 format(counting_stream.outStream(), fmt, args) catch |err| switch (err) {};
1109 return counting_stream.bytes_written;
1107 var counting_writer = std.io.countingWriter(std.io.null_writer);
1108 format(counting_writer.writer(), fmt, args) catch |err| switch (err) {};
1109 return counting_writer.bytes_written;
11101110}
11111111
11121112pub const AllocPrintError = error{OutOfMemory};
......@@ -1215,15 +1215,15 @@ test "buffer" {
12151215 {
12161216 var buf1: [32]u8 = undefined;
12171217 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);
12191219 std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234"));
12201220
12211221 fbs.reset();
1222 try formatType('a', "c", FormatOptions{}, fbs.outStream(), default_max_depth);
1222 try formatType('a', "c", FormatOptions{}, fbs.writer(), default_max_depth);
12231223 std.testing.expect(mem.eql(u8, fbs.getWritten(), "a"));
12241224
12251225 fbs.reset();
1226 try formatType(0b1100, "b", FormatOptions{}, fbs.outStream(), default_max_depth);
1226 try formatType(0b1100, "b", FormatOptions{}, fbs.writer(), default_max_depth);
12271227 std.testing.expect(mem.eql(u8, fbs.getWritten(), "1100"));
12281228 }
12291229}
......@@ -1413,12 +1413,12 @@ test "custom" {
14131413 self: SelfType,
14141414 comptime fmt: []const u8,
14151415 options: FormatOptions,
1416 out_stream: var,
1416 writer: var,
14171417 ) !void {
14181418 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 });
14201420 } 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 });
14221422 } else {
14231423 @compileError("Unknown format character: '" ++ fmt ++ "'");
14241424 }
......@@ -1604,7 +1604,7 @@ test "formatIntValue with comptime_int" {
16041604
16051605 var buf: [20]u8 = undefined;
16061606 var fbs = std.io.fixedBufferStream(&buf);
1607 try formatIntValue(value, "", FormatOptions{}, fbs.outStream());
1607 try formatIntValue(value, "", FormatOptions{}, fbs.writer());
16081608 std.testing.expect(mem.eql(u8, fbs.getWritten(), "123456789123456789"));
16091609}
16101610
......@@ -1613,7 +1613,7 @@ test "formatFloatValue with comptime_float" {
16131613
16141614 var buf: [20]u8 = undefined;
16151615 var fbs = std.io.fixedBufferStream(&buf);
1616 try formatFloatValue(value, "", FormatOptions{}, fbs.outStream());
1616 try formatFloatValue(value, "", FormatOptions{}, fbs.writer());
16171617 std.testing.expect(mem.eql(u8, fbs.getWritten(), "1.0e+00"));
16181618
16191619 try testFmt("1.0e+00", "{}", .{value});
......@@ -1630,10 +1630,10 @@ test "formatType max_depth" {
16301630 self: SelfType,
16311631 comptime fmt: []const u8,
16321632 options: FormatOptions,
1633 out_stream: var,
1633 writer: var,
16341634 ) !void {
16351635 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 });
16371637 } else {
16381638 @compileError("Unknown format string: '" ++ fmt ++ "'");
16391639 }
......@@ -1669,19 +1669,19 @@ test "formatType max_depth" {
16691669
16701670 var buf: [1000]u8 = undefined;
16711671 var fbs = std.io.fixedBufferStream(&buf);
1672 try formatType(inst, "", FormatOptions{}, fbs.outStream(), 0);
1672 try formatType(inst, "", FormatOptions{}, fbs.writer(), 0);
16731673 std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ ... }"));
16741674
16751675 fbs.reset();
1676 try formatType(inst, "", FormatOptions{}, fbs.outStream(), 1);
1676 try formatType(inst, "", FormatOptions{}, fbs.writer(), 1);
16771677 std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
16781678
16791679 fbs.reset();
1680 try formatType(inst, "", FormatOptions{}, fbs.outStream(), 2);
1680 try formatType(inst, "", FormatOptions{}, fbs.writer(), 2);
16811681 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
16831683 fbs.reset();
1684 try formatType(inst, "", FormatOptions{}, fbs.outStream(), 3);
1684 try formatType(inst, "", FormatOptions{}, fbs.writer(), 3);
16851685 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) }"));
16861686}
16871687
lib/std/fs.zig+17-21
......@@ -261,17 +261,7 @@ pub const Dir = struct {
261261 name: []const u8,
262262 kind: Kind,
263263
264 pub const Kind = enum {
265 BlockDevice,
266 CharacterDevice,
267 Directory,
268 NamedPipe,
269 SymLink,
270 File,
271 UnixDomainSocket,
272 Whiteout,
273 Unknown,
274 };
264 pub const Kind = File.Kind;
275265 };
276266
277267 const IteratorError = error{AccessDenied} || os.UnexpectedError;
......@@ -1229,14 +1219,9 @@ pub const Dir = struct {
12291219 var file = try self.openFile(file_path, .{});
12301220 defer file.close();
12311221
1232 const size = math.cast(usize, try file.getEndPos()) catch math.maxInt(usize);
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);
1222 const stat_size = try file.getEndPos();
12371223
1238 try file.inStream().readNoEof(buf);
1239 return buf;
1224 return file.readAllAllocOptions(allocator, stat_size, max_bytes, alignment, optional_sentinel);
12401225 }
12411226
12421227 pub const DeleteTreeError = error{
......@@ -1532,9 +1517,9 @@ pub const Dir = struct {
15321517
15331518 var size: ?u64 = null;
15341519 const mode = options.override_mode orelse blk: {
1535 const stat = try in_file.stat();
1536 size = stat.size;
1537 break :blk stat.mode;
1520 const st = try in_file.stat();
1521 size = st.size;
1522 break :blk st.mode;
15381523 };
15391524
15401525 var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode });
......@@ -1560,6 +1545,17 @@ pub const Dir = struct {
15601545 return AtomicFile.init(dest_path, options.mode, self, false);
15611546 }
15621547 }
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 }
15631559};
15641560
15651561/// 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 {
2929 pub const Mode = os.mode_t;
3030 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
3244 pub const default_mode = switch (builtin.os.tag) {
3345 .windows => 0,
3446 .wasi => 0,
......@@ -209,7 +221,7 @@ pub const File = struct {
209221 /// TODO: integrate with async I/O
210222 pub fn mode(self: File) ModeError!Mode {
211223 if (builtin.os.tag == .windows) {
212 return {};
224 return 0;
213225 }
214226 return (try self.stat()).mode;
215227 }
......@@ -219,13 +231,14 @@ pub const File = struct {
219231 /// unique across time, as some file systems may reuse an inode after its file has been deleted.
220232 /// Some systems may change the inode of a file over time.
221233 ///
222 /// On Linux, the inode _is_ structure that stores the metadata, and the inode _number_ is what
234 /// On Linux, the inode is a structure that stores the metadata, and the inode _number_ is what
223235 /// you see here: the index number of the inode.
224236 ///
225237 /// The FileIndex on Windows is similar. It is a number for a file that is unique to each filesystem.
226238 inode: INode,
227239 size: u64,
228240 mode: Mode,
241 kind: Kind,
229242
230243 /// Access time in nanoseconds, relative to UTC 1970-01-01.
231244 atime: i128,
......@@ -254,6 +267,7 @@ pub const File = struct {
254267 .inode = info.InternalInformation.IndexNumber,
255268 .size = @bitCast(u64, info.StandardInformation.EndOfFile),
256269 .mode = 0,
270 .kind = if (info.StandardInformation.Directory == 0) .File else .Directory,
257271 .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime),
258272 .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime),
259273 .ctime = windows.fromSysTime(info.BasicInformation.CreationTime),
......@@ -268,6 +282,27 @@ pub const File = struct {
268282 .inode = st.ino,
269283 .size = @bitCast(u64, st.size),
270284 .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 },
271306 .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
272307 .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
273308 .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
......@@ -306,6 +341,33 @@ pub const File = struct {
306341 try os.futimens(self.handle, &times);
307342 }
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
309371 pub const ReadError = os.ReadError;
310372 pub const PReadError = os.PReadError;
311373
lib/std/fs/test.zig+40-3
......@@ -1,7 +1,44 @@
11const std = @import("../std.zig");
2const testing = std.testing;
23const builtin = std.builtin;
34const fs = std.fs;
5const mem = std.mem;
6
47const 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
643test "openSelfExe" {
744 if (builtin.os.tag == .wasi) return error.SkipZigTest;
......@@ -116,7 +153,7 @@ test "create file, lock and read from multiple process at once" {
116153test "open file with exclusive nonblocking lock twice (absolute paths)" {
117154 if (builtin.os.tag == .wasi) return error.SkipZigTest;
118155
119 const allocator = std.testing.allocator;
156 const allocator = testing.allocator;
120157
121158 const file_paths: [1][]const u8 = .{"zig-test-absolute-paths.txt"};
122159 const filename = try fs.path.resolve(allocator, &file_paths);
......@@ -126,7 +163,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
126163
127164 const file2 = fs.createFileAbsolute(filename, .{ .lock = .Exclusive, .lock_nonblocking = true });
128165 file1.close();
129 std.testing.expectError(error.WouldBlock, file2);
166 testing.expectError(error.WouldBlock, file2);
130167
131168 try fs.deleteFileAbsolute(filename);
132169}
......@@ -187,7 +224,7 @@ const FileLockTestContext = struct {
187224};
188225
189226fn 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);
191228 defer {
192229 for (threads.items) |thread| {
193230 thread.wait();
lib/std/io/buffered_out_stream.zig+1-1
......@@ -2,4 +2,4 @@
22pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter;
33
44/// Deprecated: use `std.io.buffered_writer.bufferedWriter`
5pub const bufferedOutStream = @import("./buffered_writer.zig").bufferedWriter
5pub const bufferedOutStream = @import("./buffered_writer.zig").bufferedWriter;
lib/std/io/reader.zig+1-2
......@@ -40,8 +40,7 @@ pub fn Reader(
4040 return index;
4141 }
4242
43 /// Returns the number of bytes read. If the number read would be smaller than buf.len,
44 /// error.EndOfStream is returned instead.
43 /// If the number read would be smaller than `buf.len`, `error.EndOfStream` is returned instead.
4544 pub fn readNoEof(self: Self, buf: []u8) !void {
4645 const amt_read = try self.readAll(buf);
4746 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:
15351535 const allocator = options.allocator orelse return error.AllocatorRequired;
15361536 switch (ptrInfo.size) {
15371537 .One => {
1538 const r: T = allocator.create(ptrInfo.child);
1538 const r: T = try allocator.create(ptrInfo.child);
15391539 r.* = try parseInternal(ptrInfo.child, token, tokens, options);
15401540 return r;
15411541 },
......@@ -1629,7 +1629,7 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void {
16291629 switch (ptrInfo.size) {
16301630 .One => {
16311631 parseFree(ptrInfo.child, value.*, options);
1632 allocator.destroy(v);
1632 allocator.destroy(value);
16331633 },
16341634 .Slice => {
16351635 for (value) |v| {
......@@ -2576,8 +2576,8 @@ pub fn stringify(
25762576 },
25772577 .Array => return stringify(&value, options, out_stream),
25782578 .Vector => |info| {
2579 const array: [info.len]info.child = value;
2580 return stringify(&array, options, out_stream);
2579 const array: [info.len]info.child = value;
2580 return stringify(&array, options, out_stream);
25812581 },
25822582 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
25832583 }
......@@ -2770,4 +2770,3 @@ test "stringify struct with custom stringifier" {
27702770test "stringify vector" {
27712771 try teststringify("[1,1]", @splat(2, @as(u32, 1)), StringifyOptions{});
27722772}
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 {
122122 const p = @ptrCast(*volatile f64, &x);
123123 p.* = x;
124124 },
125 f128 => {
126 var x: f128 = undefined;
127 const p = @ptrCast(*volatile f128, &x);
128 p.* = x;
129 },
125130 else => {
126131 @compileError("forceEval not implemented for " ++ @typeName(T));
127132 },
lib/std/math/ceil.zig+43
......@@ -20,6 +20,7 @@ pub fn ceil(x: var) @TypeOf(x) {
2020 return switch (T) {
2121 f32 => ceil32(x),
2222 f64 => ceil64(x),
23 f128 => ceil128(x),
2324 else => @compileError("ceil not implemented for " ++ @typeName(T)),
2425 };
2526}
......@@ -86,9 +87,37 @@ fn ceil64(x: f64) f64 {
8687 }
8788}
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
89117test "math.ceil" {
90118 expect(ceil(@as(f32, 0.0)) == ceil32(0.0));
91119 expect(ceil(@as(f64, 0.0)) == ceil64(0.0));
120 expect(ceil(@as(f128, 0.0)) == ceil128(0.0));
92121}
93122
94123test "math.ceil32" {
......@@ -103,6 +132,12 @@ test "math.ceil64" {
103132 expect(ceil64(0.2) == 1.0);
104133}
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
106141test "math.ceil32.special" {
107142 expect(ceil32(0.0) == 0.0);
108143 expect(ceil32(-0.0) == -0.0);
......@@ -118,3 +153,11 @@ test "math.ceil64.special" {
118153 expect(math.isNegativeInf(ceil64(-math.inf(f64))));
119154 expect(math.isNan(ceil64(math.nan(f64))));
120155}
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) {
2121 f16 => floor16(x),
2222 f32 => floor32(x),
2323 f64 => floor64(x),
24 f128 => floor128(x),
2425 else => @compileError("floor not implemented for " ++ @typeName(T)),
2526 };
2627}
......@@ -122,10 +123,38 @@ fn floor64(x: f64) f64 {
122123 }
123124}
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
125153test "math.floor" {
126154 expect(floor(@as(f16, 1.3)) == floor16(1.3));
127155 expect(floor(@as(f32, 1.3)) == floor32(1.3));
128156 expect(floor(@as(f64, 1.3)) == floor64(1.3));
157 expect(floor(@as(f128, 1.3)) == floor128(1.3));
129158}
130159
131160test "math.floor16" {
......@@ -146,6 +175,12 @@ test "math.floor64" {
146175 expect(floor64(0.2) == 0.0);
147176}
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
149184test "math.floor16.special" {
150185 expect(floor16(0.0) == 0.0);
151186 expect(floor16(-0.0) == -0.0);
......@@ -169,3 +204,11 @@ test "math.floor64.special" {
169204 expect(math.isNegativeInf(floor64(-math.inf(f64))));
170205 expect(math.isNan(floor64(math.nan(f64))));
171206}
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) {
2020 return switch (T) {
2121 f32 => round32(x),
2222 f64 => round64(x),
23 f128 => round128(x),
2324 else => @compileError("round not implemented for " ++ @typeName(T)),
2425 };
2526}
......@@ -90,9 +91,43 @@ fn round64(x_: f64) f64 {
9091 }
9192}
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
93127test "math.round" {
94128 expect(round(@as(f32, 1.3)) == round32(1.3));
95129 expect(round(@as(f64, 1.3)) == round64(1.3));
130 expect(round(@as(f128, 1.3)) == round128(1.3));
96131}
97132
98133test "math.round32" {
......@@ -109,6 +144,13 @@ test "math.round64" {
109144 expect(round64(1.8) == 2.0);
110145}
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
112154test "math.round32.special" {
113155 expect(round32(0.0) == 0.0);
114156 expect(round32(-0.0) == -0.0);
......@@ -124,3 +166,11 @@ test "math.round64.special" {
124166 expect(math.isNegativeInf(round64(-math.inf(f64))));
125167 expect(math.isNan(round64(math.nan(f64))));
126168}
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) {
2020 return switch (T) {
2121 f32 => trunc32(x),
2222 f64 => trunc64(x),
23 f128 => trunc128(x),
2324 else => @compileError("trunc not implemented for " ++ @typeName(T)),
2425 };
2526}
......@@ -66,9 +67,31 @@ fn trunc64(x: f64) f64 {
6667 }
6768}
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
6991test "math.trunc" {
7092 expect(trunc(@as(f32, 1.3)) == trunc32(1.3));
7193 expect(trunc(@as(f64, 1.3)) == trunc64(1.3));
94 expect(trunc(@as(f128, 1.3)) == trunc128(1.3));
7295}
7396
7497test "math.trunc32" {
......@@ -83,6 +106,12 @@ test "math.trunc64" {
83106 expect(trunc64(0.2) == 0.0);
84107}
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
86115test "math.trunc32.special" {
87116 expect(trunc32(0.0) == 0.0); // 0x3F800000
88117 expect(trunc32(-0.0) == -0.0);
......@@ -98,3 +127,11 @@ test "math.trunc64.special" {
98127 expect(math.isNegativeInf(trunc64(-math.inf(f64))));
99128 expect(math.isNan(trunc64(math.nan(f64))));
100129}
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" {
250250 testing.expect(containerLayout(U3) == .Extern);
251251}
252252
253pub fn declarations(comptime T: type) []TypeInfo.Declaration {
253pub fn declarations(comptime T: type) []const TypeInfo.Declaration {
254254 return switch (@typeInfo(T)) {
255255 .Struct => |info| info.decls,
256256 .Enum => |info| info.decls,
......@@ -274,7 +274,7 @@ test "std.meta.declarations" {
274274 fn a() void {}
275275 };
276276
277 const decls = comptime [_][]TypeInfo.Declaration{
277 const decls = comptime [_][]const TypeInfo.Declaration{
278278 declarations(E1),
279279 declarations(S1),
280280 declarations(U1),
......@@ -323,10 +323,10 @@ test "std.meta.declarationInfo" {
323323}
324324
325325pub fn fields(comptime T: type) switch (@typeInfo(T)) {
326 .Struct => []TypeInfo.StructField,
327 .Union => []TypeInfo.UnionField,
328 .ErrorSet => []TypeInfo.Error,
329 .Enum => []TypeInfo.EnumField,
326 .Struct => []const TypeInfo.StructField,
327 .Union => []const TypeInfo.UnionField,
328 .ErrorSet => []const TypeInfo.Error,
329 .Enum => []const TypeInfo.EnumField,
330330 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
331331} {
332332 return switch (@typeInfo(T)) {
......@@ -693,3 +693,85 @@ pub fn Vector(comptime len: u32, comptime child: type) type {
693693 },
694694 });
695695}
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{
15201520/// If `sym_link_path` exists, it will not be overwritten.
15211521/// See also `symlinkC` and `symlinkW`.
15221522pub 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 }
15231526 if (builtin.os.tag == .windows) {
15241527 const target_path_w = try windows.sliceToPrefixedFileW(target_path);
15251528 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
15261529 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);
15311530 }
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);
15321534}
15331535
15341536pub 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
15611563 }
15621564}
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`.
15641572pub 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 }
15651581 const target_path_c = try toPosixPath(target_path);
15661582 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);
15681584}
15691585
15701586pub 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`.
15721619pub 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 }
15731625 switch (errno(system.symlinkat(target_path, newdirfd, sym_link_path))) {
15741626 0 => return,
15751627 EFAULT => unreachable,
......@@ -2291,12 +2343,54 @@ pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8
22912343 }
22922344}
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
22942361pub 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`.
22962390pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
22972391 if (builtin.os.tag == .windows) {
22982392 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);
23002394 }
23012395 const rc = system.readlinkat(dirfd, file_path, out_buffer.ptr, out_buffer.len);
23022396 switch (errno(rc)) {
lib/std/os/test.zig+19
......@@ -18,6 +18,25 @@ const AtomicOrder = builtin.AtomicOrder;
1818const tmpDir = std.testing.tmpDir;
1919const 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
2140test "makePath, put some files in it, deleteTree" {
2241 var tmp = tmpDir(.{});
2342 defer tmp.cleanup();
lib/std/os/windows.zig+10-1
......@@ -901,7 +901,13 @@ pub fn WSAStartup(majorVersion: u8, minorVersion: u8) !ws2_32.WSADATA {
901901 var wsadata: ws2_32.WSADATA = undefined;
902902 return switch (ws2_32.WSAStartup((@as(WORD, minorVersion) << 8) | majorVersion, &wsadata)) {
903903 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 },
905911 };
906912}
907913
......@@ -909,6 +915,9 @@ pub fn WSACleanup() !void {
909915 return switch (ws2_32.WSACleanup()) {
910916 0 => {},
911917 ws2_32.SOCKET_ERROR => switch (ws2_32.WSAGetLastError()) {
918 .WSANOTINITIALISED => return error.NotInitialized,
919 .WSAENETDOWN => return error.NetworkNotAvailable,
920 .WSAEINPROGRESS => return error.BlockingOperationInProgress,
912921 else => |err| return unexpectedWSAError(err),
913922 },
914923 else => unreachable,
lib/std/os/windows/ws2_32.zig+9-9
......@@ -163,16 +163,16 @@ pub const IPPROTO_UDP = 17;
163163pub const IPPROTO_ICMPV6 = 58;
164164pub const IPPROTO_RM = 113;
165165
166pub const AI_PASSIVE = 0x00001;
167pub const AI_CANONNAME = 0x00002;
168pub const AI_NUMERICHOST = 0x00004;
169pub const AI_NUMERICSERV = 0x00008;
170pub const AI_ADDRCONFIG = 0x00400;
171pub const AI_V4MAPPED = 0x00800;
172pub const AI_NON_AUTHORITATIVE = 0x04000;
173pub const AI_SECURE = 0x08000;
166pub const AI_PASSIVE = 0x00001;
167pub const AI_CANONNAME = 0x00002;
168pub const AI_NUMERICHOST = 0x00004;
169pub const AI_NUMERICSERV = 0x00008;
170pub const AI_ADDRCONFIG = 0x00400;
171pub const AI_V4MAPPED = 0x00800;
172pub const AI_NON_AUTHORITATIVE = 0x04000;
173pub const AI_SECURE = 0x08000;
174174pub const AI_RETURN_PREFERRED_NAMES = 0x10000;
175pub const AI_DISABLE_IDN_ENCODING = 0x80000;
175pub const AI_DISABLE_IDN_ENCODING = 0x80000;
176176
177177pub const FIONBIO = -2147195266;
178178
lib/std/process.zig+7-34
......@@ -281,9 +281,6 @@ pub const ArgIteratorWasi = struct {
281281pub const ArgIteratorWindows = struct {
282282 index: usize,
283283 cmd_line: [*]const u8,
284 in_quote: bool,
285 quote_count: usize,
286 seen_quote_count: usize,
287284
288285 pub const NextError = error{OutOfMemory};
289286
......@@ -295,9 +292,6 @@ pub const ArgIteratorWindows = struct {
295292 return ArgIteratorWindows{
296293 .index = 0,
297294 .cmd_line = cmd_line,
298 .in_quote = false,
299 .quote_count = countQuotes(cmd_line),
300 .seen_quote_count = 0,
301295 };
302296 }
303297
......@@ -328,6 +322,7 @@ pub const ArgIteratorWindows = struct {
328322 }
329323
330324 var backslash_count: usize = 0;
325 var in_quote = false;
331326 while (true) : (self.index += 1) {
332327 const byte = self.cmd_line[self.index];
333328 switch (byte) {
......@@ -335,14 +330,14 @@ pub const ArgIteratorWindows = struct {
335330 '"' => {
336331 const quote_is_real = backslash_count % 2 == 0;
337332 if (quote_is_real) {
338 self.seen_quote_count += 1;
333 in_quote = !in_quote;
339334 }
340335 },
341336 '\\' => {
342337 backslash_count += 1;
343338 },
344339 ' ', '\t' => {
345 if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {
340 if (!in_quote) {
346341 return true;
347342 }
348343 backslash_count = 0;
......@@ -360,6 +355,7 @@ pub const ArgIteratorWindows = struct {
360355 defer buf.deinit();
361356
362357 var backslash_count: usize = 0;
358 var in_quote = false;
363359 while (true) : (self.index += 1) {
364360 const byte = self.cmd_line[self.index];
365361 switch (byte) {
......@@ -370,10 +366,7 @@ pub const ArgIteratorWindows = struct {
370366 backslash_count = 0;
371367
372368 if (quote_is_real) {
373 self.seen_quote_count += 1;
374 if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
375 try buf.append('"');
376 }
369 in_quote = !in_quote;
377370 } else {
378371 try buf.append('"');
379372 }
......@@ -384,7 +377,7 @@ pub const ArgIteratorWindows = struct {
384377 ' ', '\t' => {
385378 try self.emitBackslashes(&buf, backslash_count);
386379 backslash_count = 0;
387 if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
380 if (in_quote) {
388381 try buf.append(byte);
389382 } else {
390383 return buf.toOwnedSlice();
......@@ -405,26 +398,6 @@ pub const ArgIteratorWindows = struct {
405398 try buf.append('\\');
406399 }
407400 }
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 }
428401};
429402
430403pub const ArgIterator = struct {
......@@ -578,7 +551,7 @@ test "windows arg parsing" {
578551 testWindowsCmdLine("a\\\\\\b d\"e f\"g h", &[_][]const u8{ "a\\\\\\b", "de fg", "h" });
579552 testWindowsCmdLine("a\\\\\\\"b c d", &[_][]const u8{ "a\\\"b", "c", "d" });
580553 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
583556 testWindowsCmdLine("\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", &[_][]const u8{
584557 ".\\..\\zig-cache\\build",
lib/std/std.zig+1
......@@ -49,6 +49,7 @@ pub const heap = @import("heap.zig");
4949pub const http = @import("http.zig");
5050pub const io = @import("io.zig");
5151pub const json = @import("json.zig");
52pub const log = @import("log.zig");
5253pub const macho = @import("macho.zig");
5354pub const math = @import("math.zig");
5455pub const mem = @import("mem.zig");
lib/std/unicode.zig+41
......@@ -235,6 +235,22 @@ pub const Utf8Iterator = struct {
235235 else => unreachable,
236236 }
237237 }
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 }
238254};
239255
240256pub const Utf16LeIterator = struct {
......@@ -451,6 +467,31 @@ fn testMiscInvalidUtf8() void {
451467 testValid("\xee\x80\x80", 0xe000);
452468}
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
454495fn testError(bytes: []const u8, expected_err: anyerror) void {
455496 testing.expectError(expected_err, testDecode(bytes));
456497}
lib/std/zig/parse.zig-1
......@@ -937,7 +937,6 @@ const Parser = struct {
937937 return node;
938938 }
939939
940
941940 while_prefix.body = try p.expectNode(parseAssignExpr, .{
942941 .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
943942 });
src-self-hosted/main.zig+93-43
......@@ -546,8 +546,9 @@ const Fmt = struct {
546546 any_error: bool,
547547 color: Color,
548548 gpa: *Allocator,
549 out_buffer: std.ArrayList(u8),
549550
550 const SeenMap = std.BufSet;
551 const SeenMap = std.AutoHashMap(fs.File.INode, void);
551552};
552553
553554pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
......@@ -641,10 +642,20 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
641642 .seen = Fmt.SeenMap.init(gpa),
642643 .any_error = false,
643644 .color = color,
645 .out_buffer = std.ArrayList(u8).init(gpa),
644646 };
647 defer fmt.seen.deinit();
648 defer fmt.out_buffer.deinit();
645649
646650 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);
648659 }
649660 if (fmt.any_error) {
650661 process.exit(1);
......@@ -670,48 +681,82 @@ const FmtError = error{
670681 ReadOnlyFileSystem,
671682 LinkQuotaExceeded,
672683 FileBusy,
684 EndOfStream,
673685} || fs.File.OpenError;
674686
675fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
676 // get the real path here to avoid Windows failing on relative file paths with . or .. in them
677 var real_path = fs.realpathAlloc(fmt.gpa, file_path) catch |err| {
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 },
687fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
688 fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
689 error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
702690 else => {
703 std.debug.warn("unable to open '{}': {}\n", .{ file_path, err });
691 std.debug.warn("unable to format '{}': {}\n", .{ file_path, err });
704692 fmt.any_error = true;
705693 return;
706694 },
707695 };
708 defer fmt.gpa.free(source_code);
696}
709697
710 const tree = std.zig.parse(fmt.gpa, source_code) catch |err| {
711 std.debug.warn("error parsing file '{}': {}\n", .{ file_path, err });
712 fmt.any_error = true;
713 return;
698fn fmtPathDir(
699 fmt: *Fmt,
700 file_path: []const u8,
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,
714751 };
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);
715760 defer tree.deinit();
716761
717762 for (tree.errors) |parse_error| {
......@@ -729,14 +774,19 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
729774 fmt.any_error = true;
730775 }
731776 } else {
732 const baf = try io.BufferedAtomicFile.create(fmt.gpa, fs.cwd(), real_path, .{});
733 defer baf.destroy();
734
735 const anything_changed = try std.zig.render(fmt.gpa, baf.stream(), tree);
736 if (anything_changed) {
737 std.debug.warn("{}\n", .{file_path});
738 try baf.finish();
739 }
777 // As a heuristic, we make enough capacity for the same as the input source.
778 try fmt.out_buffer.ensureCapacity(source_code.len);
779 fmt.out_buffer.items.len = 0;
780 const anything_changed = try std.zig.render(fmt.gpa, fmt.out_buffer.writer(), tree);
781 if (!anything_changed)
782 return; // Good thing we didn't waste any file system access on this.
783
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});
740790 }
741791}
742792
src-self-hosted/translate_c.zig+13-151
......@@ -5668,161 +5668,23 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56685668
56695669 const lparen = try appendToken(c, .LParen, "(");
56705670
5671 if (saw_integer_literal) {
5672 //( if (@typeInfo(dest) == .Pointer))
5673 // @intToPtr(dest, x)
5674 //else
5675 // @as(dest, x) )
5676 const if_node = try transCreateNodeIf(c);
5677 const type_info_node = try c.createBuiltinCall("@typeInfo", 1);
5678 type_info_node.params()[0] = inner_node;
5679 type_info_node.rparen_token = try appendToken(c, .LParen, ")");
5680 const cmp_node = try c.arena.create(ast.Node.InfixOp);
5681 cmp_node.* = .{
5682 .op_token = try appendToken(c, .EqualEqual, "=="),
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;
5671 //(@import("std").meta.cast(dest, x))
5672 const import_fn_call = try c.createBuiltinCall("@import", 1);
5673 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
5674 import_fn_call.params()[0] = std_node;
5675 import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
5676 const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "meta");
5677 const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "cast");
5678
5679 const cast_fn_call = try c.createCall(outer_field_access, 2);
5680 cast_fn_call.params()[0] = inner_node;
5681 cast_fn_call.params()[1] = node_to_cast;
5682 cast_fn_call.rtoken = try appendToken(c, .RParen, ")");
58215683
58225684 const group_node = try c.arena.create(ast.Node.GroupedExpression);
58235685 group_node.* = .{
58245686 .lparen = lparen,
5825 .expr = &if_1.base,
5687 .expr = &cast_fn_call.base,
58265688 .rparen = try appendToken(c, .RParen, ")"),
58275689 };
58285690 return &group_node.base;
src/analyze.cpp+13
......@@ -6012,6 +6012,19 @@ ZigValue *create_const_null(CodeGen *g, ZigType *type) {
60126012 return const_val;
60136013}
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
60156028void init_const_float(ZigValue *const_val, ZigType *type, double value) {
60166029 const_val->special = ConstValSpecialStatic;
60176030 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
180180void init_const_null(ZigValue *const_val, ZigType *type);
181181ZigValue *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
183186ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count);
184187ZigValue **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
35403540
35413541 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
35423542 TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i];
3543
3543
35443544 Buf *name = type_enum_field->name;
35453545 auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
35463546 if (entry != nullptr) {
......@@ -3654,7 +3654,7 @@ static LLVMValueRef ir_gen_negation(CodeGen *g, IrInstGen *inst, IrInstGen *oper
36543654 } else if (scalar_type->data.integral.is_signed) {
36553655 return LLVMBuildNSWNeg(g->builder, llvm_operand, "");
36563656 } else {
3657 return LLVMBuildNUWNeg(g->builder, llvm_operand, "");
3657 zig_unreachable();
36583658 }
36593659 } else {
36603660 zig_unreachable();
......@@ -3984,7 +3984,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutableGen *executable,
39843984 assert(array_type->data.pointer.child_type->id == ZigTypeIdArray);
39853985 array_type = array_type->data.pointer.child_type;
39863986 }
3987
3987
39883988 assert(array_type->data.array.len != 0 || array_type->data.array.sentinel != nullptr);
39893989
39903990 if (safety_check_on) {
......@@ -5258,7 +5258,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
52585258
52595259 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
52605260 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
5261
5261
52625262 Buf *name = type_enum_field->name;
52635263 auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
52645264 if (entry != nullptr) {
......@@ -5471,7 +5471,7 @@ static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {
54715471 }
54725472 auto bit_count = operand_type->data.integral.bit_count;
54735473 bool is_signed = operand_type->data.integral.is_signed;
5474
5474
54755475 ir_assert(bit_count != 0, instruction);
54765476 if (bit_count == 1 || !is_power_of_2(bit_count)) {
54775477 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) {
92759275 abi_name = (g->zig_target->arch == ZigLLVM_riscv32) ? "ilp32" : "lp64";
92769276 }
92779277 }
9278
9278
92799279 g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str),
92809280 target_specific_cpu_args, target_specific_features, opt_level, reloc_mode,
92819281 to_llvm_code_model(g), g->function_sections, float_abi, abi_name);
src/ir.cpp+133-27
......@@ -13,6 +13,7 @@
1313#include "os.hpp"
1414#include "range_set.hpp"
1515#include "softfloat.hpp"
16#include "softfloat_ext.hpp"
1617#include "util.hpp"
1718#include "mem_list.hpp"
1819#include "all_types.hpp"
......@@ -825,12 +826,11 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_
825826 ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
826827 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
827828
828 // TODO handle sentinel terminated arrays
829829 expand_undef_array(g, array_val);
830830 result = g->pass1_arena->create<ZigValue>();
831831 result->special = array_val->special;
832832 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);
834834 result->data.x_array.special = ConstArraySpecialNone;
835835 result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index];
836836 result->parent.id = ConstParentIdArray;
......@@ -12601,28 +12601,28 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
1260112601 if (prev_type->id == ZigTypeIdPointer &&
1260212602 prev_type->data.pointer.ptr_len == PtrLenSingle &&
1260312603 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)))
1260512605 {
12606 prev_inst = cur_inst;
12606 prev_inst = cur_inst;
1260712607
1260812608 if (prev_type->data.pointer.is_const && !cur_type->data.pointer.is_const) {
1260912609 // const array pointer and non-const unknown pointer
1261012610 make_the_pointer_const = true;
1261112611 }
12612 continue;
12612 continue;
1261312613 }
1261412614
1261512615 // *[N]T to [*]T
1261612616 if (cur_type->id == ZigTypeIdPointer &&
1261712617 cur_type->data.pointer.ptr_len == PtrLenSingle &&
1261812618 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)))
1262012620 {
1262112621 if (cur_type->data.pointer.is_const && !prev_type->data.pointer.is_const) {
1262212622 // const array pointer and non-const unknown pointer
1262312623 make_the_pointer_const = true;
1262412624 }
12625 continue;
12625 continue;
1262612626 }
1262712627
1262812628 // *[N]T to []T
......@@ -20986,17 +20986,24 @@ static IrInstGen *ir_analyze_negation(IrAnalyze *ira, IrInstSrcUnOp *instruction
2098620986 if (type_is_invalid(expr_type))
2098720987 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
2099820989 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
2100021007 ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
2100121008
2100221009 if (instr_is_comptime(value)) {
......@@ -25609,9 +25616,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2560925616 break;
2561025617 }
2561125618 case ZigTypeIdFnFrame:
25612 ir_add_error(ira, source_instr,
25613 buf_sprintf("compiler bug: TODO @typeInfo for async function frames. https://github.com/ziglang/zig/issues/3066"));
25614 return ErrorSemanticAnalyzeFail;
25619 {
25620 result = ira->codegen->pass1_arena->create<ZigValue>();
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 }
2561525631 }
2561625632
2561725633 assert(result != nullptr);
......@@ -25880,10 +25896,90 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2588025896 ZigType *child_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "child", 0);
2588125897 return get_any_frame_type(ira->codegen, child_type);
2588225898 }
25883 case ZigTypeIdErrorSet:
25884 case ZigTypeIdEnum:
25885 case ZigTypeIdFnFrame:
2588625899 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:
2588725983 ir_add_error(ira, source_instr, buf_sprintf(
2588825984 "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));
2588925985 return ira->codegen->invalid_inst_gen->value->type;
......@@ -30278,6 +30374,21 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF
3027830374 case BuiltinFnIdSqrt:
3027930375 f128M_sqrt(in, out);
3028030376 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;
3028130392 case BuiltinFnIdNearbyInt:
3028230393 case BuiltinFnIdSin:
3028330394 case BuiltinFnIdCos:
......@@ -30286,11 +30397,6 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF
3028630397 case BuiltinFnIdLog:
3028730398 case BuiltinFnIdLog10:
3028830399 case BuiltinFnIdLog2:
30289 case BuiltinFnIdFabs:
30290 case BuiltinFnIdFloor:
30291 case BuiltinFnIdCeil:
30292 case BuiltinFnIdTrunc:
30293 case BuiltinFnIdRound:
3029430400 return ir_add_error(ira, source_instr,
3029530401 buf_sprintf("compiler bug: TODO: implement '%s' for type '%s'. See https://github.com/ziglang/zig/issues/4026",
3029630402 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 {
3434 testZigInitExe,
3535 testGodboltApi,
3636 testMissingOutputPath,
37 testZigFmt,
3738 };
3839 for (test_fns) |testFn| {
3940 try fs.cwd().deleteTree(dir_path);
......@@ -143,3 +144,29 @@ fn testMissingOutputPath(zig_exe: []const u8, dir_path: []const u8) !void {
143144 zig_exe, "build-exe", source_path, "--output-dir", output_path,
144145 });
145146}
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 {
75307530 , &[_][]const u8{
75317531 "tmp.zig:2:9: error: @wasmMemoryGrow is a wasm32 feature only",
75327532 });
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 });
75337542}
test/stage1/behavior/math.zig+122
......@@ -634,6 +634,128 @@ fn testSqrt(comptime T: type, x: T) void {
634634 expect(@sqrt(x * x) == x);
635635}
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
637759test "comptime_int param and return" {
638760 const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
639761 expect(a == 137114567242441932203689521744947848950);
test/stage1/behavior/slice.zig+5
......@@ -280,6 +280,11 @@ test "slice syntax resulting in pointer-to-array" {
280280 expect(slice[0] == 5);
281281 comptime expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8);
282282 }
283
284 fn testConcatStrLiterals() void {
285 expectEqualSlices("a"[0..] ++ "b"[0..], "ab");
286 expectEqualSlices("a"[0..:0] ++ "b"[0..:0], "ab");
287 }
283288 };
284289
285290 S.doTheTest();
test/stage1/behavior/type.zig+23
......@@ -213,3 +213,26 @@ test "Type.AnyFrame" {
213213 anyframe->anyframe->u8,
214214 });
215215}
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 {
202202 expect(typeinfo_info.Union.fields[4].enum_field != null);
203203 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
204204 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
207207 const TestNoTagUnion = union {
208208 Foo: void,
......@@ -389,3 +389,16 @@ test "defaut value for a var-typed field" {
389389 const S = struct { x: var };
390390 expect(@typeInfo(S).Struct.fields[0].default_value == null);
391391}
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 {
14731473 cases.add("macro pointer cast",
14741474 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
14751475 , &[_][]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));
14771477 });
14781478
14791479 cases.add("basic macro function",
......@@ -2683,11 +2683,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
26832683 \\#define FOO(bar) baz((void *)(baz))
26842684 \\#define BAR (void*) a
26852685 , &[_][]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)))) {
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)));
2686 \\pub inline fn FOO(bar: var) @TypeOf(baz((@import("std").meta.cast(?*c_void, baz)))) {
2687 \\ return baz((@import("std").meta.cast(?*c_void, baz)));
26882688 \\}
26892689 ,
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));
26912691 });
26922692
26932693 cases.add("macro conditional operator",
......@@ -2905,8 +2905,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
29052905 \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
29062906 \\
29072907 , &[_][]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) {
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;
2908 \\pub inline fn DefaultScreen(dpy: var) @TypeOf((@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen) {
2909 \\ return (@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen;
29102910 \\}
29112911 });
29122912
......@@ -2914,9 +2914,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
29142914 \\#define NULL ((void*)0)
29152915 \\#define FOO ((int)0x8000)
29162916 , &[_][]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));
29182918 ,
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));
29202920 });
29212921
29222922 if (std.Target.current.abi == .msvc) {