| author | |
| committer | |
| log | 6938245fcc1daa6a63bcfcb3ba1092d569efc875 |
| tree | 035b27a399c418cab679043f87282dc3de1ef5b1 |
| parent | 7b68385d7d4448e81cc882d9a5464bf58d10dc0d |
| parent | 78c6d39cd49225bdfd2de4da7b1730ba26a41ba4 |
47 files changed, 1631 insertions(+), 647 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -288,6 +288,7 @@ set(ZIG_SOURCES |
| 288 | 288 | "${CMAKE_SOURCE_DIR}/src/target.cpp" |
| 289 | 289 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" |
| 290 | 290 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 291 | "${CMAKE_SOURCE_DIR}/src/softfloat_ext.cpp" | |
| 291 | 292 | "${ZIG_SOURCES_MEM_PROFILE}" |
| 292 | 293 | ) |
| 293 | 294 | set(OPTIMIZED_C_SOURCES |
build.zig+4-1| ... | ... | @@ -139,7 +139,10 @@ pub fn build(b: *Builder) !void { |
| 139 | 139 | test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); |
| 140 | 140 | test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes)); |
| 141 | 141 | test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes)); |
| 142 | test_step.dependOn(tests.addCliTests(b, test_filter, modes)); | |
| 142 | const test_cli = tests.addCliTests(b, test_filter, modes); | |
| 143 | const test_cli_step = b.step("test-cli", "Run zig cli tests"); | |
| 144 | test_cli_step.dependOn(test_cli); | |
| 145 | test_step.dependOn(test_cli); | |
| 143 | 146 | test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes)); |
| 144 | 147 | test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes)); |
| 145 | 148 | test_step.dependOn(tests.addTranslateCTests(b, test_filter)); |
doc/langref.html.in+79-80| ... | ... | @@ -236,19 +236,18 @@ pub fn main() !void { |
| 236 | 236 | } |
| 237 | 237 | {#code_end#} |
| 238 | 238 | <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: | |
| 242 | 241 | </p> |
| 243 | 242 | {#code_begin|exe|hello#} |
| 244 | const warn = @import("std").debug.warn; | |
| 243 | const print = @import("std").debug.print; | |
| 245 | 244 | |
| 246 | 245 | pub fn main() void { |
| 247 | warn("Hello, world!\n", .{}); | |
| 246 | print("Hello, world!\n", .{}); | |
| 248 | 247 | } |
| 249 | 248 | {#code_end#} |
| 250 | 249 | <p> |
| 251 | Note that you can leave off the {#syntax#}!{#endsyntax#} from the return type because {#syntax#}warn{#endsyntax#} cannot fail. | |
| 250 | Note that you can leave off the {#syntax#}!{#endsyntax#} from the return type because {#syntax#}print{#endsyntax#} cannot fail. | |
| 252 | 251 | </p> |
| 253 | 252 | {#see_also|Values|@import|Errors|Root Source File#} |
| 254 | 253 | {#header_close#} |
| ... | ... | @@ -307,7 +306,7 @@ const Timestamp = struct { |
| 307 | 306 | {#header_open|Values#} |
| 308 | 307 | {#code_begin|exe|values#} |
| 309 | 308 | // Top-level declarations are order-independent: |
| 310 | const warn = std.debug.warn; | |
| 309 | const print = std.debug.print; | |
| 311 | 310 | const std = @import("std"); |
| 312 | 311 | const os = std.os; |
| 313 | 312 | const assert = std.debug.assert; |
| ... | ... | @@ -315,14 +314,14 @@ const assert = std.debug.assert; |
| 315 | 314 | pub fn main() void { |
| 316 | 315 | // integers |
| 317 | 316 | const one_plus_one: i32 = 1 + 1; |
| 318 | warn("1 + 1 = {}\n", .{one_plus_one}); | |
| 317 | print("1 + 1 = {}\n", .{one_plus_one}); | |
| 319 | 318 | |
| 320 | 319 | // floats |
| 321 | 320 | const seven_div_three: f32 = 7.0 / 3.0; |
| 322 | warn("7.0 / 3.0 = {}\n", .{seven_div_three}); | |
| 321 | print("7.0 / 3.0 = {}\n", .{seven_div_three}); | |
| 323 | 322 | |
| 324 | 323 | // boolean |
| 325 | warn("{}\n{}\n{}\n", .{ | |
| 324 | print("{}\n{}\n{}\n", .{ | |
| 326 | 325 | true and false, |
| 327 | 326 | true or false, |
| 328 | 327 | !true, |
| ... | ... | @@ -332,7 +331,7 @@ pub fn main() void { |
| 332 | 331 | var optional_value: ?[]const u8 = null; |
| 333 | 332 | assert(optional_value == null); |
| 334 | 333 | |
| 335 | warn("\noptional 1\ntype: {}\nvalue: {}\n", .{ | |
| 334 | print("\noptional 1\ntype: {}\nvalue: {}\n", .{ | |
| 336 | 335 | @typeName(@TypeOf(optional_value)), |
| 337 | 336 | optional_value, |
| 338 | 337 | }); |
| ... | ... | @@ -340,7 +339,7 @@ pub fn main() void { |
| 340 | 339 | optional_value = "hi"; |
| 341 | 340 | assert(optional_value != null); |
| 342 | 341 | |
| 343 | warn("\noptional 2\ntype: {}\nvalue: {}\n", .{ | |
| 342 | print("\noptional 2\ntype: {}\nvalue: {}\n", .{ | |
| 344 | 343 | @typeName(@TypeOf(optional_value)), |
| 345 | 344 | optional_value, |
| 346 | 345 | }); |
| ... | ... | @@ -348,14 +347,14 @@ pub fn main() void { |
| 348 | 347 | // error union |
| 349 | 348 | var number_or_error: anyerror!i32 = error.ArgNotFound; |
| 350 | 349 | |
| 351 | warn("\nerror union 1\ntype: {}\nvalue: {}\n", .{ | |
| 350 | print("\nerror union 1\ntype: {}\nvalue: {}\n", .{ | |
| 352 | 351 | @typeName(@TypeOf(number_or_error)), |
| 353 | 352 | number_or_error, |
| 354 | 353 | }); |
| 355 | 354 | |
| 356 | 355 | number_or_error = 1234; |
| 357 | 356 | |
| 358 | warn("\nerror union 2\ntype: {}\nvalue: {}\n", .{ | |
| 357 | print("\nerror union 2\ntype: {}\nvalue: {}\n", .{ | |
| 359 | 358 | @typeName(@TypeOf(number_or_error)), |
| 360 | 359 | number_or_error, |
| 361 | 360 | }); |
| ... | ... | @@ -994,15 +993,15 @@ export fn foo_optimized(x: f64) f64 { |
| 994 | 993 | which operates in strict mode.</p> |
| 995 | 994 | {#code_begin|exe|float_mode#} |
| 996 | 995 | {#code_link_object|foo#} |
| 997 | const warn = @import("std").debug.warn; | |
| 996 | const print = @import("std").debug.print; | |
| 998 | 997 | |
| 999 | 998 | extern fn foo_strict(x: f64) f64; |
| 1000 | 999 | extern fn foo_optimized(x: f64) f64; |
| 1001 | 1000 | |
| 1002 | 1001 | pub fn main() void { |
| 1003 | 1002 | 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)}); | |
| 1006 | 1005 | } |
| 1007 | 1006 | {#code_end#} |
| 1008 | 1007 | {#see_also|@setFloatMode|Division by Zero#} |
| ... | ... | @@ -2668,9 +2667,9 @@ const std = @import("std"); |
| 2668 | 2667 | |
| 2669 | 2668 | pub fn main() void { |
| 2670 | 2669 | 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))}); | |
| 2674 | 2673 | } |
| 2675 | 2674 | |
| 2676 | 2675 | fn List(comptime T: type) type { |
| ... | ... | @@ -3869,7 +3868,7 @@ test "if error union" { |
| 3869 | 3868 | {#code_begin|test|defer#} |
| 3870 | 3869 | const std = @import("std"); |
| 3871 | 3870 | const assert = std.debug.assert; |
| 3872 | const warn = std.debug.warn; | |
| 3871 | const print = std.debug.print; | |
| 3873 | 3872 | |
| 3874 | 3873 | // defer will execute an expression at the end of the current scope. |
| 3875 | 3874 | fn deferExample() usize { |
| ... | ... | @@ -3892,18 +3891,18 @@ test "defer basics" { |
| 3892 | 3891 | // If multiple defer statements are specified, they will be executed in |
| 3893 | 3892 | // the reverse order they were run. |
| 3894 | 3893 | fn deferUnwindExample() void { |
| 3895 | warn("\n", .{}); | |
| 3894 | print("\n", .{}); | |
| 3896 | 3895 | |
| 3897 | 3896 | defer { |
| 3898 | warn("1 ", .{}); | |
| 3897 | print("1 ", .{}); | |
| 3899 | 3898 | } |
| 3900 | 3899 | defer { |
| 3901 | warn("2 ", .{}); | |
| 3900 | print("2 ", .{}); | |
| 3902 | 3901 | } |
| 3903 | 3902 | if (false) { |
| 3904 | 3903 | // defers are not run if they are never executed. |
| 3905 | 3904 | defer { |
| 3906 | warn("3 ", .{}); | |
| 3905 | print("3 ", .{}); | |
| 3907 | 3906 | } |
| 3908 | 3907 | } |
| 3909 | 3908 | } |
| ... | ... | @@ -3918,15 +3917,15 @@ test "defer unwinding" { |
| 3918 | 3917 | // This is especially useful in allowing a function to clean up properly |
| 3919 | 3918 | // on error, and replaces goto error handling tactics as seen in c. |
| 3920 | 3919 | fn deferErrorExample(is_error: bool) !void { |
| 3921 | warn("\nstart of function\n", .{}); | |
| 3920 | print("\nstart of function\n", .{}); | |
| 3922 | 3921 | |
| 3923 | 3922 | // This will always be executed on exit |
| 3924 | 3923 | defer { |
| 3925 | warn("end of function\n", .{}); | |
| 3924 | print("end of function\n", .{}); | |
| 3926 | 3925 | } |
| 3927 | 3926 | |
| 3928 | 3927 | errdefer { |
| 3929 | warn("encountered an error!\n", .{}); | |
| 3928 | print("encountered an error!\n", .{}); | |
| 3930 | 3929 | } |
| 3931 | 3930 | |
| 3932 | 3931 | if (is_error) { |
| ... | ... | @@ -5925,13 +5924,13 @@ const Node = struct { |
| 5925 | 5924 | Putting all of this together, let's see how {#syntax#}printf{#endsyntax#} works in Zig. |
| 5926 | 5925 | </p> |
| 5927 | 5926 | {#code_begin|exe|printf#} |
| 5928 | const warn = @import("std").debug.warn; | |
| 5927 | const print = @import("std").debug.print; | |
| 5929 | 5928 | |
| 5930 | 5929 | const a_number: i32 = 1234; |
| 5931 | 5930 | const a_string = "foobar"; |
| 5932 | 5931 | |
| 5933 | 5932 | pub fn main() void { |
| 5934 | warn("here is a string: '{}' here is a number: {}\n", .{a_string, a_number}); | |
| 5933 | print("here is a string: '{}' here is a number: {}\n", .{a_string, a_number}); | |
| 5935 | 5934 | } |
| 5936 | 5935 | {#code_end#} |
| 5937 | 5936 | |
| ... | ... | @@ -6045,13 +6044,13 @@ pub fn printValue(self: *OutStream, value: var) !void { |
| 6045 | 6044 | And now, what happens if we give too many arguments to {#syntax#}printf{#endsyntax#}? |
| 6046 | 6045 | </p> |
| 6047 | 6046 | {#code_begin|test_err|Unused arguments#} |
| 6048 | const warn = @import("std").debug.warn; | |
| 6047 | const print = @import("std").debug.print; | |
| 6049 | 6048 | |
| 6050 | 6049 | const a_number: i32 = 1234; |
| 6051 | 6050 | const a_string = "foobar"; |
| 6052 | 6051 | |
| 6053 | 6052 | test "printf too many arguments" { |
| 6054 | warn("here is a string: '{}' here is a number: {}\n", .{ | |
| 6053 | print("here is a string: '{}' here is a number: {}\n", .{ | |
| 6055 | 6054 | a_string, |
| 6056 | 6055 | a_number, |
| 6057 | 6056 | a_number, |
| ... | ... | @@ -6066,14 +6065,14 @@ test "printf too many arguments" { |
| 6066 | 6065 | only that it is a compile-time known value that can be coerced to a {#syntax#}[]const u8{#endsyntax#}: |
| 6067 | 6066 | </p> |
| 6068 | 6067 | {#code_begin|exe|printf#} |
| 6069 | const warn = @import("std").debug.warn; | |
| 6068 | const print = @import("std").debug.print; | |
| 6070 | 6069 | |
| 6071 | 6070 | const a_number: i32 = 1234; |
| 6072 | 6071 | const a_string = "foobar"; |
| 6073 | 6072 | const fmt = "here is a string: '{}' here is a number: {}\n"; |
| 6074 | 6073 | |
| 6075 | 6074 | pub fn main() void { |
| 6076 | warn(fmt, .{a_string, a_number}); | |
| 6075 | print(fmt, .{a_string, a_number}); | |
| 6077 | 6076 | } |
| 6078 | 6077 | {#code_end#} |
| 6079 | 6078 | <p> |
| ... | ... | @@ -6511,7 +6510,7 @@ pub fn main() void { |
| 6511 | 6510 | |
| 6512 | 6511 | fn amainWrap() void { |
| 6513 | 6512 | amain() catch |e| { |
| 6514 | std.debug.warn("{}\n", .{e}); | |
| 6513 | std.debug.print("{}\n", .{e}); | |
| 6515 | 6514 | if (@errorReturnTrace()) |trace| { |
| 6516 | 6515 | std.debug.dumpStackTrace(trace.*); |
| 6517 | 6516 | } |
| ... | ... | @@ -6541,8 +6540,8 @@ fn amain() !void { |
| 6541 | 6540 | const download_text = try await download_frame; |
| 6542 | 6541 | defer allocator.free(download_text); |
| 6543 | 6542 | |
| 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}); | |
| 6546 | 6545 | } |
| 6547 | 6546 | |
| 6548 | 6547 | var global_download_frame: anyframe = undefined; |
| ... | ... | @@ -6552,7 +6551,7 @@ fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 { |
| 6552 | 6551 | suspend { |
| 6553 | 6552 | global_download_frame = @frame(); |
| 6554 | 6553 | } |
| 6555 | std.debug.warn("fetchUrl returning\n", .{}); | |
| 6554 | std.debug.print("fetchUrl returning\n", .{}); | |
| 6556 | 6555 | return result; |
| 6557 | 6556 | } |
| 6558 | 6557 | |
| ... | ... | @@ -6563,7 +6562,7 @@ fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 { |
| 6563 | 6562 | suspend { |
| 6564 | 6563 | global_file_frame = @frame(); |
| 6565 | 6564 | } |
| 6566 | std.debug.warn("readFile returning\n", .{}); | |
| 6565 | std.debug.print("readFile returning\n", .{}); | |
| 6567 | 6566 | return result; |
| 6568 | 6567 | } |
| 6569 | 6568 | {#code_end#} |
| ... | ... | @@ -6581,7 +6580,7 @@ pub fn main() void { |
| 6581 | 6580 | |
| 6582 | 6581 | fn amainWrap() void { |
| 6583 | 6582 | amain() catch |e| { |
| 6584 | std.debug.warn("{}\n", .{e}); | |
| 6583 | std.debug.print("{}\n", .{e}); | |
| 6585 | 6584 | if (@errorReturnTrace()) |trace| { |
| 6586 | 6585 | std.debug.dumpStackTrace(trace.*); |
| 6587 | 6586 | } |
| ... | ... | @@ -6611,21 +6610,21 @@ fn amain() !void { |
| 6611 | 6610 | const download_text = try await download_frame; |
| 6612 | 6611 | defer allocator.free(download_text); |
| 6613 | 6612 | |
| 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}); | |
| 6616 | 6615 | } |
| 6617 | 6616 | |
| 6618 | 6617 | fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 { |
| 6619 | 6618 | const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents"); |
| 6620 | 6619 | errdefer allocator.free(result); |
| 6621 | std.debug.warn("fetchUrl returning\n", .{}); | |
| 6620 | std.debug.print("fetchUrl returning\n", .{}); | |
| 6622 | 6621 | return result; |
| 6623 | 6622 | } |
| 6624 | 6623 | |
| 6625 | 6624 | fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 { |
| 6626 | 6625 | const result = try std.mem.dupe(allocator, u8, "this is the file contents"); |
| 6627 | 6626 | errdefer allocator.free(result); |
| 6628 | std.debug.warn("readFile returning\n", .{}); | |
| 6627 | std.debug.print("readFile returning\n", .{}); | |
| 6629 | 6628 | return result; |
| 6630 | 6629 | } |
| 6631 | 6630 | {#code_end#} |
| ... | ... | @@ -7121,7 +7120,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 7121 | 7120 | compile-time executing code. |
| 7122 | 7121 | </p> |
| 7123 | 7122 | {#code_begin|test_err|found compile log statement#} |
| 7124 | const warn = @import("std").debug.warn; | |
| 7123 | const print = @import("std").debug.print; | |
| 7125 | 7124 | |
| 7126 | 7125 | const num1 = blk: { |
| 7127 | 7126 | var val1: i32 = 99; |
| ... | ... | @@ -7133,7 +7132,7 @@ const num1 = blk: { |
| 7133 | 7132 | test "main" { |
| 7134 | 7133 | @compileLog("comptime in main"); |
| 7135 | 7134 | |
| 7136 | warn("Runtime in main, num1 = {}.\n", .{num1}); | |
| 7135 | print("Runtime in main, num1 = {}.\n", .{num1}); | |
| 7137 | 7136 | } |
| 7138 | 7137 | {#code_end#} |
| 7139 | 7138 | <p> |
| ... | ... | @@ -7145,7 +7144,7 @@ test "main" { |
| 7145 | 7144 | program compiles successfully and the generated executable prints: |
| 7146 | 7145 | </p> |
| 7147 | 7146 | {#code_begin|test#} |
| 7148 | const warn = @import("std").debug.warn; | |
| 7147 | const print = @import("std").debug.print; | |
| 7149 | 7148 | |
| 7150 | 7149 | const num1 = blk: { |
| 7151 | 7150 | var val1: i32 = 99; |
| ... | ... | @@ -7154,7 +7153,7 @@ const num1 = blk: { |
| 7154 | 7153 | }; |
| 7155 | 7154 | |
| 7156 | 7155 | test "main" { |
| 7157 | warn("Runtime in main, num1 = {}.\n", .{num1}); | |
| 7156 | print("Runtime in main, num1 = {}.\n", .{num1}); | |
| 7158 | 7157 | } |
| 7159 | 7158 | {#code_end#} |
| 7160 | 7159 | {#header_close#} |
| ... | ... | @@ -8205,7 +8204,7 @@ test "vector @splat" { |
| 8205 | 8204 | {#header_open|@This#} |
| 8206 | 8205 | <pre>{#syntax#}@This() type{#endsyntax#}</pre> |
| 8207 | 8206 | <p> |
| 8208 | Returns the innermost struct or union that this function call is inside. | |
| 8207 | Returns the innermost struct, enum, or union that this function call is inside. | |
| 8209 | 8208 | This can be useful for an anonymous struct that needs to refer to itself: |
| 8210 | 8209 | </p> |
| 8211 | 8210 | {#code_begin|test#} |
| ... | ... | @@ -8555,7 +8554,7 @@ const std = @import("std"); |
| 8555 | 8554 | pub fn main() void { |
| 8556 | 8555 | var value: i32 = -1; |
| 8557 | 8556 | var unsigned = @intCast(u32, value); |
| 8558 | std.debug.warn("value: {}\n", .{unsigned}); | |
| 8557 | std.debug.print("value: {}\n", .{unsigned}); | |
| 8559 | 8558 | } |
| 8560 | 8559 | {#code_end#} |
| 8561 | 8560 | <p> |
| ... | ... | @@ -8577,7 +8576,7 @@ const std = @import("std"); |
| 8577 | 8576 | pub fn main() void { |
| 8578 | 8577 | var spartan_count: u16 = 300; |
| 8579 | 8578 | const byte = @intCast(u8, spartan_count); |
| 8580 | std.debug.warn("value: {}\n", .{byte}); | |
| 8579 | std.debug.print("value: {}\n", .{byte}); | |
| 8581 | 8580 | } |
| 8582 | 8581 | {#code_end#} |
| 8583 | 8582 | <p> |
| ... | ... | @@ -8611,7 +8610,7 @@ const std = @import("std"); |
| 8611 | 8610 | pub fn main() void { |
| 8612 | 8611 | var byte: u8 = 255; |
| 8613 | 8612 | byte += 1; |
| 8614 | std.debug.warn("value: {}\n", .{byte}); | |
| 8613 | std.debug.print("value: {}\n", .{byte}); | |
| 8615 | 8614 | } |
| 8616 | 8615 | {#code_end#} |
| 8617 | 8616 | {#header_close#} |
| ... | ... | @@ -8629,16 +8628,16 @@ pub fn main() void { |
| 8629 | 8628 | <p>Example of catching an overflow for addition:</p> |
| 8630 | 8629 | {#code_begin|exe_err#} |
| 8631 | 8630 | const math = @import("std").math; |
| 8632 | const warn = @import("std").debug.warn; | |
| 8631 | const print = @import("std").debug.print; | |
| 8633 | 8632 | pub fn main() !void { |
| 8634 | 8633 | var byte: u8 = 255; |
| 8635 | 8634 | |
| 8636 | 8635 | byte = if (math.add(u8, byte, 1)) |result| result else |err| { |
| 8637 | warn("unable to add one: {}\n", .{@errorName(err)}); | |
| 8636 | print("unable to add one: {}\n", .{@errorName(err)}); | |
| 8638 | 8637 | return err; |
| 8639 | 8638 | }; |
| 8640 | 8639 | |
| 8641 | warn("result: {}\n", .{byte}); | |
| 8640 | print("result: {}\n", .{byte}); | |
| 8642 | 8641 | } |
| 8643 | 8642 | {#code_end#} |
| 8644 | 8643 | {#header_close#} |
| ... | ... | @@ -8657,15 +8656,15 @@ pub fn main() !void { |
| 8657 | 8656 | Example of {#link|@addWithOverflow#}: |
| 8658 | 8657 | </p> |
| 8659 | 8658 | {#code_begin|exe#} |
| 8660 | const warn = @import("std").debug.warn; | |
| 8659 | const print = @import("std").debug.print; | |
| 8661 | 8660 | pub fn main() void { |
| 8662 | 8661 | var byte: u8 = 255; |
| 8663 | 8662 | |
| 8664 | 8663 | var result: u8 = undefined; |
| 8665 | 8664 | if (@addWithOverflow(u8, byte, 10, &result)) { |
| 8666 | warn("overflowed result: {}\n", .{result}); | |
| 8665 | print("overflowed result: {}\n", .{result}); | |
| 8667 | 8666 | } else { |
| 8668 | warn("result: {}\n", .{result}); | |
| 8667 | print("result: {}\n", .{result}); | |
| 8669 | 8668 | } |
| 8670 | 8669 | } |
| 8671 | 8670 | {#code_end#} |
| ... | ... | @@ -8710,7 +8709,7 @@ const std = @import("std"); |
| 8710 | 8709 | pub fn main() void { |
| 8711 | 8710 | var x: u8 = 0b01010101; |
| 8712 | 8711 | var y = @shlExact(x, 2); |
| 8713 | std.debug.warn("value: {}\n", .{y}); | |
| 8712 | std.debug.print("value: {}\n", .{y}); | |
| 8714 | 8713 | } |
| 8715 | 8714 | {#code_end#} |
| 8716 | 8715 | {#header_close#} |
| ... | ... | @@ -8728,7 +8727,7 @@ const std = @import("std"); |
| 8728 | 8727 | pub fn main() void { |
| 8729 | 8728 | var x: u8 = 0b10101010; |
| 8730 | 8729 | var y = @shrExact(x, 2); |
| 8731 | std.debug.warn("value: {}\n", .{y}); | |
| 8730 | std.debug.print("value: {}\n", .{y}); | |
| 8732 | 8731 | } |
| 8733 | 8732 | {#code_end#} |
| 8734 | 8733 | {#header_close#} |
| ... | ... | @@ -8749,7 +8748,7 @@ pub fn main() void { |
| 8749 | 8748 | var a: u32 = 1; |
| 8750 | 8749 | var b: u32 = 0; |
| 8751 | 8750 | var c = a / b; |
| 8752 | std.debug.warn("value: {}\n", .{c}); | |
| 8751 | std.debug.print("value: {}\n", .{c}); | |
| 8753 | 8752 | } |
| 8754 | 8753 | {#code_end#} |
| 8755 | 8754 | {#header_close#} |
| ... | ... | @@ -8770,7 +8769,7 @@ pub fn main() void { |
| 8770 | 8769 | var a: u32 = 10; |
| 8771 | 8770 | var b: u32 = 0; |
| 8772 | 8771 | var c = a % b; |
| 8773 | std.debug.warn("value: {}\n", .{c}); | |
| 8772 | std.debug.print("value: {}\n", .{c}); | |
| 8774 | 8773 | } |
| 8775 | 8774 | {#code_end#} |
| 8776 | 8775 | {#header_close#} |
| ... | ... | @@ -8791,7 +8790,7 @@ pub fn main() void { |
| 8791 | 8790 | var a: u32 = 10; |
| 8792 | 8791 | var b: u32 = 3; |
| 8793 | 8792 | var c = @divExact(a, b); |
| 8794 | std.debug.warn("value: {}\n", .{c}); | |
| 8793 | std.debug.print("value: {}\n", .{c}); | |
| 8795 | 8794 | } |
| 8796 | 8795 | {#code_end#} |
| 8797 | 8796 | {#header_close#} |
| ... | ... | @@ -8810,20 +8809,20 @@ const std = @import("std"); |
| 8810 | 8809 | pub fn main() void { |
| 8811 | 8810 | var optional_number: ?i32 = null; |
| 8812 | 8811 | var number = optional_number.?; |
| 8813 | std.debug.warn("value: {}\n", .{number}); | |
| 8812 | std.debug.print("value: {}\n", .{number}); | |
| 8814 | 8813 | } |
| 8815 | 8814 | {#code_end#} |
| 8816 | 8815 | <p>One way to avoid this crash is to test for null instead of assuming non-null, with |
| 8817 | 8816 | the {#syntax#}if{#endsyntax#} expression:</p> |
| 8818 | 8817 | {#code_begin|exe|test#} |
| 8819 | const warn = @import("std").debug.warn; | |
| 8818 | const print = @import("std").debug.print; | |
| 8820 | 8819 | pub fn main() void { |
| 8821 | 8820 | const optional_number: ?i32 = null; |
| 8822 | 8821 | |
| 8823 | 8822 | if (optional_number) |number| { |
| 8824 | warn("got number: {}\n", .{number}); | |
| 8823 | print("got number: {}\n", .{number}); | |
| 8825 | 8824 | } else { |
| 8826 | warn("it's null\n", .{}); | |
| 8825 | print("it's null\n", .{}); | |
| 8827 | 8826 | } |
| 8828 | 8827 | } |
| 8829 | 8828 | {#code_end#} |
| ... | ... | @@ -8846,7 +8845,7 @@ const std = @import("std"); |
| 8846 | 8845 | |
| 8847 | 8846 | pub fn main() void { |
| 8848 | 8847 | const number = getNumberOrFail() catch unreachable; |
| 8849 | std.debug.warn("value: {}\n", .{number}); | |
| 8848 | std.debug.print("value: {}\n", .{number}); | |
| 8850 | 8849 | } |
| 8851 | 8850 | |
| 8852 | 8851 | fn getNumberOrFail() !i32 { |
| ... | ... | @@ -8856,15 +8855,15 @@ fn getNumberOrFail() !i32 { |
| 8856 | 8855 | <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with |
| 8857 | 8856 | the {#syntax#}if{#endsyntax#} expression:</p> |
| 8858 | 8857 | {#code_begin|exe#} |
| 8859 | const warn = @import("std").debug.warn; | |
| 8858 | const print = @import("std").debug.print; | |
| 8860 | 8859 | |
| 8861 | 8860 | pub fn main() void { |
| 8862 | 8861 | const result = getNumberOrFail(); |
| 8863 | 8862 | |
| 8864 | 8863 | if (result) |number| { |
| 8865 | warn("got number: {}\n", .{number}); | |
| 8864 | print("got number: {}\n", .{number}); | |
| 8866 | 8865 | } else |err| { |
| 8867 | warn("got error: {}\n", .{@errorName(err)}); | |
| 8866 | print("got error: {}\n", .{@errorName(err)}); | |
| 8868 | 8867 | } |
| 8869 | 8868 | } |
| 8870 | 8869 | |
| ... | ... | @@ -8891,7 +8890,7 @@ pub fn main() void { |
| 8891 | 8890 | var err = error.AnError; |
| 8892 | 8891 | var number = @errorToInt(err) + 500; |
| 8893 | 8892 | var invalid_err = @intToError(number); |
| 8894 | std.debug.warn("value: {}\n", .{number}); | |
| 8893 | std.debug.print("value: {}\n", .{number}); | |
| 8895 | 8894 | } |
| 8896 | 8895 | {#code_end#} |
| 8897 | 8896 | {#header_close#} |
| ... | ... | @@ -8921,7 +8920,7 @@ const Foo = enum { |
| 8921 | 8920 | pub fn main() void { |
| 8922 | 8921 | var a: u2 = 3; |
| 8923 | 8922 | var b = @intToEnum(Foo, a); |
| 8924 | std.debug.warn("value: {}\n", .{@tagName(b)}); | |
| 8923 | std.debug.print("value: {}\n", .{@tagName(b)}); | |
| 8925 | 8924 | } |
| 8926 | 8925 | {#code_end#} |
| 8927 | 8926 | {#header_close#} |
| ... | ... | @@ -8958,7 +8957,7 @@ pub fn main() void { |
| 8958 | 8957 | } |
| 8959 | 8958 | fn foo(set1: Set1) void { |
| 8960 | 8959 | const x = @errSetCast(Set2, set1); |
| 8961 | std.debug.warn("value: {}\n", .{x}); | |
| 8960 | std.debug.print("value: {}\n", .{x}); | |
| 8962 | 8961 | } |
| 8963 | 8962 | {#code_end#} |
| 8964 | 8963 | {#header_close#} |
| ... | ... | @@ -9015,7 +9014,7 @@ pub fn main() void { |
| 9015 | 9014 | |
| 9016 | 9015 | fn bar(f: *Foo) void { |
| 9017 | 9016 | f.float = 12.34; |
| 9018 | std.debug.warn("value: {}\n", .{f.float}); | |
| 9017 | std.debug.print("value: {}\n", .{f.float}); | |
| 9019 | 9018 | } |
| 9020 | 9019 | {#code_end#} |
| 9021 | 9020 | <p> |
| ... | ... | @@ -9039,7 +9038,7 @@ pub fn main() void { |
| 9039 | 9038 | |
| 9040 | 9039 | fn bar(f: *Foo) void { |
| 9041 | 9040 | f.* = Foo{ .float = 12.34 }; |
| 9042 | std.debug.warn("value: {}\n", .{f.float}); | |
| 9041 | std.debug.print("value: {}\n", .{f.float}); | |
| 9043 | 9042 | } |
| 9044 | 9043 | {#code_end#} |
| 9045 | 9044 | <p> |
| ... | ... | @@ -9058,7 +9057,7 @@ pub fn main() void { |
| 9058 | 9057 | var f = Foo{ .int = 42 }; |
| 9059 | 9058 | f = Foo{ .float = undefined }; |
| 9060 | 9059 | bar(&f); |
| 9061 | std.debug.warn("value: {}\n", .{f.float}); | |
| 9060 | std.debug.print("value: {}\n", .{f.float}); | |
| 9062 | 9061 | } |
| 9063 | 9062 | |
| 9064 | 9063 | fn bar(f: *Foo) void { |
| ... | ... | @@ -9178,7 +9177,7 @@ pub fn main() !void { |
| 9178 | 9177 | const allocator = &arena.allocator; |
| 9179 | 9178 | |
| 9180 | 9179 | const ptr = try allocator.create(i32); |
| 9181 | std.debug.warn("ptr={*}\n", .{ptr}); | |
| 9180 | std.debug.print("ptr={*}\n", .{ptr}); | |
| 9182 | 9181 | } |
| 9183 | 9182 | {#code_end#} |
| 9184 | 9183 | When using this kind of allocator, there is no need to free anything manually. Everything |
| ... | ... | @@ -9712,7 +9711,7 @@ pub fn main() !void { |
| 9712 | 9711 | defer std.process.argsFree(std.heap.page_allocator, args); |
| 9713 | 9712 | |
| 9714 | 9713 | for (args) |arg, i| { |
| 9715 | std.debug.warn("{}: {}\n", .{i, arg}); | |
| 9714 | std.debug.print("{}: {}\n", .{i, arg}); | |
| 9716 | 9715 | } |
| 9717 | 9716 | } |
| 9718 | 9717 | {#code_end#} |
| ... | ... | @@ -9734,7 +9733,7 @@ pub fn main() !void { |
| 9734 | 9733 | try preopens.populate(); |
| 9735 | 9734 | |
| 9736 | 9735 | for (preopens.asSlice()) |preopen, i| { |
| 9737 | std.debug.warn("{}: {}\n", .{ i, preopen }); | |
| 9736 | std.debug.print("{}: {}\n", .{ i, preopen }); | |
| 9738 | 9737 | } |
| 9739 | 9738 | } |
| 9740 | 9739 | {#code_end#} |
lib/std/array_list.zig+1-1| ... | ... | @@ -162,7 +162,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 162 | 162 | mem.copy(T, self.items[oldlen..], items); |
| 163 | 163 | } |
| 164 | 164 | |
| 165 | pub usingnamespace if (T != u8) struct { } else struct { | |
| 165 | pub usingnamespace if (T != u8) struct {} else struct { | |
| 166 | 166 | pub const Writer = std.io.Writer(*Self, error{OutOfMemory}, appendWrite); |
| 167 | 167 | |
| 168 | 168 | /// Initializes a Writer which will append to the list. |
lib/std/build.zig+7| ... | ... | @@ -2559,3 +2559,10 @@ pub const InstalledFile = struct { |
| 2559 | 2559 | dir: InstallDir, |
| 2560 | 2560 | path: []const u8, |
| 2561 | 2561 | }; |
| 2562 | ||
| 2563 | test "" { | |
| 2564 | // The only purpose of this test is to get all these untested functions | |
| 2565 | // to be referenced to avoid regression so it is okay to skip some targets. | |
| 2566 | if (comptime std.Target.current.cpu.arch.ptrBitWidth() == 64) | |
| 2567 | std.meta.refAllDecls(@This()); | |
| 2568 | } |
lib/std/build/emit_raw.zig+4| ... | ... | @@ -215,3 +215,7 @@ pub const InstallRawStep = struct { |
| 215 | 215 | try emitRaw(builder.allocator, full_src_path, full_dest_path); |
| 216 | 216 | } |
| 217 | 217 | }; |
| 218 | ||
| 219 | test "" { | |
| 220 | std.meta.refAllDecls(InstallRawStep); | |
| 221 | } |
lib/std/builtin.zig+17-10| ... | ... | @@ -166,7 +166,7 @@ pub const TypeInfo = union(enum) { |
| 166 | 166 | Fn: Fn, |
| 167 | 167 | BoundFn: Fn, |
| 168 | 168 | Opaque: void, |
| 169 | Frame: void, | |
| 169 | Frame: Frame, | |
| 170 | 170 | AnyFrame: AnyFrame, |
| 171 | 171 | Vector: Vector, |
| 172 | 172 | EnumLiteral: void, |
| ... | ... | @@ -244,8 +244,8 @@ pub const TypeInfo = union(enum) { |
| 244 | 244 | /// therefore must be kept in sync with the compiler implementation. |
| 245 | 245 | pub const Struct = struct { |
| 246 | 246 | layout: ContainerLayout, |
| 247 | fields: []StructField, | |
| 248 | decls: []Declaration, | |
| 247 | fields: []const StructField, | |
| 248 | decls: []const Declaration, | |
| 249 | 249 | }; |
| 250 | 250 | |
| 251 | 251 | /// This data structure is used by the Zig language code generation and |
| ... | ... | @@ -265,12 +265,13 @@ pub const TypeInfo = union(enum) { |
| 265 | 265 | /// therefore must be kept in sync with the compiler implementation. |
| 266 | 266 | pub const Error = struct { |
| 267 | 267 | name: []const u8, |
| 268 | /// This field is ignored when using @Type(). | |
| 268 | 269 | value: comptime_int, |
| 269 | 270 | }; |
| 270 | 271 | |
| 271 | 272 | /// This data structure is used by the Zig language code generation and |
| 272 | 273 | /// therefore must be kept in sync with the compiler implementation. |
| 273 | pub const ErrorSet = ?[]Error; | |
| 274 | pub const ErrorSet = ?[]const Error; | |
| 274 | 275 | |
| 275 | 276 | /// This data structure is used by the Zig language code generation and |
| 276 | 277 | /// therefore must be kept in sync with the compiler implementation. |
| ... | ... | @@ -284,8 +285,8 @@ pub const TypeInfo = union(enum) { |
| 284 | 285 | pub const Enum = struct { |
| 285 | 286 | layout: ContainerLayout, |
| 286 | 287 | tag_type: type, |
| 287 | fields: []EnumField, | |
| 288 | decls: []Declaration, | |
| 288 | fields: []const EnumField, | |
| 289 | decls: []const Declaration, | |
| 289 | 290 | is_exhaustive: bool, |
| 290 | 291 | }; |
| 291 | 292 | |
| ... | ... | @@ -302,8 +303,8 @@ pub const TypeInfo = union(enum) { |
| 302 | 303 | pub const Union = struct { |
| 303 | 304 | layout: ContainerLayout, |
| 304 | 305 | tag_type: ?type, |
| 305 | fields: []UnionField, | |
| 306 | decls: []Declaration, | |
| 306 | fields: []const UnionField, | |
| 307 | decls: []const Declaration, | |
| 307 | 308 | }; |
| 308 | 309 | |
| 309 | 310 | /// This data structure is used by the Zig language code generation and |
| ... | ... | @@ -321,7 +322,13 @@ pub const TypeInfo = union(enum) { |
| 321 | 322 | is_generic: bool, |
| 322 | 323 | is_var_args: bool, |
| 323 | 324 | return_type: ?type, |
| 324 | args: []FnArg, | |
| 325 | args: []const FnArg, | |
| 326 | }; | |
| 327 | ||
| 328 | /// This data structure is used by the Zig language code generation and | |
| 329 | /// therefore must be kept in sync with the compiler implementation. | |
| 330 | pub const Frame = struct { | |
| 331 | function: var, | |
| 325 | 332 | }; |
| 326 | 333 | |
| 327 | 334 | /// This data structure is used by the Zig language code generation and |
| ... | ... | @@ -361,7 +368,7 @@ pub const TypeInfo = union(enum) { |
| 361 | 368 | is_export: bool, |
| 362 | 369 | lib_name: ?[]const u8, |
| 363 | 370 | return_type: type, |
| 364 | arg_names: [][]const u8, | |
| 371 | arg_names: []const []const u8, | |
| 365 | 372 | |
| 366 | 373 | /// This data structure is used by the Zig language code generation and |
| 367 | 374 | /// therefore must be kept in sync with the compiler implementation. |
lib/std/c.zig+1| ... | ... | @@ -102,6 +102,7 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int; |
| 102 | 102 | pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int; |
| 103 | 103 | pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int; |
| 104 | 104 | pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int; |
| 105 | pub extern "c" fn symlinkat(oldpath: [*:0]const u8, newdirfd: fd_t, newpath: [*:0]const u8) c_int; | |
| 105 | 106 | pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int; |
| 106 | 107 | pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int; |
| 107 | 108 | pub extern "c" fn chdir(path: [*:0]const u8) c_int; |
lib/std/c/tokenizer.zig+50-50| ... | ... | @@ -278,62 +278,62 @@ pub const Token = struct { |
| 278 | 278 | |
| 279 | 279 | // TODO extensions |
| 280 | 280 | 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 }, | |
| 313 | 313 | |
| 314 | 314 | // 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 }, | |
| 320 | 320 | |
| 321 | 321 | // 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 }, | |
| 329 | 329 | |
| 330 | 330 | // 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 }, | |
| 337 | 337 | }); |
| 338 | 338 | |
| 339 | 339 | // TODO do this in the preprocessor |
lib/std/debug.zig+7-3| ... | ... | @@ -52,9 +52,13 @@ pub const LineInfo = struct { |
| 52 | 52 | |
| 53 | 53 | var stderr_mutex = std.Mutex.init(); |
| 54 | 54 | |
| 55 | /// Tries to write to stderr, unbuffered, and ignores any error returned. | |
| 56 | /// Does not append a newline. | |
| 57 | pub 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". | |
| 57 | pub 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. | |
| 61 | pub fn print(comptime fmt: []const u8, args: var) void { | |
| 58 | 62 | const held = stderr_mutex.acquire(); |
| 59 | 63 | defer held.release(); |
| 60 | 64 | const stderr = io.getStdErr().writer(); |
lib/std/fmt.zig+175-175| ... | ... | @@ -69,14 +69,14 @@ fn peekIsAlign(comptime fmt: []const u8) bool { |
| 69 | 69 | /// |
| 70 | 70 | /// If a formatted user type contains a function of the type |
| 71 | 71 | /// ``` |
| 72 | /// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void | |
| 72 | /// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: var) !void | |
| 73 | 73 | /// ``` |
| 74 | 74 | /// with `?` being the type formatted, this function will be called instead of the default implementation. |
| 75 | 75 | /// This allows user types to be formatted in a logical manner instead of dumping all fields of the type. |
| 76 | 76 | /// |
| 77 | 77 | /// A user type may be a `struct`, `vector`, `union` or `enum` type. |
| 78 | 78 | pub fn format( |
| 79 | out_stream: var, | |
| 79 | writer: var, | |
| 80 | 80 | comptime fmt: []const u8, |
| 81 | 81 | args: var, |
| 82 | 82 | ) !void { |
| ... | ... | @@ -136,7 +136,7 @@ pub fn format( |
| 136 | 136 | .Start => switch (c) { |
| 137 | 137 | '{' => { |
| 138 | 138 | if (start_index < i) { |
| 139 | try out_stream.writeAll(fmt[start_index..i]); | |
| 139 | try writer.writeAll(fmt[start_index..i]); | |
| 140 | 140 | } |
| 141 | 141 | |
| 142 | 142 | start_index = i; |
| ... | ... | @@ -148,7 +148,7 @@ pub fn format( |
| 148 | 148 | }, |
| 149 | 149 | '}' => { |
| 150 | 150 | if (start_index < i) { |
| 151 | try out_stream.writeAll(fmt[start_index..i]); | |
| 151 | try writer.writeAll(fmt[start_index..i]); | |
| 152 | 152 | } |
| 153 | 153 | state = .CloseBrace; |
| 154 | 154 | }, |
| ... | ... | @@ -183,7 +183,7 @@ pub fn format( |
| 183 | 183 | args[arg_to_print], |
| 184 | 184 | fmt[0..0], |
| 185 | 185 | options, |
| 186 | out_stream, | |
| 186 | writer, | |
| 187 | 187 | default_max_depth, |
| 188 | 188 | ); |
| 189 | 189 | |
| ... | ... | @@ -214,7 +214,7 @@ pub fn format( |
| 214 | 214 | args[arg_to_print], |
| 215 | 215 | fmt[specifier_start..i], |
| 216 | 216 | options, |
| 217 | out_stream, | |
| 217 | writer, | |
| 218 | 218 | default_max_depth, |
| 219 | 219 | ); |
| 220 | 220 | state = .Start; |
| ... | ... | @@ -259,7 +259,7 @@ pub fn format( |
| 259 | 259 | args[arg_to_print], |
| 260 | 260 | fmt[specifier_start..specifier_end], |
| 261 | 261 | options, |
| 262 | out_stream, | |
| 262 | writer, | |
| 263 | 263 | default_max_depth, |
| 264 | 264 | ); |
| 265 | 265 | state = .Start; |
| ... | ... | @@ -285,7 +285,7 @@ pub fn format( |
| 285 | 285 | args[arg_to_print], |
| 286 | 286 | fmt[specifier_start..specifier_end], |
| 287 | 287 | options, |
| 288 | out_stream, | |
| 288 | writer, | |
| 289 | 289 | default_max_depth, |
| 290 | 290 | ); |
| 291 | 291 | state = .Start; |
| ... | ... | @@ -306,7 +306,7 @@ pub fn format( |
| 306 | 306 | } |
| 307 | 307 | } |
| 308 | 308 | if (start_index < fmt.len) { |
| 309 | try out_stream.writeAll(fmt[start_index..]); | |
| 309 | try writer.writeAll(fmt[start_index..]); | |
| 310 | 310 | } |
| 311 | 311 | } |
| 312 | 312 | |
| ... | ... | @@ -314,140 +314,140 @@ pub fn formatType( |
| 314 | 314 | value: var, |
| 315 | 315 | comptime fmt: []const u8, |
| 316 | 316 | options: FormatOptions, |
| 317 | out_stream: var, | |
| 317 | writer: var, | |
| 318 | 318 | max_depth: usize, |
| 319 | ) @TypeOf(out_stream).Error!void { | |
| 319 | ) @TypeOf(writer).Error!void { | |
| 320 | 320 | 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); | |
| 324 | 324 | return; |
| 325 | 325 | } |
| 326 | 326 | |
| 327 | 327 | const T = @TypeOf(value); |
| 328 | 328 | if (comptime std.meta.trait.hasFn("format")(T)) { |
| 329 | return try value.format(fmt, options, out_stream); | |
| 329 | return try value.format(fmt, options, writer); | |
| 330 | 330 | } |
| 331 | 331 | |
| 332 | 332 | switch (@typeInfo(T)) { |
| 333 | 333 | .ComptimeInt, .Int, .ComptimeFloat, .Float => { |
| 334 | return formatValue(value, fmt, options, out_stream); | |
| 334 | return formatValue(value, fmt, options, writer); | |
| 335 | 335 | }, |
| 336 | 336 | .Void => { |
| 337 | return formatBuf("void", options, out_stream); | |
| 337 | return formatBuf("void", options, writer); | |
| 338 | 338 | }, |
| 339 | 339 | .Bool => { |
| 340 | return formatBuf(if (value) "true" else "false", options, out_stream); | |
| 340 | return formatBuf(if (value) "true" else "false", options, writer); | |
| 341 | 341 | }, |
| 342 | 342 | .Optional => { |
| 343 | 343 | if (value) |payload| { |
| 344 | return formatType(payload, fmt, options, out_stream, max_depth); | |
| 344 | return formatType(payload, fmt, options, writer, max_depth); | |
| 345 | 345 | } else { |
| 346 | return formatBuf("null", options, out_stream); | |
| 346 | return formatBuf("null", options, writer); | |
| 347 | 347 | } |
| 348 | 348 | }, |
| 349 | 349 | .ErrorUnion => { |
| 350 | 350 | if (value) |payload| { |
| 351 | return formatType(payload, fmt, options, out_stream, max_depth); | |
| 351 | return formatType(payload, fmt, options, writer, max_depth); | |
| 352 | 352 | } else |err| { |
| 353 | return formatType(err, fmt, options, out_stream, max_depth); | |
| 353 | return formatType(err, fmt, options, writer, max_depth); | |
| 354 | 354 | } |
| 355 | 355 | }, |
| 356 | 356 | .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)); | |
| 359 | 359 | }, |
| 360 | 360 | .Enum => |enumInfo| { |
| 361 | try out_stream.writeAll(@typeName(T)); | |
| 361 | try writer.writeAll(@typeName(T)); | |
| 362 | 362 | 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)); | |
| 365 | 365 | return; |
| 366 | 366 | } |
| 367 | 367 | |
| 368 | 368 | // Use @tagName only if value is one of known fields |
| 369 | 369 | inline for (enumInfo.fields) |enumField| { |
| 370 | 370 | 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)); | |
| 373 | 373 | return; |
| 374 | 374 | } |
| 375 | 375 | } |
| 376 | 376 | |
| 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(")"); | |
| 380 | 380 | }, |
| 381 | 381 | .Union => { |
| 382 | try out_stream.writeAll(@typeName(T)); | |
| 382 | try writer.writeAll(@typeName(T)); | |
| 383 | 383 | if (max_depth == 0) { |
| 384 | return out_stream.writeAll("{ ... }"); | |
| 384 | return writer.writeAll("{ ... }"); | |
| 385 | 385 | } |
| 386 | 386 | const info = @typeInfo(T).Union; |
| 387 | 387 | 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(" = "); | |
| 391 | 391 | inline for (info.fields) |u_field| { |
| 392 | 392 | if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { |
| 393 | try formatType(@field(value, u_field.name), fmt, options, out_stream, max_depth - 1); | |
| 393 | try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1); | |
| 394 | 394 | } |
| 395 | 395 | } |
| 396 | try out_stream.writeAll(" }"); | |
| 396 | try writer.writeAll(" }"); | |
| 397 | 397 | } else { |
| 398 | try format(out_stream, "@{x}", .{@ptrToInt(&value)}); | |
| 398 | try format(writer, "@{x}", .{@ptrToInt(&value)}); | |
| 399 | 399 | } |
| 400 | 400 | }, |
| 401 | 401 | .Struct => |StructT| { |
| 402 | try out_stream.writeAll(@typeName(T)); | |
| 402 | try writer.writeAll(@typeName(T)); | |
| 403 | 403 | if (max_depth == 0) { |
| 404 | return out_stream.writeAll("{ ... }"); | |
| 404 | return writer.writeAll("{ ... }"); | |
| 405 | 405 | } |
| 406 | try out_stream.writeAll("{"); | |
| 406 | try writer.writeAll("{"); | |
| 407 | 407 | inline for (StructT.fields) |f, i| { |
| 408 | 408 | if (i == 0) { |
| 409 | try out_stream.writeAll(" ."); | |
| 409 | try writer.writeAll(" ."); | |
| 410 | 410 | } else { |
| 411 | try out_stream.writeAll(", ."); | |
| 411 | try writer.writeAll(", ."); | |
| 412 | 412 | } |
| 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); | |
| 416 | 416 | } |
| 417 | try out_stream.writeAll(" }"); | |
| 417 | try writer.writeAll(" }"); | |
| 418 | 418 | }, |
| 419 | 419 | .Pointer => |ptr_info| switch (ptr_info.size) { |
| 420 | 420 | .One => switch (@typeInfo(ptr_info.child)) { |
| 421 | 421 | .Array => |info| { |
| 422 | 422 | if (info.child == u8) { |
| 423 | return formatText(value, fmt, options, out_stream); | |
| 423 | return formatText(value, fmt, options, writer); | |
| 424 | 424 | } |
| 425 | return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }); | |
| 425 | return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }); | |
| 426 | 426 | }, |
| 427 | 427 | .Enum, .Union, .Struct => { |
| 428 | return formatType(value.*, fmt, options, out_stream, max_depth); | |
| 428 | return formatType(value.*, fmt, options, writer, max_depth); | |
| 429 | 429 | }, |
| 430 | else => return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }), | |
| 430 | else => return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }), | |
| 431 | 431 | }, |
| 432 | 432 | .Many, .C => { |
| 433 | 433 | if (ptr_info.sentinel) |sentinel| { |
| 434 | return formatType(mem.span(value), fmt, options, out_stream, max_depth); | |
| 434 | return formatType(mem.span(value), fmt, options, writer, max_depth); | |
| 435 | 435 | } |
| 436 | 436 | if (ptr_info.child == u8) { |
| 437 | 437 | if (fmt.len > 0 and fmt[0] == 's') { |
| 438 | return formatText(mem.span(value), fmt, options, out_stream); | |
| 438 | return formatText(mem.span(value), fmt, options, writer); | |
| 439 | 439 | } |
| 440 | 440 | } |
| 441 | return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }); | |
| 441 | return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }); | |
| 442 | 442 | }, |
| 443 | 443 | .Slice => { |
| 444 | 444 | if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) { |
| 445 | return formatText(value, fmt, options, out_stream); | |
| 445 | return formatText(value, fmt, options, writer); | |
| 446 | 446 | } |
| 447 | 447 | if (ptr_info.child == u8) { |
| 448 | return formatText(value, fmt, options, out_stream); | |
| 448 | return formatText(value, fmt, options, writer); | |
| 449 | 449 | } |
| 450 | return format(out_stream, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) }); | |
| 450 | return format(writer, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) }); | |
| 451 | 451 | }, |
| 452 | 452 | }, |
| 453 | 453 | .Array => |info| { |
| ... | ... | @@ -462,27 +462,27 @@ pub fn formatType( |
| 462 | 462 | .sentinel = null, |
| 463 | 463 | }, |
| 464 | 464 | }); |
| 465 | return formatType(@as(Slice, &value), fmt, options, out_stream, max_depth); | |
| 465 | return formatType(@as(Slice, &value), fmt, options, writer, max_depth); | |
| 466 | 466 | }, |
| 467 | 467 | .Vector => { |
| 468 | 468 | const len = @typeInfo(T).Vector.len; |
| 469 | try out_stream.writeAll("{ "); | |
| 469 | try writer.writeAll("{ "); | |
| 470 | 470 | var i: usize = 0; |
| 471 | 471 | while (i < len) : (i += 1) { |
| 472 | try formatValue(value[i], fmt, options, out_stream); | |
| 472 | try formatValue(value[i], fmt, options, writer); | |
| 473 | 473 | if (i < len - 1) { |
| 474 | try out_stream.writeAll(", "); | |
| 474 | try writer.writeAll(", "); | |
| 475 | 475 | } |
| 476 | 476 | } |
| 477 | try out_stream.writeAll(" }"); | |
| 477 | try writer.writeAll(" }"); | |
| 478 | 478 | }, |
| 479 | 479 | .Fn => { |
| 480 | return format(out_stream, "{}@{x}", .{ @typeName(T), @ptrToInt(value) }); | |
| 480 | return format(writer, "{}@{x}", .{ @typeName(T), @ptrToInt(value) }); | |
| 481 | 481 | }, |
| 482 | .Type => return out_stream.writeAll(@typeName(T)), | |
| 482 | .Type => return writer.writeAll(@typeName(T)), | |
| 483 | 483 | .EnumLiteral => { |
| 484 | 484 | const buffer = [_]u8{'.'} ++ @tagName(value); |
| 485 | return formatType(buffer, fmt, options, out_stream, max_depth); | |
| 485 | return formatType(buffer, fmt, options, writer, max_depth); | |
| 486 | 486 | }, |
| 487 | 487 | else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"), |
| 488 | 488 | } |
| ... | ... | @@ -492,19 +492,19 @@ fn formatValue( |
| 492 | 492 | value: var, |
| 493 | 493 | comptime fmt: []const u8, |
| 494 | 494 | options: FormatOptions, |
| 495 | out_stream: var, | |
| 495 | writer: var, | |
| 496 | 496 | ) !void { |
| 497 | 497 | if (comptime std.mem.eql(u8, fmt, "B")) { |
| 498 | return formatBytes(value, options, 1000, out_stream); | |
| 498 | return formatBytes(value, options, 1000, writer); | |
| 499 | 499 | } else if (comptime std.mem.eql(u8, fmt, "Bi")) { |
| 500 | return formatBytes(value, options, 1024, out_stream); | |
| 500 | return formatBytes(value, options, 1024, writer); | |
| 501 | 501 | } |
| 502 | 502 | |
| 503 | 503 | const T = @TypeOf(value); |
| 504 | 504 | 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), | |
| 508 | 508 | else => comptime unreachable, |
| 509 | 509 | } |
| 510 | 510 | } |
| ... | ... | @@ -513,7 +513,7 @@ pub fn formatIntValue( |
| 513 | 513 | value: var, |
| 514 | 514 | comptime fmt: []const u8, |
| 515 | 515 | options: FormatOptions, |
| 516 | out_stream: var, | |
| 516 | writer: var, | |
| 517 | 517 | ) !void { |
| 518 | 518 | comptime var radix = 10; |
| 519 | 519 | comptime var uppercase = false; |
| ... | ... | @@ -529,7 +529,7 @@ pub fn formatIntValue( |
| 529 | 529 | uppercase = false; |
| 530 | 530 | } else if (comptime std.mem.eql(u8, fmt, "c")) { |
| 531 | 531 | if (@TypeOf(int_value).bit_count <= 8) { |
| 532 | return formatAsciiChar(@as(u8, int_value), options, out_stream); | |
| 532 | return formatAsciiChar(@as(u8, int_value), options, writer); | |
| 533 | 533 | } else { |
| 534 | 534 | @compileError("Cannot print integer that is larger than 8 bits as a ascii"); |
| 535 | 535 | } |
| ... | ... | @@ -546,19 +546,19 @@ pub fn formatIntValue( |
| 546 | 546 | @compileError("Unknown format string: '" ++ fmt ++ "'"); |
| 547 | 547 | } |
| 548 | 548 | |
| 549 | return formatInt(int_value, radix, uppercase, options, out_stream); | |
| 549 | return formatInt(int_value, radix, uppercase, options, writer); | |
| 550 | 550 | } |
| 551 | 551 | |
| 552 | 552 | fn formatFloatValue( |
| 553 | 553 | value: var, |
| 554 | 554 | comptime fmt: []const u8, |
| 555 | 555 | options: FormatOptions, |
| 556 | out_stream: var, | |
| 556 | writer: var, | |
| 557 | 557 | ) !void { |
| 558 | 558 | if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) { |
| 559 | return formatFloatScientific(value, options, out_stream); | |
| 559 | return formatFloatScientific(value, options, writer); | |
| 560 | 560 | } else if (comptime std.mem.eql(u8, fmt, "d")) { |
| 561 | return formatFloatDecimal(value, options, out_stream); | |
| 561 | return formatFloatDecimal(value, options, writer); | |
| 562 | 562 | } else { |
| 563 | 563 | @compileError("Unknown format string: '" ++ fmt ++ "'"); |
| 564 | 564 | } |
| ... | ... | @@ -568,13 +568,13 @@ pub fn formatText( |
| 568 | 568 | bytes: []const u8, |
| 569 | 569 | comptime fmt: []const u8, |
| 570 | 570 | options: FormatOptions, |
| 571 | out_stream: var, | |
| 571 | writer: var, | |
| 572 | 572 | ) !void { |
| 573 | 573 | if (comptime std.mem.eql(u8, fmt, "s") or (fmt.len == 0)) { |
| 574 | return formatBuf(bytes, options, out_stream); | |
| 574 | return formatBuf(bytes, options, writer); | |
| 575 | 575 | } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) { |
| 576 | 576 | for (bytes) |c| { |
| 577 | try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, out_stream); | |
| 577 | try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, writer); | |
| 578 | 578 | } |
| 579 | 579 | return; |
| 580 | 580 | } else { |
| ... | ... | @@ -585,38 +585,38 @@ pub fn formatText( |
| 585 | 585 | pub fn formatAsciiChar( |
| 586 | 586 | c: u8, |
| 587 | 587 | options: FormatOptions, |
| 588 | out_stream: var, | |
| 588 | writer: var, | |
| 589 | 589 | ) !void { |
| 590 | return out_stream.writeAll(@as(*const [1]u8, &c)); | |
| 590 | return writer.writeAll(@as(*const [1]u8, &c)); | |
| 591 | 591 | } |
| 592 | 592 | |
| 593 | 593 | pub fn formatBuf( |
| 594 | 594 | buf: []const u8, |
| 595 | 595 | options: FormatOptions, |
| 596 | out_stream: var, | |
| 596 | writer: var, | |
| 597 | 597 | ) !void { |
| 598 | 598 | const width = options.width orelse buf.len; |
| 599 | 599 | var padding = if (width > buf.len) (width - buf.len) else 0; |
| 600 | 600 | const pad_byte = [1]u8{options.fill}; |
| 601 | 601 | switch (options.alignment) { |
| 602 | 602 | .Left => { |
| 603 | try out_stream.writeAll(buf); | |
| 603 | try writer.writeAll(buf); | |
| 604 | 604 | while (padding > 0) : (padding -= 1) { |
| 605 | try out_stream.writeAll(&pad_byte); | |
| 605 | try writer.writeAll(&pad_byte); | |
| 606 | 606 | } |
| 607 | 607 | }, |
| 608 | 608 | .Center => { |
| 609 | 609 | const padl = padding / 2; |
| 610 | 610 | 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); | |
| 614 | 614 | }, |
| 615 | 615 | .Right => { |
| 616 | 616 | while (padding > 0) : (padding -= 1) { |
| 617 | try out_stream.writeAll(&pad_byte); | |
| 617 | try writer.writeAll(&pad_byte); | |
| 618 | 618 | } |
| 619 | try out_stream.writeAll(buf); | |
| 619 | try writer.writeAll(buf); | |
| 620 | 620 | }, |
| 621 | 621 | } |
| 622 | 622 | } |
| ... | ... | @@ -627,38 +627,38 @@ pub fn formatBuf( |
| 627 | 627 | pub fn formatFloatScientific( |
| 628 | 628 | value: var, |
| 629 | 629 | options: FormatOptions, |
| 630 | out_stream: var, | |
| 630 | writer: var, | |
| 631 | 631 | ) !void { |
| 632 | 632 | var x = @floatCast(f64, value); |
| 633 | 633 | |
| 634 | 634 | // Errol doesn't handle these special cases. |
| 635 | 635 | if (math.signbit(x)) { |
| 636 | try out_stream.writeAll("-"); | |
| 636 | try writer.writeAll("-"); | |
| 637 | 637 | x = -x; |
| 638 | 638 | } |
| 639 | 639 | |
| 640 | 640 | if (math.isNan(x)) { |
| 641 | return out_stream.writeAll("nan"); | |
| 641 | return writer.writeAll("nan"); | |
| 642 | 642 | } |
| 643 | 643 | if (math.isPositiveInf(x)) { |
| 644 | return out_stream.writeAll("inf"); | |
| 644 | return writer.writeAll("inf"); | |
| 645 | 645 | } |
| 646 | 646 | if (x == 0.0) { |
| 647 | try out_stream.writeAll("0"); | |
| 647 | try writer.writeAll("0"); | |
| 648 | 648 | |
| 649 | 649 | if (options.precision) |precision| { |
| 650 | 650 | if (precision != 0) { |
| 651 | try out_stream.writeAll("."); | |
| 651 | try writer.writeAll("."); | |
| 652 | 652 | var i: usize = 0; |
| 653 | 653 | while (i < precision) : (i += 1) { |
| 654 | try out_stream.writeAll("0"); | |
| 654 | try writer.writeAll("0"); | |
| 655 | 655 | } |
| 656 | 656 | } |
| 657 | 657 | } else { |
| 658 | try out_stream.writeAll(".0"); | |
| 658 | try writer.writeAll(".0"); | |
| 659 | 659 | } |
| 660 | 660 | |
| 661 | try out_stream.writeAll("e+00"); | |
| 661 | try writer.writeAll("e+00"); | |
| 662 | 662 | return; |
| 663 | 663 | } |
| 664 | 664 | |
| ... | ... | @@ -668,50 +668,50 @@ pub fn formatFloatScientific( |
| 668 | 668 | if (options.precision) |precision| { |
| 669 | 669 | errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific); |
| 670 | 670 | |
| 671 | try out_stream.writeAll(float_decimal.digits[0..1]); | |
| 671 | try writer.writeAll(float_decimal.digits[0..1]); | |
| 672 | 672 | |
| 673 | 673 | // {e0} case prints no `.` |
| 674 | 674 | if (precision != 0) { |
| 675 | try out_stream.writeAll("."); | |
| 675 | try writer.writeAll("."); | |
| 676 | 676 | |
| 677 | 677 | var printed: usize = 0; |
| 678 | 678 | if (float_decimal.digits.len > 1) { |
| 679 | 679 | const num_digits = math.min(float_decimal.digits.len, precision + 1); |
| 680 | try out_stream.writeAll(float_decimal.digits[1..num_digits]); | |
| 680 | try writer.writeAll(float_decimal.digits[1..num_digits]); | |
| 681 | 681 | printed += num_digits - 1; |
| 682 | 682 | } |
| 683 | 683 | |
| 684 | 684 | while (printed < precision) : (printed += 1) { |
| 685 | try out_stream.writeAll("0"); | |
| 685 | try writer.writeAll("0"); | |
| 686 | 686 | } |
| 687 | 687 | } |
| 688 | 688 | } 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("."); | |
| 691 | 691 | if (float_decimal.digits.len > 1) { |
| 692 | 692 | const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len; |
| 693 | 693 | |
| 694 | try out_stream.writeAll(float_decimal.digits[1..num_digits]); | |
| 694 | try writer.writeAll(float_decimal.digits[1..num_digits]); | |
| 695 | 695 | } else { |
| 696 | try out_stream.writeAll("0"); | |
| 696 | try writer.writeAll("0"); | |
| 697 | 697 | } |
| 698 | 698 | } |
| 699 | 699 | |
| 700 | try out_stream.writeAll("e"); | |
| 700 | try writer.writeAll("e"); | |
| 701 | 701 | const exp = float_decimal.exp - 1; |
| 702 | 702 | |
| 703 | 703 | if (exp >= 0) { |
| 704 | try out_stream.writeAll("+"); | |
| 704 | try writer.writeAll("+"); | |
| 705 | 705 | if (exp > -10 and exp < 10) { |
| 706 | try out_stream.writeAll("0"); | |
| 706 | try writer.writeAll("0"); | |
| 707 | 707 | } |
| 708 | try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, out_stream); | |
| 708 | try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, writer); | |
| 709 | 709 | } else { |
| 710 | try out_stream.writeAll("-"); | |
| 710 | try writer.writeAll("-"); | |
| 711 | 711 | if (exp > -10 and exp < 10) { |
| 712 | try out_stream.writeAll("0"); | |
| 712 | try writer.writeAll("0"); | |
| 713 | 713 | } |
| 714 | try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, out_stream); | |
| 714 | try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, writer); | |
| 715 | 715 | } |
| 716 | 716 | } |
| 717 | 717 | |
| ... | ... | @@ -720,34 +720,34 @@ pub fn formatFloatScientific( |
| 720 | 720 | pub fn formatFloatDecimal( |
| 721 | 721 | value: var, |
| 722 | 722 | options: FormatOptions, |
| 723 | out_stream: var, | |
| 723 | writer: var, | |
| 724 | 724 | ) !void { |
| 725 | 725 | var x = @as(f64, value); |
| 726 | 726 | |
| 727 | 727 | // Errol doesn't handle these special cases. |
| 728 | 728 | if (math.signbit(x)) { |
| 729 | try out_stream.writeAll("-"); | |
| 729 | try writer.writeAll("-"); | |
| 730 | 730 | x = -x; |
| 731 | 731 | } |
| 732 | 732 | |
| 733 | 733 | if (math.isNan(x)) { |
| 734 | return out_stream.writeAll("nan"); | |
| 734 | return writer.writeAll("nan"); | |
| 735 | 735 | } |
| 736 | 736 | if (math.isPositiveInf(x)) { |
| 737 | return out_stream.writeAll("inf"); | |
| 737 | return writer.writeAll("inf"); | |
| 738 | 738 | } |
| 739 | 739 | if (x == 0.0) { |
| 740 | try out_stream.writeAll("0"); | |
| 740 | try writer.writeAll("0"); | |
| 741 | 741 | |
| 742 | 742 | if (options.precision) |precision| { |
| 743 | 743 | if (precision != 0) { |
| 744 | try out_stream.writeAll("."); | |
| 744 | try writer.writeAll("."); | |
| 745 | 745 | var i: usize = 0; |
| 746 | 746 | while (i < precision) : (i += 1) { |
| 747 | try out_stream.writeAll("0"); | |
| 747 | try writer.writeAll("0"); | |
| 748 | 748 | } |
| 749 | 749 | } else { |
| 750 | try out_stream.writeAll(".0"); | |
| 750 | try writer.writeAll(".0"); | |
| 751 | 751 | } |
| 752 | 752 | } |
| 753 | 753 | |
| ... | ... | @@ -769,14 +769,14 @@ pub fn formatFloatDecimal( |
| 769 | 769 | |
| 770 | 770 | if (num_digits_whole > 0) { |
| 771 | 771 | // We may have to zero pad, for instance 1e4 requires zero padding. |
| 772 | try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]); | |
| 772 | try writer.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]); | |
| 773 | 773 | |
| 774 | 774 | var i = num_digits_whole_no_pad; |
| 775 | 775 | while (i < num_digits_whole) : (i += 1) { |
| 776 | try out_stream.writeAll("0"); | |
| 776 | try writer.writeAll("0"); | |
| 777 | 777 | } |
| 778 | 778 | } else { |
| 779 | try out_stream.writeAll("0"); | |
| 779 | try writer.writeAll("0"); | |
| 780 | 780 | } |
| 781 | 781 | |
| 782 | 782 | // {.0} special case doesn't want a trailing '.' |
| ... | ... | @@ -784,7 +784,7 @@ pub fn formatFloatDecimal( |
| 784 | 784 | return; |
| 785 | 785 | } |
| 786 | 786 | |
| 787 | try out_stream.writeAll("."); | |
| 787 | try writer.writeAll("."); | |
| 788 | 788 | |
| 789 | 789 | // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's. |
| 790 | 790 | var printed: usize = 0; |
| ... | ... | @@ -796,7 +796,7 @@ pub fn formatFloatDecimal( |
| 796 | 796 | |
| 797 | 797 | var i: usize = 0; |
| 798 | 798 | while (i < zeros_to_print) : (i += 1) { |
| 799 | try out_stream.writeAll("0"); | |
| 799 | try writer.writeAll("0"); | |
| 800 | 800 | printed += 1; |
| 801 | 801 | } |
| 802 | 802 | |
| ... | ... | @@ -808,14 +808,14 @@ pub fn formatFloatDecimal( |
| 808 | 808 | // Remaining fractional portion, zero-padding if insufficient. |
| 809 | 809 | assert(precision >= printed); |
| 810 | 810 | if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) { |
| 811 | try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]); | |
| 811 | try writer.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]); | |
| 812 | 812 | return; |
| 813 | 813 | } else { |
| 814 | try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]); | |
| 814 | try writer.writeAll(float_decimal.digits[num_digits_whole_no_pad..]); | |
| 815 | 815 | printed += float_decimal.digits.len - num_digits_whole_no_pad; |
| 816 | 816 | |
| 817 | 817 | while (printed < precision) : (printed += 1) { |
| 818 | try out_stream.writeAll("0"); | |
| 818 | try writer.writeAll("0"); | |
| 819 | 819 | } |
| 820 | 820 | } |
| 821 | 821 | } else { |
| ... | ... | @@ -827,14 +827,14 @@ pub fn formatFloatDecimal( |
| 827 | 827 | |
| 828 | 828 | if (num_digits_whole > 0) { |
| 829 | 829 | // We may have to zero pad, for instance 1e4 requires zero padding. |
| 830 | try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]); | |
| 830 | try writer.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]); | |
| 831 | 831 | |
| 832 | 832 | var i = num_digits_whole_no_pad; |
| 833 | 833 | while (i < num_digits_whole) : (i += 1) { |
| 834 | try out_stream.writeAll("0"); | |
| 834 | try writer.writeAll("0"); | |
| 835 | 835 | } |
| 836 | 836 | } else { |
| 837 | try out_stream.writeAll("0"); | |
| 837 | try writer.writeAll("0"); | |
| 838 | 838 | } |
| 839 | 839 | |
| 840 | 840 | // Omit `.` if no fractional portion |
| ... | ... | @@ -842,7 +842,7 @@ pub fn formatFloatDecimal( |
| 842 | 842 | return; |
| 843 | 843 | } |
| 844 | 844 | |
| 845 | try out_stream.writeAll("."); | |
| 845 | try writer.writeAll("."); | |
| 846 | 846 | |
| 847 | 847 | // Zero-fill until we reach significant digits or run out of precision. |
| 848 | 848 | if (float_decimal.exp < 0) { |
| ... | ... | @@ -850,11 +850,11 @@ pub fn formatFloatDecimal( |
| 850 | 850 | |
| 851 | 851 | var i: usize = 0; |
| 852 | 852 | while (i < zero_digit_count) : (i += 1) { |
| 853 | try out_stream.writeAll("0"); | |
| 853 | try writer.writeAll("0"); | |
| 854 | 854 | } |
| 855 | 855 | } |
| 856 | 856 | |
| 857 | try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]); | |
| 857 | try writer.writeAll(float_decimal.digits[num_digits_whole_no_pad..]); | |
| 858 | 858 | } |
| 859 | 859 | } |
| 860 | 860 | |
| ... | ... | @@ -862,10 +862,10 @@ pub fn formatBytes( |
| 862 | 862 | value: var, |
| 863 | 863 | options: FormatOptions, |
| 864 | 864 | comptime radix: usize, |
| 865 | out_stream: var, | |
| 865 | writer: var, | |
| 866 | 866 | ) !void { |
| 867 | 867 | if (value == 0) { |
| 868 | return out_stream.writeAll("0B"); | |
| 868 | return writer.writeAll("0B"); | |
| 869 | 869 | } |
| 870 | 870 | |
| 871 | 871 | const is_float = comptime std.meta.trait.is(.Float)(@TypeOf(value)); |
| ... | ... | @@ -885,10 +885,10 @@ pub fn formatBytes( |
| 885 | 885 | else => unreachable, |
| 886 | 886 | }; |
| 887 | 887 | |
| 888 | try formatFloatDecimal(new_value, options, out_stream); | |
| 888 | try formatFloatDecimal(new_value, options, writer); | |
| 889 | 889 | |
| 890 | 890 | if (suffix == ' ') { |
| 891 | return out_stream.writeAll("B"); | |
| 891 | return writer.writeAll("B"); | |
| 892 | 892 | } |
| 893 | 893 | |
| 894 | 894 | const buf = switch (radix) { |
| ... | ... | @@ -896,7 +896,7 @@ pub fn formatBytes( |
| 896 | 896 | 1024 => &[_]u8{ suffix, 'i', 'B' }, |
| 897 | 897 | else => unreachable, |
| 898 | 898 | }; |
| 899 | return out_stream.writeAll(buf); | |
| 899 | return writer.writeAll(buf); | |
| 900 | 900 | } |
| 901 | 901 | |
| 902 | 902 | pub fn formatInt( |
| ... | ... | @@ -904,7 +904,7 @@ pub fn formatInt( |
| 904 | 904 | base: u8, |
| 905 | 905 | uppercase: bool, |
| 906 | 906 | options: FormatOptions, |
| 907 | out_stream: var, | |
| 907 | writer: var, | |
| 908 | 908 | ) !void { |
| 909 | 909 | const int_value = if (@TypeOf(value) == comptime_int) blk: { |
| 910 | 910 | const Int = math.IntFittingRange(value, value); |
| ... | ... | @@ -913,9 +913,9 @@ pub fn formatInt( |
| 913 | 913 | value; |
| 914 | 914 | |
| 915 | 915 | if (@TypeOf(int_value).is_signed) { |
| 916 | return formatIntSigned(int_value, base, uppercase, options, out_stream); | |
| 916 | return formatIntSigned(int_value, base, uppercase, options, writer); | |
| 917 | 917 | } else { |
| 918 | return formatIntUnsigned(int_value, base, uppercase, options, out_stream); | |
| 918 | return formatIntUnsigned(int_value, base, uppercase, options, writer); | |
| 919 | 919 | } |
| 920 | 920 | } |
| 921 | 921 | |
| ... | ... | @@ -924,7 +924,7 @@ fn formatIntSigned( |
| 924 | 924 | base: u8, |
| 925 | 925 | uppercase: bool, |
| 926 | 926 | options: FormatOptions, |
| 927 | out_stream: var, | |
| 927 | writer: var, | |
| 928 | 928 | ) !void { |
| 929 | 929 | const new_options = FormatOptions{ |
| 930 | 930 | .width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null, |
| ... | ... | @@ -934,15 +934,15 @@ fn formatIntSigned( |
| 934 | 934 | const bit_count = @typeInfo(@TypeOf(value)).Int.bits; |
| 935 | 935 | const Uint = std.meta.Int(false, bit_count); |
| 936 | 936 | if (value < 0) { |
| 937 | try out_stream.writeAll("-"); | |
| 937 | try writer.writeAll("-"); | |
| 938 | 938 | const new_value = math.absCast(value); |
| 939 | return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream); | |
| 939 | return formatIntUnsigned(new_value, base, uppercase, new_options, writer); | |
| 940 | 940 | } else if (options.width == null or options.width.? == 0) { |
| 941 | return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, out_stream); | |
| 941 | return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, writer); | |
| 942 | 942 | } else { |
| 943 | try out_stream.writeAll("+"); | |
| 943 | try writer.writeAll("+"); | |
| 944 | 944 | const new_value = @intCast(Uint, value); |
| 945 | return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream); | |
| 945 | return formatIntUnsigned(new_value, base, uppercase, new_options, writer); | |
| 946 | 946 | } |
| 947 | 947 | } |
| 948 | 948 | |
| ... | ... | @@ -951,7 +951,7 @@ fn formatIntUnsigned( |
| 951 | 951 | base: u8, |
| 952 | 952 | uppercase: bool, |
| 953 | 953 | options: FormatOptions, |
| 954 | out_stream: var, | |
| 954 | writer: var, | |
| 955 | 955 | ) !void { |
| 956 | 956 | assert(base >= 2); |
| 957 | 957 | var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined; |
| ... | ... | @@ -976,22 +976,22 @@ fn formatIntUnsigned( |
| 976 | 976 | const zero_byte: u8 = options.fill; |
| 977 | 977 | var leftover_padding = padding - index; |
| 978 | 978 | while (true) { |
| 979 | try out_stream.writeAll(@as(*const [1]u8, &zero_byte)[0..]); | |
| 979 | try writer.writeAll(@as(*const [1]u8, &zero_byte)[0..]); | |
| 980 | 980 | leftover_padding -= 1; |
| 981 | 981 | if (leftover_padding == 0) break; |
| 982 | 982 | } |
| 983 | 983 | mem.set(u8, buf[0..index], options.fill); |
| 984 | return out_stream.writeAll(&buf); | |
| 984 | return writer.writeAll(&buf); | |
| 985 | 985 | } else { |
| 986 | 986 | const padded_buf = buf[index - padding ..]; |
| 987 | 987 | mem.set(u8, padded_buf[0..padding], options.fill); |
| 988 | return out_stream.writeAll(padded_buf); | |
| 988 | return writer.writeAll(padded_buf); | |
| 989 | 989 | } |
| 990 | 990 | } |
| 991 | 991 | |
| 992 | 992 | pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize { |
| 993 | 993 | var fbs = std.io.fixedBufferStream(out_buf); |
| 994 | formatInt(value, base, uppercase, options, fbs.outStream()) catch unreachable; | |
| 994 | formatInt(value, base, uppercase, options, fbs.writer()) catch unreachable; | |
| 995 | 995 | return fbs.pos; |
| 996 | 996 | } |
| 997 | 997 | |
| ... | ... | @@ -1098,15 +1098,15 @@ pub const BufPrintError = error{ |
| 1098 | 1098 | }; |
| 1099 | 1099 | pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 { |
| 1100 | 1100 | var fbs = std.io.fixedBufferStream(buf); |
| 1101 | try format(fbs.outStream(), fmt, args); | |
| 1101 | try format(fbs.writer(), fmt, args); | |
| 1102 | 1102 | return fbs.getWritten(); |
| 1103 | 1103 | } |
| 1104 | 1104 | |
| 1105 | 1105 | // Count the characters needed for format. Useful for preallocating memory |
| 1106 | 1106 | pub 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; | |
| 1110 | 1110 | } |
| 1111 | 1111 | |
| 1112 | 1112 | pub const AllocPrintError = error{OutOfMemory}; |
| ... | ... | @@ -1215,15 +1215,15 @@ test "buffer" { |
| 1215 | 1215 | { |
| 1216 | 1216 | var buf1: [32]u8 = undefined; |
| 1217 | 1217 | var fbs = std.io.fixedBufferStream(&buf1); |
| 1218 | try formatType(1234, "", FormatOptions{}, fbs.outStream(), default_max_depth); | |
| 1218 | try formatType(1234, "", FormatOptions{}, fbs.writer(), default_max_depth); | |
| 1219 | 1219 | std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234")); |
| 1220 | 1220 | |
| 1221 | 1221 | fbs.reset(); |
| 1222 | try formatType('a', "c", FormatOptions{}, fbs.outStream(), default_max_depth); | |
| 1222 | try formatType('a', "c", FormatOptions{}, fbs.writer(), default_max_depth); | |
| 1223 | 1223 | std.testing.expect(mem.eql(u8, fbs.getWritten(), "a")); |
| 1224 | 1224 | |
| 1225 | 1225 | fbs.reset(); |
| 1226 | try formatType(0b1100, "b", FormatOptions{}, fbs.outStream(), default_max_depth); | |
| 1226 | try formatType(0b1100, "b", FormatOptions{}, fbs.writer(), default_max_depth); | |
| 1227 | 1227 | std.testing.expect(mem.eql(u8, fbs.getWritten(), "1100")); |
| 1228 | 1228 | } |
| 1229 | 1229 | } |
| ... | ... | @@ -1413,12 +1413,12 @@ test "custom" { |
| 1413 | 1413 | self: SelfType, |
| 1414 | 1414 | comptime fmt: []const u8, |
| 1415 | 1415 | options: FormatOptions, |
| 1416 | out_stream: var, | |
| 1416 | writer: var, | |
| 1417 | 1417 | ) !void { |
| 1418 | 1418 | if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) { |
| 1419 | return std.fmt.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y }); | |
| 1419 | return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y }); | |
| 1420 | 1420 | } else if (comptime std.mem.eql(u8, fmt, "d")) { |
| 1421 | return std.fmt.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y }); | |
| 1421 | return std.fmt.format(writer, "{d:.3}x{d:.3}", .{ self.x, self.y }); | |
| 1422 | 1422 | } else { |
| 1423 | 1423 | @compileError("Unknown format character: '" ++ fmt ++ "'"); |
| 1424 | 1424 | } |
| ... | ... | @@ -1604,7 +1604,7 @@ test "formatIntValue with comptime_int" { |
| 1604 | 1604 | |
| 1605 | 1605 | var buf: [20]u8 = undefined; |
| 1606 | 1606 | var fbs = std.io.fixedBufferStream(&buf); |
| 1607 | try formatIntValue(value, "", FormatOptions{}, fbs.outStream()); | |
| 1607 | try formatIntValue(value, "", FormatOptions{}, fbs.writer()); | |
| 1608 | 1608 | std.testing.expect(mem.eql(u8, fbs.getWritten(), "123456789123456789")); |
| 1609 | 1609 | } |
| 1610 | 1610 | |
| ... | ... | @@ -1613,7 +1613,7 @@ test "formatFloatValue with comptime_float" { |
| 1613 | 1613 | |
| 1614 | 1614 | var buf: [20]u8 = undefined; |
| 1615 | 1615 | var fbs = std.io.fixedBufferStream(&buf); |
| 1616 | try formatFloatValue(value, "", FormatOptions{}, fbs.outStream()); | |
| 1616 | try formatFloatValue(value, "", FormatOptions{}, fbs.writer()); | |
| 1617 | 1617 | std.testing.expect(mem.eql(u8, fbs.getWritten(), "1.0e+00")); |
| 1618 | 1618 | |
| 1619 | 1619 | try testFmt("1.0e+00", "{}", .{value}); |
| ... | ... | @@ -1630,10 +1630,10 @@ test "formatType max_depth" { |
| 1630 | 1630 | self: SelfType, |
| 1631 | 1631 | comptime fmt: []const u8, |
| 1632 | 1632 | options: FormatOptions, |
| 1633 | out_stream: var, | |
| 1633 | writer: var, | |
| 1634 | 1634 | ) !void { |
| 1635 | 1635 | if (fmt.len == 0) { |
| 1636 | return std.fmt.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y }); | |
| 1636 | return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y }); | |
| 1637 | 1637 | } else { |
| 1638 | 1638 | @compileError("Unknown format string: '" ++ fmt ++ "'"); |
| 1639 | 1639 | } |
| ... | ... | @@ -1669,19 +1669,19 @@ test "formatType max_depth" { |
| 1669 | 1669 | |
| 1670 | 1670 | var buf: [1000]u8 = undefined; |
| 1671 | 1671 | var fbs = std.io.fixedBufferStream(&buf); |
| 1672 | try formatType(inst, "", FormatOptions{}, fbs.outStream(), 0); | |
| 1672 | try formatType(inst, "", FormatOptions{}, fbs.writer(), 0); | |
| 1673 | 1673 | std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ ... }")); |
| 1674 | 1674 | |
| 1675 | 1675 | fbs.reset(); |
| 1676 | try formatType(inst, "", FormatOptions{}, fbs.outStream(), 1); | |
| 1676 | try formatType(inst, "", FormatOptions{}, fbs.writer(), 1); | |
| 1677 | 1677 | std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }")); |
| 1678 | 1678 | |
| 1679 | 1679 | fbs.reset(); |
| 1680 | try formatType(inst, "", FormatOptions{}, fbs.outStream(), 2); | |
| 1680 | try formatType(inst, "", FormatOptions{}, fbs.writer(), 2); | |
| 1681 | 1681 | std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }")); |
| 1682 | 1682 | |
| 1683 | 1683 | fbs.reset(); |
| 1684 | try formatType(inst, "", FormatOptions{}, fbs.outStream(), 3); | |
| 1684 | try formatType(inst, "", FormatOptions{}, fbs.writer(), 3); | |
| 1685 | 1685 | std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }")); |
| 1686 | 1686 | } |
| 1687 | 1687 |
lib/std/fs.zig+17-21| ... | ... | @@ -261,17 +261,7 @@ pub const Dir = struct { |
| 261 | 261 | name: []const u8, |
| 262 | 262 | kind: Kind, |
| 263 | 263 | |
| 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; | |
| 275 | 265 | }; |
| 276 | 266 | |
| 277 | 267 | const IteratorError = error{AccessDenied} || os.UnexpectedError; |
| ... | ... | @@ -1229,14 +1219,9 @@ pub const Dir = struct { |
| 1229 | 1219 | var file = try self.openFile(file_path, .{}); |
| 1230 | 1220 | defer file.close(); |
| 1231 | 1221 | |
| 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(); | |
| 1237 | 1223 | |
| 1238 | try file.inStream().readNoEof(buf); | |
| 1239 | return buf; | |
| 1224 | return file.readAllAllocOptions(allocator, stat_size, max_bytes, alignment, optional_sentinel); | |
| 1240 | 1225 | } |
| 1241 | 1226 | |
| 1242 | 1227 | pub const DeleteTreeError = error{ |
| ... | ... | @@ -1532,9 +1517,9 @@ pub const Dir = struct { |
| 1532 | 1517 | |
| 1533 | 1518 | var size: ?u64 = null; |
| 1534 | 1519 | 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; | |
| 1538 | 1523 | }; |
| 1539 | 1524 | |
| 1540 | 1525 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode }); |
| ... | ... | @@ -1560,6 +1545,17 @@ pub const Dir = struct { |
| 1560 | 1545 | return AtomicFile.init(dest_path, options.mode, self, false); |
| 1561 | 1546 | } |
| 1562 | 1547 | } |
| 1548 | ||
| 1549 | pub const Stat = File.Stat; | |
| 1550 | pub const StatError = File.StatError; | |
| 1551 | ||
| 1552 | pub fn stat(self: Dir) StatError!Stat { | |
| 1553 | const file: File = .{ | |
| 1554 | .handle = self.fd, | |
| 1555 | .capable_io_mode = .blocking, | |
| 1556 | }; | |
| 1557 | return file.stat(); | |
| 1558 | } | |
| 1563 | 1559 | }; |
| 1564 | 1560 | |
| 1565 | 1561 | /// Returns an handle to the current working directory. It is not opened with iteration capability. |
lib/std/fs/file.zig+64-2| ... | ... | @@ -29,6 +29,18 @@ pub const File = struct { |
| 29 | 29 | pub const Mode = os.mode_t; |
| 30 | 30 | pub const INode = os.ino_t; |
| 31 | 31 | |
| 32 | pub const Kind = enum { | |
| 33 | BlockDevice, | |
| 34 | CharacterDevice, | |
| 35 | Directory, | |
| 36 | NamedPipe, | |
| 37 | SymLink, | |
| 38 | File, | |
| 39 | UnixDomainSocket, | |
| 40 | Whiteout, | |
| 41 | Unknown, | |
| 42 | }; | |
| 43 | ||
| 32 | 44 | pub const default_mode = switch (builtin.os.tag) { |
| 33 | 45 | .windows => 0, |
| 34 | 46 | .wasi => 0, |
| ... | ... | @@ -209,7 +221,7 @@ pub const File = struct { |
| 209 | 221 | /// TODO: integrate with async I/O |
| 210 | 222 | pub fn mode(self: File) ModeError!Mode { |
| 211 | 223 | if (builtin.os.tag == .windows) { |
| 212 | return {}; | |
| 224 | return 0; | |
| 213 | 225 | } |
| 214 | 226 | return (try self.stat()).mode; |
| 215 | 227 | } |
| ... | ... | @@ -219,13 +231,14 @@ pub const File = struct { |
| 219 | 231 | /// unique across time, as some file systems may reuse an inode after its file has been deleted. |
| 220 | 232 | /// Some systems may change the inode of a file over time. |
| 221 | 233 | /// |
| 222 | /// On Linux, the inode _is_ structure that stores the metadata, and the inode _number_ is what | |
| 234 | /// On Linux, the inode is a structure that stores the metadata, and the inode _number_ is what | |
| 223 | 235 | /// you see here: the index number of the inode. |
| 224 | 236 | /// |
| 225 | 237 | /// The FileIndex on Windows is similar. It is a number for a file that is unique to each filesystem. |
| 226 | 238 | inode: INode, |
| 227 | 239 | size: u64, |
| 228 | 240 | mode: Mode, |
| 241 | kind: Kind, | |
| 229 | 242 | |
| 230 | 243 | /// Access time in nanoseconds, relative to UTC 1970-01-01. |
| 231 | 244 | atime: i128, |
| ... | ... | @@ -254,6 +267,7 @@ pub const File = struct { |
| 254 | 267 | .inode = info.InternalInformation.IndexNumber, |
| 255 | 268 | .size = @bitCast(u64, info.StandardInformation.EndOfFile), |
| 256 | 269 | .mode = 0, |
| 270 | .kind = if (info.StandardInformation.Directory == 0) .File else .Directory, | |
| 257 | 271 | .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime), |
| 258 | 272 | .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime), |
| 259 | 273 | .ctime = windows.fromSysTime(info.BasicInformation.CreationTime), |
| ... | ... | @@ -268,6 +282,27 @@ pub const File = struct { |
| 268 | 282 | .inode = st.ino, |
| 269 | 283 | .size = @bitCast(u64, st.size), |
| 270 | 284 | .mode = st.mode, |
| 285 | .kind = switch (builtin.os.tag) { | |
| 286 | .wasi => switch (st.filetype) { | |
| 287 | os.FILETYPE_BLOCK_DEVICE => Kind.BlockDevice, | |
| 288 | os.FILETYPE_CHARACTER_DEVICE => Kind.CharacterDevice, | |
| 289 | os.FILETYPE_DIRECTORY => Kind.Directory, | |
| 290 | os.FILETYPE_SYMBOLIC_LINK => Kind.SymLink, | |
| 291 | os.FILETYPE_REGULAR_FILE => Kind.File, | |
| 292 | os.FILETYPE_SOCKET_STREAM, os.FILETYPE_SOCKET_DGRAM => Kind.UnixDomainSocket, | |
| 293 | else => Kind.Unknown, | |
| 294 | }, | |
| 295 | else => switch (st.mode & os.S_IFMT) { | |
| 296 | os.S_IFBLK => Kind.BlockDevice, | |
| 297 | os.S_IFCHR => Kind.CharacterDevice, | |
| 298 | os.S_IFDIR => Kind.Directory, | |
| 299 | os.S_IFIFO => Kind.NamedPipe, | |
| 300 | os.S_IFLNK => Kind.SymLink, | |
| 301 | os.S_IFREG => Kind.File, | |
| 302 | os.S_IFSOCK => Kind.UnixDomainSocket, | |
| 303 | else => Kind.Unknown, | |
| 304 | }, | |
| 305 | }, | |
| 271 | 306 | .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec, |
| 272 | 307 | .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec, |
| 273 | 308 | .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec, |
| ... | ... | @@ -306,6 +341,33 @@ pub const File = struct { |
| 306 | 341 | try os.futimens(self.handle, &times); |
| 307 | 342 | } |
| 308 | 343 | |
| 344 | /// On success, caller owns returned buffer. | |
| 345 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | |
| 346 | pub fn readAllAlloc(self: File, allocator: *mem.Allocator, stat_size: u64, max_bytes: usize) ![]u8 { | |
| 347 | return self.readAllAllocOptions(allocator, stat_size, max_bytes, @alignOf(u8), null); | |
| 348 | } | |
| 349 | ||
| 350 | /// On success, caller owns returned buffer. | |
| 351 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | |
| 352 | /// Allows specifying alignment and a sentinel value. | |
| 353 | pub fn readAllAllocOptions( | |
| 354 | self: File, | |
| 355 | allocator: *mem.Allocator, | |
| 356 | stat_size: u64, | |
| 357 | max_bytes: usize, | |
| 358 | comptime alignment: u29, | |
| 359 | comptime optional_sentinel: ?u8, | |
| 360 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { | |
| 361 | const size = math.cast(usize, stat_size) catch math.maxInt(usize); | |
| 362 | if (size > max_bytes) return error.FileTooBig; | |
| 363 | ||
| 364 | const buf = try allocator.allocWithOptions(u8, size, alignment, optional_sentinel); | |
| 365 | errdefer allocator.free(buf); | |
| 366 | ||
| 367 | try self.reader().readNoEof(buf); | |
| 368 | return buf; | |
| 369 | } | |
| 370 | ||
| 309 | 371 | pub const ReadError = os.ReadError; |
| 310 | 372 | pub const PReadError = os.PReadError; |
| 311 | 373 |
lib/std/fs/test.zig+40-3| ... | ... | @@ -1,7 +1,44 @@ |
| 1 | 1 | const std = @import("../std.zig"); |
| 2 | const testing = std.testing; | |
| 2 | 3 | const builtin = std.builtin; |
| 3 | 4 | const fs = std.fs; |
| 5 | const mem = std.mem; | |
| 6 | ||
| 4 | 7 | const File = std.fs.File; |
| 8 | const tmpDir = testing.tmpDir; | |
| 9 | ||
| 10 | test "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 | } | |
| 5 | 42 | |
| 6 | 43 | test "openSelfExe" { |
| 7 | 44 | if (builtin.os.tag == .wasi) return error.SkipZigTest; |
| ... | ... | @@ -116,7 +153,7 @@ test "create file, lock and read from multiple process at once" { |
| 116 | 153 | test "open file with exclusive nonblocking lock twice (absolute paths)" { |
| 117 | 154 | if (builtin.os.tag == .wasi) return error.SkipZigTest; |
| 118 | 155 | |
| 119 | const allocator = std.testing.allocator; | |
| 156 | const allocator = testing.allocator; | |
| 120 | 157 | |
| 121 | 158 | const file_paths: [1][]const u8 = .{"zig-test-absolute-paths.txt"}; |
| 122 | 159 | const filename = try fs.path.resolve(allocator, &file_paths); |
| ... | ... | @@ -126,7 +163,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" { |
| 126 | 163 | |
| 127 | 164 | const file2 = fs.createFileAbsolute(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); |
| 128 | 165 | file1.close(); |
| 129 | std.testing.expectError(error.WouldBlock, file2); | |
| 166 | testing.expectError(error.WouldBlock, file2); | |
| 130 | 167 | |
| 131 | 168 | try fs.deleteFileAbsolute(filename); |
| 132 | 169 | } |
| ... | ... | @@ -187,7 +224,7 @@ const FileLockTestContext = struct { |
| 187 | 224 | }; |
| 188 | 225 | |
| 189 | 226 | fn run_lock_file_test(contexts: []FileLockTestContext) !void { |
| 190 | var threads = std.ArrayList(*std.Thread).init(std.testing.allocator); | |
| 227 | var threads = std.ArrayList(*std.Thread).init(testing.allocator); | |
| 191 | 228 | defer { |
| 192 | 229 | for (threads.items) |thread| { |
| 193 | 230 | thread.wait(); |
lib/std/io/buffered_out_stream.zig+1-1| ... | ... | @@ -2,4 +2,4 @@ |
| 2 | 2 | pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter; |
| 3 | 3 | |
| 4 | 4 | /// Deprecated: use `std.io.buffered_writer.bufferedWriter` |
| 5 | pub const bufferedOutStream = @import("./buffered_writer.zig").bufferedWriter | |
| 5 | pub const bufferedOutStream = @import("./buffered_writer.zig").bufferedWriter; |
lib/std/io/reader.zig+1-2| ... | ... | @@ -40,8 +40,7 @@ pub fn Reader( |
| 40 | 40 | return index; |
| 41 | 41 | } |
| 42 | 42 | |
| 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. | |
| 45 | 44 | pub fn readNoEof(self: Self, buf: []u8) !void { |
| 46 | 45 | const amt_read = try self.readAll(buf); |
| 47 | 46 | if (amt_read < buf.len) return error.EndOfStream; |
lib/std/json.zig+4-5| ... | ... | @@ -1535,7 +1535,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: |
| 1535 | 1535 | const allocator = options.allocator orelse return error.AllocatorRequired; |
| 1536 | 1536 | switch (ptrInfo.size) { |
| 1537 | 1537 | .One => { |
| 1538 | const r: T = allocator.create(ptrInfo.child); | |
| 1538 | const r: T = try allocator.create(ptrInfo.child); | |
| 1539 | 1539 | r.* = try parseInternal(ptrInfo.child, token, tokens, options); |
| 1540 | 1540 | return r; |
| 1541 | 1541 | }, |
| ... | ... | @@ -1629,7 +1629,7 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void { |
| 1629 | 1629 | switch (ptrInfo.size) { |
| 1630 | 1630 | .One => { |
| 1631 | 1631 | parseFree(ptrInfo.child, value.*, options); |
| 1632 | allocator.destroy(v); | |
| 1632 | allocator.destroy(value); | |
| 1633 | 1633 | }, |
| 1634 | 1634 | .Slice => { |
| 1635 | 1635 | for (value) |v| { |
| ... | ... | @@ -2576,8 +2576,8 @@ pub fn stringify( |
| 2576 | 2576 | }, |
| 2577 | 2577 | .Array => return stringify(&value, options, out_stream), |
| 2578 | 2578 | .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); | |
| 2581 | 2581 | }, |
| 2582 | 2582 | else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), |
| 2583 | 2583 | } |
| ... | ... | @@ -2770,4 +2770,3 @@ test "stringify struct with custom stringifier" { |
| 2770 | 2770 | test "stringify vector" { |
| 2771 | 2771 | try teststringify("[1,1]", @splat(2, @as(u32, 1)), StringifyOptions{}); |
| 2772 | 2772 | } |
| 2773 |
lib/std/log.zig created+202| ... | ... | @@ -0,0 +1,202 @@ |
| 1 | const std = @import("std.zig"); | |
| 2 | const builtin = std.builtin; | |
| 3 | const 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 | ||
| 59 | pub 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. | |
| 86 | pub 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. | |
| 95 | pub const level: Level = if (@hasDecl(root, "log_level")) | |
| 96 | root.log_level | |
| 97 | else | |
| 98 | default_level; | |
| 99 | ||
| 100 | fn 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. | |
| 120 | pub 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). | |
| 131 | pub 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. | |
| 143 | pub 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. | |
| 154 | pub 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. | |
| 166 | pub 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. | |
| 176 | pub 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. | |
| 186 | pub 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. | |
| 196 | pub fn debug( | |
| 197 | comptime scope: @Type(.EnumLiteral), | |
| 198 | comptime format: []const u8, | |
| 199 | args: var, | |
| 200 | ) void { | |
| 201 | log(.debug, scope, format, args); | |
| 202 | } |
lib/std/math.zig+5| ... | ... | @@ -122,6 +122,11 @@ pub fn forceEval(value: var) void { |
| 122 | 122 | const p = @ptrCast(*volatile f64, &x); |
| 123 | 123 | p.* = x; |
| 124 | 124 | }, |
| 125 | f128 => { | |
| 126 | var x: f128 = undefined; | |
| 127 | const p = @ptrCast(*volatile f128, &x); | |
| 128 | p.* = x; | |
| 129 | }, | |
| 125 | 130 | else => { |
| 126 | 131 | @compileError("forceEval not implemented for " ++ @typeName(T)); |
| 127 | 132 | }, |
lib/std/math/ceil.zig+43| ... | ... | @@ -20,6 +20,7 @@ pub fn ceil(x: var) @TypeOf(x) { |
| 20 | 20 | return switch (T) { |
| 21 | 21 | f32 => ceil32(x), |
| 22 | 22 | f64 => ceil64(x), |
| 23 | f128 => ceil128(x), | |
| 23 | 24 | else => @compileError("ceil not implemented for " ++ @typeName(T)), |
| 24 | 25 | }; |
| 25 | 26 | } |
| ... | ... | @@ -86,9 +87,37 @@ fn ceil64(x: f64) f64 { |
| 86 | 87 | } |
| 87 | 88 | } |
| 88 | 89 | |
| 90 | fn 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 | ||
| 89 | 117 | test "math.ceil" { |
| 90 | 118 | expect(ceil(@as(f32, 0.0)) == ceil32(0.0)); |
| 91 | 119 | expect(ceil(@as(f64, 0.0)) == ceil64(0.0)); |
| 120 | expect(ceil(@as(f128, 0.0)) == ceil128(0.0)); | |
| 92 | 121 | } |
| 93 | 122 | |
| 94 | 123 | test "math.ceil32" { |
| ... | ... | @@ -103,6 +132,12 @@ test "math.ceil64" { |
| 103 | 132 | expect(ceil64(0.2) == 1.0); |
| 104 | 133 | } |
| 105 | 134 | |
| 135 | test "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 | ||
| 106 | 141 | test "math.ceil32.special" { |
| 107 | 142 | expect(ceil32(0.0) == 0.0); |
| 108 | 143 | expect(ceil32(-0.0) == -0.0); |
| ... | ... | @@ -118,3 +153,11 @@ test "math.ceil64.special" { |
| 118 | 153 | expect(math.isNegativeInf(ceil64(-math.inf(f64)))); |
| 119 | 154 | expect(math.isNan(ceil64(math.nan(f64)))); |
| 120 | 155 | } |
| 156 | ||
| 157 | test "math.ceil128.special" { | |
| 158 | expect(ceil128(0.0) == 0.0); | |
| 159 | expect(ceil128(-0.0) == -0.0); | |
| 160 | expect(math.isPositiveInf(ceil128(math.inf(f128)))); | |
| 161 | expect(math.isNegativeInf(ceil128(-math.inf(f128)))); | |
| 162 | expect(math.isNan(ceil128(math.nan(f128)))); | |
| 163 | } |
lib/std/math/floor.zig+43| ... | ... | @@ -21,6 +21,7 @@ pub fn floor(x: var) @TypeOf(x) { |
| 21 | 21 | f16 => floor16(x), |
| 22 | 22 | f32 => floor32(x), |
| 23 | 23 | f64 => floor64(x), |
| 24 | f128 => floor128(x), | |
| 24 | 25 | else => @compileError("floor not implemented for " ++ @typeName(T)), |
| 25 | 26 | }; |
| 26 | 27 | } |
| ... | ... | @@ -122,10 +123,38 @@ fn floor64(x: f64) f64 { |
| 122 | 123 | } |
| 123 | 124 | } |
| 124 | 125 | |
| 126 | fn 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 | ||
| 125 | 153 | test "math.floor" { |
| 126 | 154 | expect(floor(@as(f16, 1.3)) == floor16(1.3)); |
| 127 | 155 | expect(floor(@as(f32, 1.3)) == floor32(1.3)); |
| 128 | 156 | expect(floor(@as(f64, 1.3)) == floor64(1.3)); |
| 157 | expect(floor(@as(f128, 1.3)) == floor128(1.3)); | |
| 129 | 158 | } |
| 130 | 159 | |
| 131 | 160 | test "math.floor16" { |
| ... | ... | @@ -146,6 +175,12 @@ test "math.floor64" { |
| 146 | 175 | expect(floor64(0.2) == 0.0); |
| 147 | 176 | } |
| 148 | 177 | |
| 178 | test "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 | ||
| 149 | 184 | test "math.floor16.special" { |
| 150 | 185 | expect(floor16(0.0) == 0.0); |
| 151 | 186 | expect(floor16(-0.0) == -0.0); |
| ... | ... | @@ -169,3 +204,11 @@ test "math.floor64.special" { |
| 169 | 204 | expect(math.isNegativeInf(floor64(-math.inf(f64)))); |
| 170 | 205 | expect(math.isNan(floor64(math.nan(f64)))); |
| 171 | 206 | } |
| 207 | ||
| 208 | test "math.floor128.special" { | |
| 209 | expect(floor128(0.0) == 0.0); | |
| 210 | expect(floor128(-0.0) == -0.0); | |
| 211 | expect(math.isPositiveInf(floor128(math.inf(f128)))); | |
| 212 | expect(math.isNegativeInf(floor128(-math.inf(f128)))); | |
| 213 | expect(math.isNan(floor128(math.nan(f128)))); | |
| 214 | } |
lib/std/math/round.zig+50| ... | ... | @@ -20,6 +20,7 @@ pub fn round(x: var) @TypeOf(x) { |
| 20 | 20 | return switch (T) { |
| 21 | 21 | f32 => round32(x), |
| 22 | 22 | f64 => round64(x), |
| 23 | f128 => round128(x), | |
| 23 | 24 | else => @compileError("round not implemented for " ++ @typeName(T)), |
| 24 | 25 | }; |
| 25 | 26 | } |
| ... | ... | @@ -90,9 +91,43 @@ fn round64(x_: f64) f64 { |
| 90 | 91 | } |
| 91 | 92 | } |
| 92 | 93 | |
| 94 | fn 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 | ||
| 93 | 127 | test "math.round" { |
| 94 | 128 | expect(round(@as(f32, 1.3)) == round32(1.3)); |
| 95 | 129 | expect(round(@as(f64, 1.3)) == round64(1.3)); |
| 130 | expect(round(@as(f128, 1.3)) == round128(1.3)); | |
| 96 | 131 | } |
| 97 | 132 | |
| 98 | 133 | test "math.round32" { |
| ... | ... | @@ -109,6 +144,13 @@ test "math.round64" { |
| 109 | 144 | expect(round64(1.8) == 2.0); |
| 110 | 145 | } |
| 111 | 146 | |
| 147 | test "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 | ||
| 112 | 154 | test "math.round32.special" { |
| 113 | 155 | expect(round32(0.0) == 0.0); |
| 114 | 156 | expect(round32(-0.0) == -0.0); |
| ... | ... | @@ -124,3 +166,11 @@ test "math.round64.special" { |
| 124 | 166 | expect(math.isNegativeInf(round64(-math.inf(f64)))); |
| 125 | 167 | expect(math.isNan(round64(math.nan(f64)))); |
| 126 | 168 | } |
| 169 | ||
| 170 | test "math.round128.special" { | |
| 171 | expect(round128(0.0) == 0.0); | |
| 172 | expect(round128(-0.0) == -0.0); | |
| 173 | expect(math.isPositiveInf(round128(math.inf(f128)))); | |
| 174 | expect(math.isNegativeInf(round128(-math.inf(f128)))); | |
| 175 | expect(math.isNan(round128(math.nan(f128)))); | |
| 176 | } |
lib/std/math/trunc.zig+37| ... | ... | @@ -20,6 +20,7 @@ pub fn trunc(x: var) @TypeOf(x) { |
| 20 | 20 | return switch (T) { |
| 21 | 21 | f32 => trunc32(x), |
| 22 | 22 | f64 => trunc64(x), |
| 23 | f128 => trunc128(x), | |
| 23 | 24 | else => @compileError("trunc not implemented for " ++ @typeName(T)), |
| 24 | 25 | }; |
| 25 | 26 | } |
| ... | ... | @@ -66,9 +67,31 @@ fn trunc64(x: f64) f64 { |
| 66 | 67 | } |
| 67 | 68 | } |
| 68 | 69 | |
| 70 | fn 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 | ||
| 69 | 91 | test "math.trunc" { |
| 70 | 92 | expect(trunc(@as(f32, 1.3)) == trunc32(1.3)); |
| 71 | 93 | expect(trunc(@as(f64, 1.3)) == trunc64(1.3)); |
| 94 | expect(trunc(@as(f128, 1.3)) == trunc128(1.3)); | |
| 72 | 95 | } |
| 73 | 96 | |
| 74 | 97 | test "math.trunc32" { |
| ... | ... | @@ -83,6 +106,12 @@ test "math.trunc64" { |
| 83 | 106 | expect(trunc64(0.2) == 0.0); |
| 84 | 107 | } |
| 85 | 108 | |
| 109 | test "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 | ||
| 86 | 115 | test "math.trunc32.special" { |
| 87 | 116 | expect(trunc32(0.0) == 0.0); // 0x3F800000 |
| 88 | 117 | expect(trunc32(-0.0) == -0.0); |
| ... | ... | @@ -98,3 +127,11 @@ test "math.trunc64.special" { |
| 98 | 127 | expect(math.isNegativeInf(trunc64(-math.inf(f64)))); |
| 99 | 128 | expect(math.isNan(trunc64(math.nan(f64)))); |
| 100 | 129 | } |
| 130 | ||
| 131 | test "math.trunc128.special" { | |
| 132 | expect(trunc128(0.0) == 0.0); | |
| 133 | expect(trunc128(-0.0) == -0.0); | |
| 134 | expect(math.isPositiveInf(trunc128(math.inf(f128)))); | |
| 135 | expect(math.isNegativeInf(trunc128(-math.inf(f128)))); | |
| 136 | expect(math.isNan(trunc128(math.nan(f128)))); | |
| 137 | } |
lib/std/meta.zig+88-6| ... | ... | @@ -250,7 +250,7 @@ test "std.meta.containerLayout" { |
| 250 | 250 | testing.expect(containerLayout(U3) == .Extern); |
| 251 | 251 | } |
| 252 | 252 | |
| 253 | pub fn declarations(comptime T: type) []TypeInfo.Declaration { | |
| 253 | pub fn declarations(comptime T: type) []const TypeInfo.Declaration { | |
| 254 | 254 | return switch (@typeInfo(T)) { |
| 255 | 255 | .Struct => |info| info.decls, |
| 256 | 256 | .Enum => |info| info.decls, |
| ... | ... | @@ -274,7 +274,7 @@ test "std.meta.declarations" { |
| 274 | 274 | fn a() void {} |
| 275 | 275 | }; |
| 276 | 276 | |
| 277 | const decls = comptime [_][]TypeInfo.Declaration{ | |
| 277 | const decls = comptime [_][]const TypeInfo.Declaration{ | |
| 278 | 278 | declarations(E1), |
| 279 | 279 | declarations(S1), |
| 280 | 280 | declarations(U1), |
| ... | ... | @@ -323,10 +323,10 @@ test "std.meta.declarationInfo" { |
| 323 | 323 | } |
| 324 | 324 | |
| 325 | 325 | pub 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, | |
| 330 | 330 | else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"), |
| 331 | 331 | } { |
| 332 | 332 | return switch (@typeInfo(T)) { |
| ... | ... | @@ -693,3 +693,85 @@ pub fn Vector(comptime len: u32, comptime child: type) type { |
| 693 | 693 | }, |
| 694 | 694 | }); |
| 695 | 695 | } |
| 696 | ||
| 697 | /// Given a type and value, cast the value to the type as c would. | |
| 698 | /// This is for translate-c and is not intended for general use. | |
| 699 | pub 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 | ||
| 762 | test "std.meta.cast" { | |
| 763 | const E = enum(u2) { | |
| 764 | Zero, | |
| 765 | One, | |
| 766 | Two, | |
| 767 | }; | |
| 768 | ||
| 769 | var i = @as(i64, 10); | |
| 770 | ||
| 771 | testing.expect(cast(?*c_void, 0) == @intToPtr(?*c_void, 0)); | |
| 772 | testing.expect(cast(*u8, 16) == @intToPtr(*u8, 16)); | |
| 773 | testing.expect(cast(u64, @as(u32, 10)) == @as(u64, 10)); | |
| 774 | testing.expect(cast(E, 1) == .One); | |
| 775 | testing.expect(cast(u8, E.Two) == 2); | |
| 776 | testing.expect(cast(*u64, &i).* == @as(u64, 10)); | |
| 777 | } |
lib/std/os.zig+100-6| ... | ... | @@ -1520,15 +1520,17 @@ pub const SymLinkError = error{ |
| 1520 | 1520 | /// If `sym_link_path` exists, it will not be overwritten. |
| 1521 | 1521 | /// See also `symlinkC` and `symlinkW`. |
| 1522 | 1522 | pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void { |
| 1523 | if (builtin.os.tag == .wasi) { | |
| 1524 | @compileError("symlink is not supported in WASI; use symlinkat instead"); | |
| 1525 | } | |
| 1523 | 1526 | if (builtin.os.tag == .windows) { |
| 1524 | 1527 | const target_path_w = try windows.sliceToPrefixedFileW(target_path); |
| 1525 | 1528 | const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path); |
| 1526 | 1529 | return windows.CreateSymbolicLinkW(sym_link_path_w.span().ptr, target_path_w.span().ptr, 0); |
| 1527 | } else { | |
| 1528 | const target_path_c = try toPosixPath(target_path); | |
| 1529 | const sym_link_path_c = try toPosixPath(sym_link_path); | |
| 1530 | return symlinkZ(&target_path_c, &sym_link_path_c); | |
| 1531 | 1530 | } |
| 1531 | const target_path_c = try toPosixPath(target_path); | |
| 1532 | const sym_link_path_c = try toPosixPath(sym_link_path); | |
| 1533 | return symlinkZ(&target_path_c, &sym_link_path_c); | |
| 1532 | 1534 | } |
| 1533 | 1535 | |
| 1534 | 1536 | pub const symlinkC = @compileError("deprecated: renamed to symlinkZ"); |
| ... | ... | @@ -1561,15 +1563,65 @@ pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLin |
| 1561 | 1563 | } |
| 1562 | 1564 | } |
| 1563 | 1565 | |
| 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`. | |
| 1564 | 1572 | pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkError!void { |
| 1573 | if (builtin.os.tag == .wasi) { | |
| 1574 | return symlinkatWasi(target_path, newdirfd, sym_link_path); | |
| 1575 | } | |
| 1576 | if (builtin.os.tag == .windows) { | |
| 1577 | const target_path_w = try windows.sliceToPrefixedFileW(target_path); | |
| 1578 | const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path); | |
| 1579 | return symlinkatW(target_path_w.span().ptr, newdirfd, sym_link_path_w.span().ptr); | |
| 1580 | } | |
| 1565 | 1581 | const target_path_c = try toPosixPath(target_path); |
| 1566 | 1582 | const sym_link_path_c = try toPosixPath(sym_link_path); |
| 1567 | return symlinkatZ(target_path_c, newdirfd, sym_link_path_c); | |
| 1583 | return symlinkatZ(&target_path_c, newdirfd, &sym_link_path_c); | |
| 1568 | 1584 | } |
| 1569 | 1585 | |
| 1570 | 1586 | pub const symlinkatC = @compileError("deprecated: renamed to symlinkatZ"); |
| 1571 | 1587 | |
| 1588 | /// WASI-only. The same as `symlinkat` but targeting WASI. | |
| 1589 | /// See also `symlinkat`. | |
| 1590 | pub 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`. | |
| 1613 | pub 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`. | |
| 1572 | 1619 | pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:0]const u8) SymLinkError!void { |
| 1620 | if (builtin.os.tag == .windows) { | |
| 1621 | const target_path_w = try windows.cStrToPrefixedFileW(target_path); | |
| 1622 | const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path); | |
| 1623 | return symlinkatW(target_path_w.span().ptr, newdirfd, sym_link_path.span().ptr); | |
| 1624 | } | |
| 1573 | 1625 | switch (errno(system.symlinkat(target_path, newdirfd, sym_link_path))) { |
| 1574 | 1626 | 0 => return, |
| 1575 | 1627 | EFAULT => unreachable, |
| ... | ... | @@ -2291,12 +2343,54 @@ pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 |
| 2291 | 2343 | } |
| 2292 | 2344 | } |
| 2293 | 2345 | |
| 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`. | |
| 2349 | pub 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 | ||
| 2294 | 2361 | pub const readlinkatC = @compileError("deprecated: renamed to readlinkatZ"); |
| 2295 | 2362 | |
| 2363 | /// WASI-only. Same as `readlinkat` but targets WASI. | |
| 2364 | /// See also `readlinkat`. | |
| 2365 | pub 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`. | |
| 2384 | pub 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`. | |
| 2296 | 2390 | pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 { |
| 2297 | 2391 | if (builtin.os.tag == .windows) { |
| 2298 | 2392 | const file_path_w = try windows.cStrToPrefixedFileW(file_path); |
| 2299 | @compileError("TODO implement readlink for Windows"); | |
| 2393 | return readlinkatW(dirfd, file_path_w.span().ptr, out_buffer); | |
| 2300 | 2394 | } |
| 2301 | 2395 | const rc = system.readlinkat(dirfd, file_path, out_buffer.ptr, out_buffer.len); |
| 2302 | 2396 | switch (errno(rc)) { |
lib/std/os/test.zig+19| ... | ... | @@ -18,6 +18,25 @@ const AtomicOrder = builtin.AtomicOrder; |
| 18 | 18 | const tmpDir = std.testing.tmpDir; |
| 19 | 19 | const Dir = std.fs.Dir; |
| 20 | 20 | |
| 21 | test "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 | ||
| 21 | 40 | test "makePath, put some files in it, deleteTree" { |
| 22 | 41 | var tmp = tmpDir(.{}); |
| 23 | 42 | defer tmp.cleanup(); |
lib/std/os/windows.zig+10-1| ... | ... | @@ -901,7 +901,13 @@ pub fn WSAStartup(majorVersion: u8, minorVersion: u8) !ws2_32.WSADATA { |
| 901 | 901 | var wsadata: ws2_32.WSADATA = undefined; |
| 902 | 902 | return switch (ws2_32.WSAStartup((@as(WORD, minorVersion) << 8) | majorVersion, &wsadata)) { |
| 903 | 903 | 0 => wsadata, |
| 904 | else => |err| unexpectedWSAError(@intToEnum(ws2_32.WinsockError, @intCast(u16, err))), | |
| 904 | else => |err_int| switch (@intToEnum(ws2_32.WinsockError, @intCast(u16, err_int))) { | |
| 905 | .WSASYSNOTREADY => return error.SystemNotAvailable, | |
| 906 | .WSAVERNOTSUPPORTED => return error.VersionNotSupported, | |
| 907 | .WSAEINPROGRESS => return error.BlockingOperationInProgress, | |
| 908 | .WSAEPROCLIM => return error.SystemResources, | |
| 909 | else => |err| return unexpectedWSAError(err), | |
| 910 | }, | |
| 905 | 911 | }; |
| 906 | 912 | } |
| 907 | 913 | |
| ... | ... | @@ -909,6 +915,9 @@ pub fn WSACleanup() !void { |
| 909 | 915 | return switch (ws2_32.WSACleanup()) { |
| 910 | 916 | 0 => {}, |
| 911 | 917 | ws2_32.SOCKET_ERROR => switch (ws2_32.WSAGetLastError()) { |
| 918 | .WSANOTINITIALISED => return error.NotInitialized, | |
| 919 | .WSAENETDOWN => return error.NetworkNotAvailable, | |
| 920 | .WSAEINPROGRESS => return error.BlockingOperationInProgress, | |
| 912 | 921 | else => |err| return unexpectedWSAError(err), |
| 913 | 922 | }, |
| 914 | 923 | else => unreachable, |
lib/std/os/windows/ws2_32.zig+9-9| ... | ... | @@ -163,16 +163,16 @@ pub const IPPROTO_UDP = 17; |
| 163 | 163 | pub const IPPROTO_ICMPV6 = 58; |
| 164 | 164 | pub const IPPROTO_RM = 113; |
| 165 | 165 | |
| 166 | pub const AI_PASSIVE = 0x00001; | |
| 167 | pub const AI_CANONNAME = 0x00002; | |
| 168 | pub const AI_NUMERICHOST = 0x00004; | |
| 169 | pub const AI_NUMERICSERV = 0x00008; | |
| 170 | pub const AI_ADDRCONFIG = 0x00400; | |
| 171 | pub const AI_V4MAPPED = 0x00800; | |
| 172 | pub const AI_NON_AUTHORITATIVE = 0x04000; | |
| 173 | pub const AI_SECURE = 0x08000; | |
| 166 | pub const AI_PASSIVE = 0x00001; | |
| 167 | pub const AI_CANONNAME = 0x00002; | |
| 168 | pub const AI_NUMERICHOST = 0x00004; | |
| 169 | pub const AI_NUMERICSERV = 0x00008; | |
| 170 | pub const AI_ADDRCONFIG = 0x00400; | |
| 171 | pub const AI_V4MAPPED = 0x00800; | |
| 172 | pub const AI_NON_AUTHORITATIVE = 0x04000; | |
| 173 | pub const AI_SECURE = 0x08000; | |
| 174 | 174 | pub const AI_RETURN_PREFERRED_NAMES = 0x10000; |
| 175 | pub const AI_DISABLE_IDN_ENCODING = 0x80000; | |
| 175 | pub const AI_DISABLE_IDN_ENCODING = 0x80000; | |
| 176 | 176 | |
| 177 | 177 | pub const FIONBIO = -2147195266; |
| 178 | 178 |
lib/std/process.zig+7-34| ... | ... | @@ -281,9 +281,6 @@ pub const ArgIteratorWasi = struct { |
| 281 | 281 | pub const ArgIteratorWindows = struct { |
| 282 | 282 | index: usize, |
| 283 | 283 | cmd_line: [*]const u8, |
| 284 | in_quote: bool, | |
| 285 | quote_count: usize, | |
| 286 | seen_quote_count: usize, | |
| 287 | 284 | |
| 288 | 285 | pub const NextError = error{OutOfMemory}; |
| 289 | 286 | |
| ... | ... | @@ -295,9 +292,6 @@ pub const ArgIteratorWindows = struct { |
| 295 | 292 | return ArgIteratorWindows{ |
| 296 | 293 | .index = 0, |
| 297 | 294 | .cmd_line = cmd_line, |
| 298 | .in_quote = false, | |
| 299 | .quote_count = countQuotes(cmd_line), | |
| 300 | .seen_quote_count = 0, | |
| 301 | 295 | }; |
| 302 | 296 | } |
| 303 | 297 | |
| ... | ... | @@ -328,6 +322,7 @@ pub const ArgIteratorWindows = struct { |
| 328 | 322 | } |
| 329 | 323 | |
| 330 | 324 | var backslash_count: usize = 0; |
| 325 | var in_quote = false; | |
| 331 | 326 | while (true) : (self.index += 1) { |
| 332 | 327 | const byte = self.cmd_line[self.index]; |
| 333 | 328 | switch (byte) { |
| ... | ... | @@ -335,14 +330,14 @@ pub const ArgIteratorWindows = struct { |
| 335 | 330 | '"' => { |
| 336 | 331 | const quote_is_real = backslash_count % 2 == 0; |
| 337 | 332 | if (quote_is_real) { |
| 338 | self.seen_quote_count += 1; | |
| 333 | in_quote = !in_quote; | |
| 339 | 334 | } |
| 340 | 335 | }, |
| 341 | 336 | '\\' => { |
| 342 | 337 | backslash_count += 1; |
| 343 | 338 | }, |
| 344 | 339 | ' ', '\t' => { |
| 345 | if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) { | |
| 340 | if (!in_quote) { | |
| 346 | 341 | return true; |
| 347 | 342 | } |
| 348 | 343 | backslash_count = 0; |
| ... | ... | @@ -360,6 +355,7 @@ pub const ArgIteratorWindows = struct { |
| 360 | 355 | defer buf.deinit(); |
| 361 | 356 | |
| 362 | 357 | var backslash_count: usize = 0; |
| 358 | var in_quote = false; | |
| 363 | 359 | while (true) : (self.index += 1) { |
| 364 | 360 | const byte = self.cmd_line[self.index]; |
| 365 | 361 | switch (byte) { |
| ... | ... | @@ -370,10 +366,7 @@ pub const ArgIteratorWindows = struct { |
| 370 | 366 | backslash_count = 0; |
| 371 | 367 | |
| 372 | 368 | 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; | |
| 377 | 370 | } else { |
| 378 | 371 | try buf.append('"'); |
| 379 | 372 | } |
| ... | ... | @@ -384,7 +377,7 @@ pub const ArgIteratorWindows = struct { |
| 384 | 377 | ' ', '\t' => { |
| 385 | 378 | try self.emitBackslashes(&buf, backslash_count); |
| 386 | 379 | backslash_count = 0; |
| 387 | if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) { | |
| 380 | if (in_quote) { | |
| 388 | 381 | try buf.append(byte); |
| 389 | 382 | } else { |
| 390 | 383 | return buf.toOwnedSlice(); |
| ... | ... | @@ -405,26 +398,6 @@ pub const ArgIteratorWindows = struct { |
| 405 | 398 | try buf.append('\\'); |
| 406 | 399 | } |
| 407 | 400 | } |
| 408 | ||
| 409 | fn countQuotes(cmd_line: [*]const u8) usize { | |
| 410 | var result: usize = 0; | |
| 411 | var backslash_count: usize = 0; | |
| 412 | var index: usize = 0; | |
| 413 | while (true) : (index += 1) { | |
| 414 | const byte = cmd_line[index]; | |
| 415 | switch (byte) { | |
| 416 | 0 => return result, | |
| 417 | '\\' => backslash_count += 1, | |
| 418 | '"' => { | |
| 419 | result += 1 - (backslash_count % 2); | |
| 420 | backslash_count = 0; | |
| 421 | }, | |
| 422 | else => { | |
| 423 | backslash_count = 0; | |
| 424 | }, | |
| 425 | } | |
| 426 | } | |
| 427 | } | |
| 428 | 401 | }; |
| 429 | 402 | |
| 430 | 403 | pub const ArgIterator = struct { |
| ... | ... | @@ -578,7 +551,7 @@ test "windows arg parsing" { |
| 578 | 551 | testWindowsCmdLine("a\\\\\\b d\"e f\"g h", &[_][]const u8{ "a\\\\\\b", "de fg", "h" }); |
| 579 | 552 | testWindowsCmdLine("a\\\\\\\"b c d", &[_][]const u8{ "a\\\"b", "c", "d" }); |
| 580 | 553 | testWindowsCmdLine("a\\\\\\\\\"b c\" d e", &[_][]const u8{ "a\\\\b c", "d", "e" }); |
| 581 | testWindowsCmdLine("a b\tc \"d f", &[_][]const u8{ "a", "b", "c", "\"d", "f" }); | |
| 554 | testWindowsCmdLine("a b\tc \"d f", &[_][]const u8{ "a", "b", "c", "d f" }); | |
| 582 | 555 | |
| 583 | 556 | testWindowsCmdLine("\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", &[_][]const u8{ |
| 584 | 557 | ".\\..\\zig-cache\\build", |
lib/std/std.zig+1| ... | ... | @@ -49,6 +49,7 @@ pub const heap = @import("heap.zig"); |
| 49 | 49 | pub const http = @import("http.zig"); |
| 50 | 50 | pub const io = @import("io.zig"); |
| 51 | 51 | pub const json = @import("json.zig"); |
| 52 | pub const log = @import("log.zig"); | |
| 52 | 53 | pub const macho = @import("macho.zig"); |
| 53 | 54 | pub const math = @import("math.zig"); |
| 54 | 55 | pub const mem = @import("mem.zig"); |
lib/std/unicode.zig+41| ... | ... | @@ -235,6 +235,22 @@ pub const Utf8Iterator = struct { |
| 235 | 235 | else => unreachable, |
| 236 | 236 | } |
| 237 | 237 | } |
| 238 | ||
| 239 | /// Look ahead at the next n codepoints without advancing the iterator. | |
| 240 | /// If fewer than n codepoints are available, then return the remainder of the string. | |
| 241 | pub fn peek(it: *Utf8Iterator, n: usize) []const u8 { | |
| 242 | const original_i = it.i; | |
| 243 | defer it.i = original_i; | |
| 244 | ||
| 245 | var end_ix = original_i; | |
| 246 | var found: usize = 0; | |
| 247 | while (found < n) : (found += 1) { | |
| 248 | const next_codepoint = it.nextCodepointSlice() orelse return it.bytes[original_i..]; | |
| 249 | end_ix += next_codepoint.len; | |
| 250 | } | |
| 251 | ||
| 252 | return it.bytes[original_i..end_ix]; | |
| 253 | } | |
| 238 | 254 | }; |
| 239 | 255 | |
| 240 | 256 | pub const Utf16LeIterator = struct { |
| ... | ... | @@ -451,6 +467,31 @@ fn testMiscInvalidUtf8() void { |
| 451 | 467 | testValid("\xee\x80\x80", 0xe000); |
| 452 | 468 | } |
| 453 | 469 | |
| 470 | test "utf8 iterator peeking" { | |
| 471 | comptime testUtf8Peeking(); | |
| 472 | testUtf8Peeking(); | |
| 473 | } | |
| 474 | ||
| 475 | fn 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 | ||
| 454 | 495 | fn testError(bytes: []const u8, expected_err: anyerror) void { |
| 455 | 496 | testing.expectError(expected_err, testDecode(bytes)); |
| 456 | 497 | } |
lib/std/zig/parse.zig-1| ... | ... | @@ -937,7 +937,6 @@ const Parser = struct { |
| 937 | 937 | return node; |
| 938 | 938 | } |
| 939 | 939 | |
| 940 | ||
| 941 | 940 | while_prefix.body = try p.expectNode(parseAssignExpr, .{ |
| 942 | 941 | .ExpectedBlockOrAssignment = .{ .token = p.tok_i }, |
| 943 | 942 | }); |
src-self-hosted/main.zig+93-43| ... | ... | @@ -546,8 +546,9 @@ const Fmt = struct { |
| 546 | 546 | any_error: bool, |
| 547 | 547 | color: Color, |
| 548 | 548 | gpa: *Allocator, |
| 549 | out_buffer: std.ArrayList(u8), | |
| 549 | 550 | |
| 550 | const SeenMap = std.BufSet; | |
| 551 | const SeenMap = std.AutoHashMap(fs.File.INode, void); | |
| 551 | 552 | }; |
| 552 | 553 | |
| 553 | 554 | pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void { |
| ... | ... | @@ -641,10 +642,20 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void { |
| 641 | 642 | .seen = Fmt.SeenMap.init(gpa), |
| 642 | 643 | .any_error = false, |
| 643 | 644 | .color = color, |
| 645 | .out_buffer = std.ArrayList(u8).init(gpa), | |
| 644 | 646 | }; |
| 647 | defer fmt.seen.deinit(); | |
| 648 | defer fmt.out_buffer.deinit(); | |
| 645 | 649 | |
| 646 | 650 | for (input_files.span()) |file_path| { |
| 647 | try fmtPath(&fmt, file_path, check_flag); | |
| 651 | // Get the real path here to avoid Windows failing on relative file paths with . or .. in them. | |
| 652 | const real_path = fs.realpathAlloc(gpa, file_path) catch |err| { | |
| 653 | std.debug.warn("unable to open '{}': {}\n", .{ file_path, err }); | |
| 654 | process.exit(1); | |
| 655 | }; | |
| 656 | defer gpa.free(real_path); | |
| 657 | ||
| 658 | try fmtPath(&fmt, file_path, check_flag, fs.cwd(), real_path); | |
| 648 | 659 | } |
| 649 | 660 | if (fmt.any_error) { |
| 650 | 661 | process.exit(1); |
| ... | ... | @@ -670,48 +681,82 @@ const FmtError = error{ |
| 670 | 681 | ReadOnlyFileSystem, |
| 671 | 682 | LinkQuotaExceeded, |
| 672 | 683 | FileBusy, |
| 684 | EndOfStream, | |
| 673 | 685 | } || fs.File.OpenError; |
| 674 | 686 | |
| 675 | fn 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 | }, | |
| 687 | fn 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), | |
| 702 | 690 | else => { |
| 703 | std.debug.warn("unable to open '{}': {}\n", .{ file_path, err }); | |
| 691 | std.debug.warn("unable to format '{}': {}\n", .{ file_path, err }); | |
| 704 | 692 | fmt.any_error = true; |
| 705 | 693 | return; |
| 706 | 694 | }, |
| 707 | 695 | }; |
| 708 | defer fmt.gpa.free(source_code); | |
| 696 | } | |
| 709 | 697 | |
| 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; | |
| 698 | fn 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 | ||
| 731 | fn fmtPathFile( | |
| 732 | fmt: *Fmt, | |
| 733 | file_path: []const u8, | |
| 734 | check_mode: bool, | |
| 735 | dir: fs.Dir, | |
| 736 | sub_path: []const u8, | |
| 737 | ) FmtError!void { | |
| 738 | const source_file = try dir.openFile(sub_path, .{}); | |
| 739 | var file_closed = false; | |
| 740 | errdefer if (!file_closed) source_file.close(); | |
| 741 | ||
| 742 | const stat = try source_file.stat(); | |
| 743 | ||
| 744 | if (stat.kind == .Directory) | |
| 745 | return error.IsDir; | |
| 746 | ||
| 747 | const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) { | |
| 748 | error.ConnectionResetByPeer => unreachable, | |
| 749 | error.ConnectionTimedOut => unreachable, | |
| 750 | else => |e| return e, | |
| 714 | 751 | }; |
| 752 | source_file.close(); | |
| 753 | file_closed = true; | |
| 754 | defer fmt.gpa.free(source_code); | |
| 755 | ||
| 756 | // Add to set after no longer possible to get error.IsDir. | |
| 757 | if (try fmt.seen.put(stat.inode, {})) |_| return; | |
| 758 | ||
| 759 | const tree = try std.zig.parse(fmt.gpa, source_code); | |
| 715 | 760 | defer tree.deinit(); |
| 716 | 761 | |
| 717 | 762 | for (tree.errors) |parse_error| { |
| ... | ... | @@ -729,14 +774,19 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { |
| 729 | 774 | fmt.any_error = true; |
| 730 | 775 | } |
| 731 | 776 | } 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}); | |
| 740 | 790 | } |
| 741 | 791 | } |
| 742 | 792 |
src-self-hosted/translate_c.zig+13-151| ... | ... | @@ -5668,161 +5668,23 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5668 | 5668 | |
| 5669 | 5669 | const lparen = try appendToken(c, .LParen, "("); |
| 5670 | 5670 | |
| 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, ")"); | |
| 5821 | 5683 | |
| 5822 | 5684 | const group_node = try c.arena.create(ast.Node.GroupedExpression); |
| 5823 | 5685 | group_node.* = .{ |
| 5824 | 5686 | .lparen = lparen, |
| 5825 | .expr = &if_1.base, | |
| 5687 | .expr = &cast_fn_call.base, | |
| 5826 | 5688 | .rparen = try appendToken(c, .RParen, ")"), |
| 5827 | 5689 | }; |
| 5828 | 5690 | return &group_node.base; |
src/analyze.cpp+13| ... | ... | @@ -6012,6 +6012,19 @@ ZigValue *create_const_null(CodeGen *g, ZigType *type) { |
| 6012 | 6012 | return const_val; |
| 6013 | 6013 | } |
| 6014 | 6014 | |
| 6015 | void 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 | ||
| 6022 | ZigValue *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 | ||
| 6015 | 6028 | void init_const_float(ZigValue *const_val, ZigType *type, double value) { |
| 6016 | 6029 | const_val->special = ConstValSpecialStatic; |
| 6017 | 6030 | const_val->type = type; |
src/analyze.hpp+3| ... | ... | @@ -180,6 +180,9 @@ ZigValue *create_const_slice(CodeGen *g, ZigValue *array_val, size_t start, size |
| 180 | 180 | void init_const_null(ZigValue *const_val, ZigType *type); |
| 181 | 181 | ZigValue *create_const_null(CodeGen *g, ZigType *type); |
| 182 | 182 | |
| 183 | void init_const_fn(ZigValue *const_val, ZigFn *fn); | |
| 184 | ZigValue *create_const_fn(CodeGen *g, ZigFn *fn); | |
| 185 | ||
| 183 | 186 | ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count); |
| 184 | 187 | ZigValue **realloc_const_vals_ptrs(CodeGen *g, ZigValue **ptr, size_t old_count, size_t new_count); |
| 185 | 188 |
src/codegen.cpp+6-6| ... | ... | @@ -3540,7 +3540,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl |
| 3540 | 3540 | |
| 3541 | 3541 | for (size_t field_i = 0; field_i < field_count; field_i += 1) { |
| 3542 | 3542 | TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i]; |
| 3543 | ||
| 3543 | ||
| 3544 | 3544 | Buf *name = type_enum_field->name; |
| 3545 | 3545 | auto entry = occupied_tag_values.put_unique(type_enum_field->value, name); |
| 3546 | 3546 | if (entry != nullptr) { |
| ... | ... | @@ -3654,7 +3654,7 @@ static LLVMValueRef ir_gen_negation(CodeGen *g, IrInstGen *inst, IrInstGen *oper |
| 3654 | 3654 | } else if (scalar_type->data.integral.is_signed) { |
| 3655 | 3655 | return LLVMBuildNSWNeg(g->builder, llvm_operand, ""); |
| 3656 | 3656 | } else { |
| 3657 | return LLVMBuildNUWNeg(g->builder, llvm_operand, ""); | |
| 3657 | zig_unreachable(); | |
| 3658 | 3658 | } |
| 3659 | 3659 | } else { |
| 3660 | 3660 | zig_unreachable(); |
| ... | ... | @@ -3984,7 +3984,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutableGen *executable, |
| 3984 | 3984 | assert(array_type->data.pointer.child_type->id == ZigTypeIdArray); |
| 3985 | 3985 | array_type = array_type->data.pointer.child_type; |
| 3986 | 3986 | } |
| 3987 | ||
| 3987 | ||
| 3988 | 3988 | assert(array_type->data.array.len != 0 || array_type->data.array.sentinel != nullptr); |
| 3989 | 3989 | |
| 3990 | 3990 | if (safety_check_on) { |
| ... | ... | @@ -5258,7 +5258,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) { |
| 5258 | 5258 | |
| 5259 | 5259 | for (size_t field_i = 0; field_i < field_count; field_i += 1) { |
| 5260 | 5260 | TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; |
| 5261 | ||
| 5261 | ||
| 5262 | 5262 | Buf *name = type_enum_field->name; |
| 5263 | 5263 | auto entry = occupied_tag_values.put_unique(type_enum_field->value, name); |
| 5264 | 5264 | if (entry != nullptr) { |
| ... | ... | @@ -5471,7 +5471,7 @@ static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) { |
| 5471 | 5471 | } |
| 5472 | 5472 | auto bit_count = operand_type->data.integral.bit_count; |
| 5473 | 5473 | bool is_signed = operand_type->data.integral.is_signed; |
| 5474 | ||
| 5474 | ||
| 5475 | 5475 | ir_assert(bit_count != 0, instruction); |
| 5476 | 5476 | if (bit_count == 1 || !is_power_of_2(bit_count)) { |
| 5477 | 5477 | return get_llvm_type(g, get_int_type(g, is_signed, operand_type->abi_size * 8)); |
| ... | ... | @@ -9275,7 +9275,7 @@ static void init(CodeGen *g) { |
| 9275 | 9275 | abi_name = (g->zig_target->arch == ZigLLVM_riscv32) ? "ilp32" : "lp64"; |
| 9276 | 9276 | } |
| 9277 | 9277 | } |
| 9278 | ||
| 9278 | ||
| 9279 | 9279 | g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str), |
| 9280 | 9280 | target_specific_cpu_args, target_specific_features, opt_level, reloc_mode, |
| 9281 | 9281 | to_llvm_code_model(g), g->function_sections, float_abi, abi_name); |
src/ir.cpp+133-27| ... | ... | @@ -13,6 +13,7 @@ |
| 13 | 13 | #include "os.hpp" |
| 14 | 14 | #include "range_set.hpp" |
| 15 | 15 | #include "softfloat.hpp" |
| 16 | #include "softfloat_ext.hpp" | |
| 16 | 17 | #include "util.hpp" |
| 17 | 18 | #include "mem_list.hpp" |
| 18 | 19 | #include "all_types.hpp" |
| ... | ... | @@ -825,12 +826,11 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_ |
| 825 | 826 | ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; |
| 826 | 827 | size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; |
| 827 | 828 | |
| 828 | // TODO handle sentinel terminated arrays | |
| 829 | 829 | expand_undef_array(g, array_val); |
| 830 | 830 | result = g->pass1_arena->create<ZigValue>(); |
| 831 | 831 | result->special = array_val->special; |
| 832 | 832 | result->type = get_array_type(g, array_val->type->data.array.child_type, |
| 833 | array_val->type->data.array.len - elem_index, nullptr); | |
| 833 | array_val->type->data.array.len - elem_index, array_val->type->data.array.sentinel); | |
| 834 | 834 | result->data.x_array.special = ConstArraySpecialNone; |
| 835 | 835 | result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index]; |
| 836 | 836 | result->parent.id = ConstParentIdArray; |
| ... | ... | @@ -12601,28 +12601,28 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT |
| 12601 | 12601 | if (prev_type->id == ZigTypeIdPointer && |
| 12602 | 12602 | prev_type->data.pointer.ptr_len == PtrLenSingle && |
| 12603 | 12603 | prev_type->data.pointer.child_type->id == ZigTypeIdArray && |
| 12604 | ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown))) | |
| 12604 | ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown))) | |
| 12605 | 12605 | { |
| 12606 | prev_inst = cur_inst; | |
| 12606 | prev_inst = cur_inst; | |
| 12607 | 12607 | |
| 12608 | 12608 | if (prev_type->data.pointer.is_const && !cur_type->data.pointer.is_const) { |
| 12609 | 12609 | // const array pointer and non-const unknown pointer |
| 12610 | 12610 | make_the_pointer_const = true; |
| 12611 | 12611 | } |
| 12612 | continue; | |
| 12612 | continue; | |
| 12613 | 12613 | } |
| 12614 | 12614 | |
| 12615 | 12615 | // *[N]T to [*]T |
| 12616 | 12616 | if (cur_type->id == ZigTypeIdPointer && |
| 12617 | 12617 | cur_type->data.pointer.ptr_len == PtrLenSingle && |
| 12618 | 12618 | cur_type->data.pointer.child_type->id == ZigTypeIdArray && |
| 12619 | ((prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenUnknown))) | |
| 12619 | ((prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenUnknown))) | |
| 12620 | 12620 | { |
| 12621 | 12621 | if (cur_type->data.pointer.is_const && !prev_type->data.pointer.is_const) { |
| 12622 | 12622 | // const array pointer and non-const unknown pointer |
| 12623 | 12623 | make_the_pointer_const = true; |
| 12624 | 12624 | } |
| 12625 | continue; | |
| 12625 | continue; | |
| 12626 | 12626 | } |
| 12627 | 12627 | |
| 12628 | 12628 | // *[N]T to []T |
| ... | ... | @@ -20986,17 +20986,24 @@ static IrInstGen *ir_analyze_negation(IrAnalyze *ira, IrInstSrcUnOp *instruction |
| 20986 | 20986 | if (type_is_invalid(expr_type)) |
| 20987 | 20987 | return ira->codegen->invalid_inst_gen; |
| 20988 | 20988 | |
| 20989 | if (!(expr_type->id == ZigTypeIdInt || expr_type->id == ZigTypeIdComptimeInt || | |
| 20990 | expr_type->id == ZigTypeIdFloat || expr_type->id == ZigTypeIdComptimeFloat || | |
| 20991 | expr_type->id == ZigTypeIdVector)) | |
| 20992 | { | |
| 20993 | ir_add_error(ira, &instruction->base.base, | |
| 20994 | buf_sprintf("negation of type '%s'", buf_ptr(&expr_type->name))); | |
| 20995 | return ira->codegen->invalid_inst_gen; | |
| 20996 | } | |
| 20997 | ||
| 20998 | 20989 | bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap); |
| 20999 | 20990 | |
| 20991 | switch (expr_type->id) { | |
| 20992 | case ZigTypeIdComptimeInt: | |
| 20993 | case ZigTypeIdFloat: | |
| 20994 | case ZigTypeIdComptimeFloat: | |
| 20995 | case ZigTypeIdVector: | |
| 20996 | break; | |
| 20997 | case ZigTypeIdInt: | |
| 20998 | if (is_wrap_op || expr_type->data.integral.is_signed) | |
| 20999 | break; | |
| 21000 | ZIG_FALLTHROUGH; | |
| 21001 | default: | |
| 21002 | ir_add_error(ira, &instruction->base.base, | |
| 21003 | buf_sprintf("negation of type '%s'", buf_ptr(&expr_type->name))); | |
| 21004 | return ira->codegen->invalid_inst_gen; | |
| 21005 | } | |
| 21006 | ||
| 21000 | 21007 | ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; |
| 21001 | 21008 | |
| 21002 | 21009 | if (instr_is_comptime(value)) { |
| ... | ... | @@ -25609,9 +25616,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy |
| 25609 | 25616 | break; |
| 25610 | 25617 | } |
| 25611 | 25618 | 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 | } | |
| 25615 | 25631 | } |
| 25616 | 25632 | |
| 25617 | 25633 | assert(result != nullptr); |
| ... | ... | @@ -25880,10 +25896,90 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI |
| 25880 | 25896 | ZigType *child_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "child", 0); |
| 25881 | 25897 | return get_any_frame_type(ira->codegen, child_type); |
| 25882 | 25898 | } |
| 25883 | case ZigTypeIdErrorSet: | |
| 25884 | case ZigTypeIdEnum: | |
| 25885 | case ZigTypeIdFnFrame: | |
| 25886 | 25899 | case ZigTypeIdEnumLiteral: |
| 25900 | return ira->codegen->builtin_types.entry_enum_literal; | |
| 25901 | case ZigTypeIdFnFrame: { | |
| 25902 | assert(payload->special == ConstValSpecialStatic); | |
| 25903 | assert(payload->type == ir_type_info_get_type(ira, "Frame", nullptr)); | |
| 25904 | ZigValue *function = get_const_field(ira, source_instr->source_node, payload, "function", 0); | |
| 25905 | assert(function->type->id == ZigTypeIdFn); | |
| 25906 | ZigFn *fn = function->data.x_ptr.data.fn.fn_entry; | |
| 25907 | return get_fn_frame_type(ira->codegen, fn); | |
| 25908 | } | |
| 25909 | case ZigTypeIdErrorSet: { | |
| 25910 | assert(payload->special == ConstValSpecialStatic); | |
| 25911 | assert(payload->type->id == ZigTypeIdOptional); | |
| 25912 | ZigValue *slice = payload->data.x_optional; | |
| 25913 | if (slice == nullptr) | |
| 25914 | return ira->codegen->builtin_types.entry_global_error_set; | |
| 25915 | assert(slice->special == ConstValSpecialStatic); | |
| 25916 | assert(is_slice(slice->type)); | |
| 25917 | ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); | |
| 25918 | Buf bare_name = BUF_INIT; | |
| 25919 | buf_init_from_buf(&err_set_type->name, get_anon_type_name(ira->codegen, ira->old_irb.exec, "error", source_instr->scope, source_instr->source_node, &bare_name)); | |
| 25920 | err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; | |
| 25921 | err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; | |
| 25922 | err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; | |
| 25923 | ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index]; | |
| 25924 | assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);; | |
| 25925 | assert(ptr->data.x_ptr.data.base_array.elem_index == 0); | |
| 25926 | ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val; | |
| 25927 | assert(arr->special == ConstValSpecialStatic); | |
| 25928 | assert(arr->data.x_array.special == ConstArraySpecialNone); | |
| 25929 | ZigValue *len = slice->data.x_struct.fields[slice_len_index]; | |
| 25930 | size_t count = bigint_as_usize(&len->data.x_bigint); | |
| 25931 | err_set_type->data.error_set.err_count = count; | |
| 25932 | err_set_type->data.error_set.errors = heap::c_allocator.allocate<ErrorTableEntry *>(count); | |
| 25933 | bool *already_set = heap::c_allocator.allocate<bool>(ira->codegen->errors_by_index.length + count); | |
| 25934 | for (size_t i = 0; i < count; i++) { | |
| 25935 | ZigValue *error = &arr->data.x_array.data.s_none.elements[i]; | |
| 25936 | assert(error->type == ir_type_info_get_type(ira, "Error", nullptr)); | |
| 25937 | ErrorTableEntry *err_entry = heap::c_allocator.create<ErrorTableEntry>(); | |
| 25938 | err_entry->decl_node = source_instr->source_node; | |
| 25939 | ZigValue *name_slice = get_const_field(ira, source_instr->source_node, error, "name", 0); | |
| 25940 | ZigValue *name_ptr = name_slice->data.x_struct.fields[slice_ptr_index]; | |
| 25941 | ZigValue *name_len = name_slice->data.x_struct.fields[slice_len_index]; | |
| 25942 | assert(name_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); | |
| 25943 | assert(name_ptr->data.x_ptr.data.base_array.elem_index == 0); | |
| 25944 | ZigValue *name_arr = name_ptr->data.x_ptr.data.base_array.array_val; | |
| 25945 | assert(name_arr->special == ConstValSpecialStatic); | |
| 25946 | switch (name_arr->data.x_array.special) { | |
| 25947 | case ConstArraySpecialUndef: | |
| 25948 | return ira->codegen->invalid_inst_gen->value->type; | |
| 25949 | case ConstArraySpecialNone: { | |
| 25950 | buf_resize(&err_entry->name, 0); | |
| 25951 | size_t name_count = bigint_as_usize(&name_len->data.x_bigint); | |
| 25952 | for (size_t j = 0; j < name_count; j++) { | |
| 25953 | ZigValue *ch_val = &name_arr->data.x_array.data.s_none.elements[j]; | |
| 25954 | unsigned ch = bigint_as_u32(&ch_val->data.x_bigint); | |
| 25955 | buf_append_char(&err_entry->name, ch); | |
| 25956 | } | |
| 25957 | break; | |
| 25958 | } | |
| 25959 | case ConstArraySpecialBuf: | |
| 25960 | buf_init_from_buf(&err_entry->name, name_arr->data.x_array.data.s_buf); | |
| 25961 | break; | |
| 25962 | } | |
| 25963 | auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry); | |
| 25964 | if (existing_entry) { | |
| 25965 | err_entry->value = existing_entry->value->value; | |
| 25966 | } else { | |
| 25967 | size_t error_value_count = ira->codegen->errors_by_index.length; | |
| 25968 | assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count)); | |
| 25969 | err_entry->value = error_value_count; | |
| 25970 | ira->codegen->errors_by_index.append(err_entry); | |
| 25971 | } | |
| 25972 | if (already_set[err_entry->value]) { | |
| 25973 | ir_add_error(ira, source_instr, buf_sprintf("duplicate error: %s", buf_ptr(&err_entry->name))); | |
| 25974 | return ira->codegen->invalid_inst_gen->value->type; | |
| 25975 | } else { | |
| 25976 | already_set[err_entry->value] = true; | |
| 25977 | } | |
| 25978 | err_set_type->data.error_set.errors[i] = err_entry; | |
| 25979 | } | |
| 25980 | return err_set_type; | |
| 25981 | } | |
| 25982 | case ZigTypeIdEnum: | |
| 25887 | 25983 | ir_add_error(ira, source_instr, buf_sprintf( |
| 25888 | 25984 | "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId))); |
| 25889 | 25985 | return ira->codegen->invalid_inst_gen->value->type; |
| ... | ... | @@ -30278,6 +30374,21 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF |
| 30278 | 30374 | case BuiltinFnIdSqrt: |
| 30279 | 30375 | f128M_sqrt(in, out); |
| 30280 | 30376 | break; |
| 30377 | case BuiltinFnIdFabs: | |
| 30378 | f128M_abs(in, out); | |
| 30379 | break; | |
| 30380 | case BuiltinFnIdFloor: | |
| 30381 | f128M_roundToInt(in, softfloat_round_min, false, out); | |
| 30382 | break; | |
| 30383 | case BuiltinFnIdCeil: | |
| 30384 | f128M_roundToInt(in, softfloat_round_max, false, out); | |
| 30385 | break; | |
| 30386 | case BuiltinFnIdTrunc: | |
| 30387 | f128M_trunc(in, out); | |
| 30388 | break; | |
| 30389 | case BuiltinFnIdRound: | |
| 30390 | f128M_roundToInt(in, softfloat_round_near_maxMag, false, out); | |
| 30391 | break; | |
| 30281 | 30392 | case BuiltinFnIdNearbyInt: |
| 30282 | 30393 | case BuiltinFnIdSin: |
| 30283 | 30394 | case BuiltinFnIdCos: |
| ... | ... | @@ -30286,11 +30397,6 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF |
| 30286 | 30397 | case BuiltinFnIdLog: |
| 30287 | 30398 | case BuiltinFnIdLog10: |
| 30288 | 30399 | case BuiltinFnIdLog2: |
| 30289 | case BuiltinFnIdFabs: | |
| 30290 | case BuiltinFnIdFloor: | |
| 30291 | case BuiltinFnIdCeil: | |
| 30292 | case BuiltinFnIdTrunc: | |
| 30293 | case BuiltinFnIdRound: | |
| 30294 | 30400 | return ir_add_error(ira, source_instr, |
| 30295 | 30401 | buf_sprintf("compiler bug: TODO: implement '%s' for type '%s'. See https://github.com/ziglang/zig/issues/4026", |
| 30296 | 30402 | float_op_to_name(fop), buf_ptr(&float_type->name))); |
src/softfloat_ext.cpp created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | #include "softfloat_ext.hpp" | |
| 2 | ||
| 3 | extern "C" { | |
| 4 | #include "softfloat.h" | |
| 5 | } | |
| 6 | ||
| 7 | void 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 | ||
| 17 | void 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 | ||
| 6 | void f128M_abs(const float128_t *aPtr, float128_t *zPtr); | |
| 7 | void f128M_trunc(const float128_t *aPtr, float128_t *zPtr); | |
| 8 | ||
| 9 | #endif | |
| \ No newline at end of file |
test/cli.zig+27| ... | ... | @@ -34,6 +34,7 @@ pub fn main() !void { |
| 34 | 34 | testZigInitExe, |
| 35 | 35 | testGodboltApi, |
| 36 | 36 | testMissingOutputPath, |
| 37 | testZigFmt, | |
| 37 | 38 | }; |
| 38 | 39 | for (test_fns) |testFn| { |
| 39 | 40 | try fs.cwd().deleteTree(dir_path); |
| ... | ... | @@ -143,3 +144,29 @@ fn testMissingOutputPath(zig_exe: []const u8, dir_path: []const u8) !void { |
| 143 | 144 | zig_exe, "build-exe", source_path, "--output-dir", output_path, |
| 144 | 145 | }); |
| 145 | 146 | } |
| 147 | ||
| 148 | fn testZigFmt(zig_exe: []const u8, dir_path: []const u8) !void { | |
| 149 | _ = try exec(dir_path, &[_][]const u8{ zig_exe, "init-exe" }); | |
| 150 | ||
| 151 | const unformatted_code = " // no reason for indent"; | |
| 152 | ||
| 153 | const fmt1_zig_path = try fs.path.join(a, &[_][]const u8{ dir_path, "fmt1.zig" }); | |
| 154 | try fs.cwd().writeFile(fmt1_zig_path, unformatted_code); | |
| 155 | ||
| 156 | const run_result1 = try exec(dir_path, &[_][]const u8{ zig_exe, "fmt", fmt1_zig_path }); | |
| 157 | // stderr should be file path + \n | |
| 158 | testing.expect(std.mem.startsWith(u8, run_result1.stderr, fmt1_zig_path)); | |
| 159 | testing.expect(run_result1.stderr.len == fmt1_zig_path.len + 1 and run_result1.stderr[run_result1.stderr.len - 1] == '\n'); | |
| 160 | ||
| 161 | const fmt2_zig_path = try fs.path.join(a, &[_][]const u8{ dir_path, "fmt2.zig" }); | |
| 162 | try fs.cwd().writeFile(fmt2_zig_path, unformatted_code); | |
| 163 | ||
| 164 | const run_result2 = try exec(dir_path, &[_][]const u8{ zig_exe, "fmt", dir_path }); | |
| 165 | // running it on the dir, only the new file should be changed | |
| 166 | testing.expect(std.mem.startsWith(u8, run_result2.stderr, fmt2_zig_path)); | |
| 167 | testing.expect(run_result2.stderr.len == fmt2_zig_path.len + 1 and run_result2.stderr[run_result2.stderr.len - 1] == '\n'); | |
| 168 | ||
| 169 | const run_result3 = try exec(dir_path, &[_][]const u8{ zig_exe, "fmt", dir_path }); | |
| 170 | // both files have been formatted, nothing should change now | |
| 171 | testing.expect(run_result3.stderr.len == 0); | |
| 172 | } |
test/compile_errors.zig+9| ... | ... | @@ -7530,4 +7530,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 7530 | 7530 | , &[_][]const u8{ |
| 7531 | 7531 | "tmp.zig:2:9: error: @wasmMemoryGrow is a wasm32 feature only", |
| 7532 | 7532 | }); |
| 7533 | ||
| 7534 | cases.add("Issue #5586: Make unary minus for unsigned types a compile error", | |
| 7535 | \\export fn f(x: u32) u32 { | |
| 7536 | \\ const y = -%x; | |
| 7537 | \\ return -y; | |
| 7538 | \\} | |
| 7539 | , &[_][]const u8{ | |
| 7540 | "tmp.zig:3:12: error: negation of type 'u32'" | |
| 7541 | }); | |
| 7533 | 7542 | } |
test/stage1/behavior/math.zig+122| ... | ... | @@ -634,6 +634,128 @@ fn testSqrt(comptime T: type, x: T) void { |
| 634 | 634 | expect(@sqrt(x * x) == x); |
| 635 | 635 | } |
| 636 | 636 | |
| 637 | test "@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 | ||
| 653 | fn testFabs(comptime T: type, x: T) void { | |
| 654 | const y = -x; | |
| 655 | const z = @fabs(y); | |
| 656 | expectEqual(x, z); | |
| 657 | } | |
| 658 | ||
| 659 | test "@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 | ||
| 676 | fn testFloor(comptime T: type, x: T) void { | |
| 677 | const y = x + 0.6; | |
| 678 | const z = @floor(y); | |
| 679 | expectEqual(x, z); | |
| 680 | } | |
| 681 | ||
| 682 | test "@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 | ||
| 699 | fn testCeil(comptime T: type, x: T) void { | |
| 700 | const y = x - 0.8; | |
| 701 | const z = @ceil(y); | |
| 702 | expectEqual(x, z); | |
| 703 | } | |
| 704 | ||
| 705 | test "@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 | ||
| 722 | fn 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 | ||
| 736 | test "@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 | ||
| 753 | fn testRound(comptime T: type, x: T) void { | |
| 754 | const y = x - 0.5; | |
| 755 | const z = @round(y); | |
| 756 | expectEqual(x, z); | |
| 757 | } | |
| 758 | ||
| 637 | 759 | test "comptime_int param and return" { |
| 638 | 760 | const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); |
| 639 | 761 | expect(a == 137114567242441932203689521744947848950); |
test/stage1/behavior/slice.zig+5| ... | ... | @@ -280,6 +280,11 @@ test "slice syntax resulting in pointer-to-array" { |
| 280 | 280 | expect(slice[0] == 5); |
| 281 | 281 | comptime expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); |
| 282 | 282 | } |
| 283 | ||
| 284 | fn testConcatStrLiterals() void { | |
| 285 | expectEqualSlices("a"[0..] ++ "b"[0..], "ab"); | |
| 286 | expectEqualSlices("a"[0..:0] ++ "b"[0..:0], "ab"); | |
| 287 | } | |
| 283 | 288 | }; |
| 284 | 289 | |
| 285 | 290 | S.doTheTest(); |
test/stage1/behavior/type.zig+23| ... | ... | @@ -213,3 +213,26 @@ test "Type.AnyFrame" { |
| 213 | 213 | anyframe->anyframe->u8, |
| 214 | 214 | }); |
| 215 | 215 | } |
| 216 | ||
| 217 | test "Type.EnumLiteral" { | |
| 218 | testTypes(&[_]type{ | |
| 219 | @TypeOf(.Dummy), | |
| 220 | }); | |
| 221 | } | |
| 222 | ||
| 223 | fn add(a: i32, b: i32) i32 { | |
| 224 | return a + b; | |
| 225 | } | |
| 226 | ||
| 227 | test "Type.Frame" { | |
| 228 | testTypes(&[_]type{ | |
| 229 | @Frame(add), | |
| 230 | }); | |
| 231 | } | |
| 232 | ||
| 233 | test "Type.ErrorSet" { | |
| 234 | // error sets don't compare equal so just check if they compile | |
| 235 | _ = @Type(@typeInfo(error{})); | |
| 236 | _ = @Type(@typeInfo(error{A})); | |
| 237 | _ = @Type(@typeInfo(error{ A, B, C })); | |
| 238 | } |
test/stage1/behavior/type_info.zig+14-1| ... | ... | @@ -202,7 +202,7 @@ fn testUnion() void { |
| 202 | 202 | expect(typeinfo_info.Union.fields[4].enum_field != null); |
| 203 | 203 | expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4); |
| 204 | 204 | expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int)); |
| 205 | expect(typeinfo_info.Union.decls.len == 20); | |
| 205 | expect(typeinfo_info.Union.decls.len == 21); | |
| 206 | 206 | |
| 207 | 207 | const TestNoTagUnion = union { |
| 208 | 208 | Foo: void, |
| ... | ... | @@ -389,3 +389,16 @@ test "defaut value for a var-typed field" { |
| 389 | 389 | const S = struct { x: var }; |
| 390 | 390 | expect(@typeInfo(S).Struct.fields[0].default_value == null); |
| 391 | 391 | } |
| 392 | ||
| 393 | fn add(a: i32, b: i32) i32 { | |
| 394 | return a + b; | |
| 395 | } | |
| 396 | ||
| 397 | test "type info for async frames" { | |
| 398 | switch (@typeInfo(@Frame(add))) { | |
| 399 | .Frame => |frame| { | |
| 400 | expect(frame.function == add); | |
| 401 | }, | |
| 402 | else => unreachable, | |
| 403 | } | |
| 404 | } |
test/translate_c.zig+8-8| ... | ... | @@ -1473,7 +1473,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1473 | 1473 | cases.add("macro pointer cast", |
| 1474 | 1474 | \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) |
| 1475 | 1475 | , &[_][]const u8{ |
| 1476 | \\pub const NRF_GPIO = (if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, @alignCast(@alignOf([*c]NRF_GPIO_Type.Child), NRF_GPIO_BASE)) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int and @typeInfo([*c]NRF_GPIO_Type) == .Pointer) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE)); | |
| 1476 | \\pub const NRF_GPIO = (@import("std").meta.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE)); | |
| 1477 | 1477 | }); |
| 1478 | 1478 | |
| 1479 | 1479 | cases.add("basic macro function", |
| ... | ... | @@ -2683,11 +2683,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2683 | 2683 | \\#define FOO(bar) baz((void *)(baz)) |
| 2684 | 2684 | \\#define BAR (void*) a |
| 2685 | 2685 | , &[_][]const u8{ |
| 2686 | \\pub inline fn FOO(bar: var) @TypeOf(baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(?*c_void, @alignCast(@alignOf(?*c_void.Child), baz)) else if (@typeInfo(@TypeOf(baz)) == .Int and @typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, baz) else @as(?*c_void, baz)))) { | |
| 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))); | |
| 2688 | 2688 | \\} |
| 2689 | 2689 | , |
| 2690 | \\pub const BAR = (if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(?*c_void, @alignCast(@alignOf(?*c_void.Child), a)) else if (@typeInfo(@TypeOf(a)) == .Int and @typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, a) else @as(?*c_void, a)); | |
| 2690 | \\pub const BAR = (@import("std").meta.cast(?*c_void, a)); | |
| 2691 | 2691 | }); |
| 2692 | 2692 | |
| 2693 | 2693 | cases.add("macro conditional operator", |
| ... | ... | @@ -2905,8 +2905,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2905 | 2905 | \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen) |
| 2906 | 2906 | \\ |
| 2907 | 2907 | , &[_][]const u8{ |
| 2908 | \\pub inline fn DefaultScreen(dpy: var) @TypeOf((if (@typeInfo(@TypeOf(dpy)) == .Pointer) @ptrCast(_XPrivDisplay, @alignCast(@alignOf(_XPrivDisplay.Child), dpy)) else if (@typeInfo(@TypeOf(dpy)) == .Int and @typeInfo(_XPrivDisplay) == .Pointer) @intToPtr(_XPrivDisplay, dpy) else @as(_XPrivDisplay, dpy)).*.default_screen) { | |
| 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; | |
| 2910 | 2910 | \\} |
| 2911 | 2911 | }); |
| 2912 | 2912 | |
| ... | ... | @@ -2914,9 +2914,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2914 | 2914 | \\#define NULL ((void*)0) |
| 2915 | 2915 | \\#define FOO ((int)0x8000) |
| 2916 | 2916 | , &[_][]const u8{ |
| 2917 | \\pub const NULL = (if (@typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, 0) else @as(?*c_void, 0)); | |
| 2917 | \\pub const NULL = (@import("std").meta.cast(?*c_void, 0)); | |
| 2918 | 2918 | , |
| 2919 | \\pub const FOO = (if (@typeInfo(c_int) == .Pointer) @intToPtr(c_int, 0x8000) else @as(c_int, 0x8000)); | |
| 2919 | \\pub const FOO = (@import("std").meta.cast(c_int, 0x8000)); | |
| 2920 | 2920 | }); |
| 2921 | 2921 | |
| 2922 | 2922 | if (std.Target.current.abi == .msvc) { |