| author | |
| committer | |
| log | 0dcba03b67af0aee612b51191a8110d91a55019e |
| tree | e4aaeaa26ce2a306de343dde151ba34eb4083474 |
| parent | 31f353cd925a565dc32fa013c3ff767a06963adc |
| parent | 75ccdcc356839687033ba982a34fe0703ba1e349 |
| signature |
Autodoc: improve error reporting4 files changed, 100 insertions(+), 36 deletions(-)
lib/docs/index.html+32| ... | @@ -6,6 +6,9 @@ | ... | @@ -6,6 +6,9 @@ |
| 6 | <title>Zig Documentation</title> | 6 | <title>Zig Documentation</title> |
| 7 | <link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+"> | 7 | <link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+"> |
| 8 | <style type="text/css"> | 8 | <style type="text/css"> |
| 9 | *, *::before, *::after { | ||
| 10 | box-sizing: border-box; | ||
| 11 | } | ||
| 9 | body { | 12 | body { |
| 10 | font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif; | 13 | font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif; |
| 11 | color: #000000; | 14 | color: #000000; |
| ... | @@ -157,6 +160,23 @@ | ... | @@ -157,6 +160,23 @@ |
| 157 | cursor: default; | 160 | cursor: default; |
| 158 | } | 161 | } |
| 159 | 162 | ||
| 163 | #errors { | ||
| 164 | background-color: #faa; | ||
| 165 | position: fixed; | ||
| 166 | left: 0; | ||
| 167 | bottom: 0; | ||
| 168 | width: 100%; | ||
| 169 | max-height: min(20em, 50vh); | ||
| 170 | padding: 0.5em; | ||
| 171 | overflow: auto; | ||
| 172 | } | ||
| 173 | #errors h1 { | ||
| 174 | font-size: 1.5em; | ||
| 175 | } | ||
| 176 | #errors pre { | ||
| 177 | background-color: #fcc; | ||
| 178 | } | ||
| 179 | |||
| 160 | #listSearchResults li.selected { | 180 | #listSearchResults li.selected { |
| 161 | background-color: #93e196; | 181 | background-color: #93e196; |
| 162 | } | 182 | } |
| ... | @@ -252,6 +272,14 @@ | ... | @@ -252,6 +272,14 @@ |
| 252 | #listSearchResults li.selected a { | 272 | #listSearchResults li.selected a { |
| 253 | color: #fff; | 273 | color: #fff; |
| 254 | } | 274 | } |
| 275 | #errors { | ||
| 276 | background-color: #800; | ||
| 277 | color: #fff; | ||
| 278 | } | ||
| 279 | #errors pre { | ||
| 280 | background-color: #a00; | ||
| 281 | color: #fff; | ||
| 282 | } | ||
| 255 | dl > div { | 283 | dl > div { |
| 256 | border-color: #373737; | 284 | border-color: #373737; |
| 257 | } | 285 | } |
| ... | @@ -414,6 +442,10 @@ | ... | @@ -414,6 +442,10 @@ |
| 414 | <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl> | 442 | <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl> |
| 415 | <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl> | 443 | <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl> |
| 416 | </div> | 444 | </div> |
| 445 | <div id="errors" class="hidden"> | ||
| 446 | <h1>Errors</h1> | ||
| 447 | <pre id="errorsText"></pre> | ||
| 448 | </div> | ||
| 417 | <script src="main.js"></script> | 449 | <script src="main.js"></script> |
| 418 | </body> | 450 | </body> |
| 419 | </html> | 451 | </html> |
lib/docs/main.js+24-6| ... | @@ -11,6 +11,11 @@ | ... | @@ -11,6 +11,11 @@ |
| 11 | const CAT_type_type = 9; | 11 | const CAT_type_type = 9; |
| 12 | const CAT_type_function = 10; | 12 | const CAT_type_function = 10; |
| 13 | 13 | ||
| 14 | const LOG_err = 0; | ||
| 15 | const LOG_warn = 1; | ||
| 16 | const LOG_info = 2; | ||
| 17 | const LOG_debug = 3; | ||
| 18 | |||
| 14 | const domDocTestsCode = document.getElementById("docTestsCode"); | 19 | const domDocTestsCode = document.getElementById("docTestsCode"); |
| 15 | const domFnErrorsAnyError = document.getElementById("fnErrorsAnyError"); | 20 | const domFnErrorsAnyError = document.getElementById("fnErrorsAnyError"); |
| 16 | const domFnProto = document.getElementById("fnProto"); | 21 | const domFnProto = document.getElementById("fnProto"); |
| ... | @@ -48,6 +53,8 @@ | ... | @@ -48,6 +53,8 @@ |
| 48 | const domStatus = document.getElementById("status"); | 53 | const domStatus = document.getElementById("status"); |
| 49 | const domTableFnErrors = document.getElementById("tableFnErrors"); | 54 | const domTableFnErrors = document.getElementById("tableFnErrors"); |
| 50 | const domTldDocs = document.getElementById("tldDocs"); | 55 | const domTldDocs = document.getElementById("tldDocs"); |
| 56 | const domErrors = document.getElementById("errors"); | ||
| 57 | const domErrorsText = document.getElementById("errorsText"); | ||
| 51 | 58 | ||
| 52 | var searchTimer = null; | 59 | var searchTimer = null; |
| 53 | 60 | ||
| ... | @@ -84,13 +91,24 @@ | ... | @@ -84,13 +91,24 @@ |
| 84 | 91 | ||
| 85 | WebAssembly.instantiateStreaming(wasm_promise, { | 92 | WebAssembly.instantiateStreaming(wasm_promise, { |
| 86 | js: { | 93 | js: { |
| 87 | log: function(ptr, len) { | 94 | log: function(level, ptr, len) { |
| 88 | const msg = decodeString(ptr, len); | 95 | const msg = decodeString(ptr, len); |
| 89 | console.log(msg); | 96 | switch (level) { |
| 90 | }, | 97 | case LOG_err: |
| 91 | panic: function (ptr, len) { | 98 | console.error(msg); |
| 92 | const msg = decodeString(ptr, len); | 99 | domErrorsText.textContent += msg + "\n"; |
| 93 | throw new Error("panic: " + msg); | 100 | domErrors.classList.remove("hidden"); |
| 101 | break; | ||
| 102 | case LOG_warn: | ||
| 103 | console.warn(msg); | ||
| 104 | break; | ||
| 105 | case LOG_info: | ||
| 106 | console.info(msg); | ||
| 107 | break; | ||
| 108 | case LOG_debug: | ||
| 109 | console.debug(msg); | ||
| 110 | break; | ||
| 111 | } | ||
| 94 | }, | 112 | }, |
| 95 | }, | 113 | }, |
| 96 | }).then(function(obj) { | 114 | }).then(function(obj) { |
lib/docs/wasm/Walk.zig+27-10| ... | @@ -406,15 +406,11 @@ pub const ModuleIndex = enum(u32) { | ... | @@ -406,15 +406,11 @@ pub const ModuleIndex = enum(u32) { |
| 406 | }; | 406 | }; |
| 407 | 407 | ||
| 408 | pub fn add_file(file_name: []const u8, bytes: []u8) !File.Index { | 408 | pub fn add_file(file_name: []const u8, bytes: []u8) !File.Index { |
| 409 | const ast = try parse(bytes); | 409 | const ast = try parse(file_name, bytes); |
| 410 | assert(ast.errors.len == 0); | ||
| 410 | const file_index: File.Index = @enumFromInt(files.entries.len); | 411 | const file_index: File.Index = @enumFromInt(files.entries.len); |
| 411 | try files.put(gpa, file_name, .{ .ast = ast }); | 412 | try files.put(gpa, file_name, .{ .ast = ast }); |
| 412 | 413 | ||
| 413 | if (ast.errors.len > 0) { | ||
| 414 | log.err("can't index '{s}' because it has syntax errors", .{file_index.path()}); | ||
| 415 | return file_index; | ||
| 416 | } | ||
| 417 | |||
| 418 | var w: Walk = .{ | 414 | var w: Walk = .{ |
| 419 | .file = file_index, | 415 | .file = file_index, |
| 420 | }; | 416 | }; |
| ... | @@ -434,20 +430,41 @@ pub fn add_file(file_name: []const u8, bytes: []u8) !File.Index { | ... | @@ -434,20 +430,41 @@ pub fn add_file(file_name: []const u8, bytes: []u8) !File.Index { |
| 434 | return file_index; | 430 | return file_index; |
| 435 | } | 431 | } |
| 436 | 432 | ||
| 437 | fn parse(source: []u8) Oom!Ast { | 433 | /// Parses a file and returns its `Ast`. If the file cannot be parsed, returns |
| 434 | /// the `Ast` of an empty file, so that the rest of the Autodoc logic does not | ||
| 435 | /// need to handle parse errors. | ||
| 436 | fn parse(file_name: []const u8, source: []u8) Oom!Ast { | ||
| 438 | // Require every source file to end with a newline so that Zig's tokenizer | 437 | // Require every source file to end with a newline so that Zig's tokenizer |
| 439 | // can continue to require null termination and Autodoc implementation can | 438 | // can continue to require null termination and Autodoc implementation can |
| 440 | // avoid copying source bytes from the decompressed tar file buffer. | 439 | // avoid copying source bytes from the decompressed tar file buffer. |
| 441 | const adjusted_source: [:0]const u8 = s: { | 440 | const adjusted_source: [:0]const u8 = s: { |
| 442 | if (source.len == 0) | 441 | if (source.len == 0) |
| 443 | break :s ""; | 442 | break :s ""; |
| 444 | 443 | if (source[source.len - 1] != '\n') { | |
| 445 | assert(source[source.len - 1] == '\n'); | 444 | log.err("{s}: expected newline at end of file", .{file_name}); |
| 445 | break :s ""; | ||
| 446 | } | ||
| 446 | source[source.len - 1] = 0; | 447 | source[source.len - 1] = 0; |
| 447 | break :s source[0 .. source.len - 1 :0]; | 448 | break :s source[0 .. source.len - 1 :0]; |
| 448 | }; | 449 | }; |
| 449 | 450 | ||
| 450 | return Ast.parse(gpa, adjusted_source, .zig); | 451 | var ast = try Ast.parse(gpa, adjusted_source, .zig); |
| 452 | if (ast.errors.len > 0) { | ||
| 453 | defer ast.deinit(gpa); | ||
| 454 | |||
| 455 | const token_offsets = ast.tokens.items(.start); | ||
| 456 | var rendered_err: std.ArrayListUnmanaged(u8) = .{}; | ||
| 457 | defer rendered_err.deinit(gpa); | ||
| 458 | for (ast.errors) |err| { | ||
| 459 | const err_offset = token_offsets[err.token] + ast.errorOffset(err); | ||
| 460 | const err_loc = std.zig.findLineColumn(ast.source, err_offset); | ||
| 461 | rendered_err.clearRetainingCapacity(); | ||
| 462 | try ast.renderError(err, rendered_err.writer(gpa)); | ||
| 463 | log.err("{s}:{}:{}: {s}", .{ file_name, err_loc.line + 1, err_loc.column + 1, rendered_err.items }); | ||
| 464 | } | ||
| 465 | return Ast.parse(gpa, "", .zig); | ||
| 466 | } | ||
| 467 | return ast; | ||
| 451 | } | 468 | } |
| 452 | 469 | ||
| 453 | pub const Scope = struct { | 470 | pub const Scope = struct { |
lib/docs/wasm/main.zig+17-20| ... | @@ -14,8 +14,15 @@ const missing_feature_url_escape = @import("html_render.zig").missing_feature_ur | ... | @@ -14,8 +14,15 @@ const missing_feature_url_escape = @import("html_render.zig").missing_feature_ur |
| 14 | const gpa = std.heap.wasm_allocator; | 14 | const gpa = std.heap.wasm_allocator; |
| 15 | 15 | ||
| 16 | const js = struct { | 16 | const js = struct { |
| 17 | extern "js" fn log(ptr: [*]const u8, len: usize) void; | 17 | /// Keep in sync with the `LOG_` constants in `main.js`. |
| 18 | extern "js" fn panic(ptr: [*]const u8, len: usize) noreturn; | 18 | const LogLevel = enum(u8) { |
| 19 | err, | ||
| 20 | warn, | ||
| 21 | info, | ||
| 22 | debug, | ||
| 23 | }; | ||
| 24 | |||
| 25 | extern "js" fn log(level: LogLevel, ptr: [*]const u8, len: usize) void; | ||
| 19 | }; | 26 | }; |
| 20 | 27 | ||
| 21 | pub const std_options: std.Options = .{ | 28 | pub const std_options: std.Options = .{ |
| ... | @@ -36,14 +43,13 @@ fn logFn( | ... | @@ -36,14 +43,13 @@ fn logFn( |
| 36 | comptime format: []const u8, | 43 | comptime format: []const u8, |
| 37 | args: anytype, | 44 | args: anytype, |
| 38 | ) void { | 45 | ) void { |
| 39 | const level_txt = comptime message_level.asText(); | 46 | const prefix = if (scope == .default) "" else @tagName(scope) ++ ": "; |
| 40 | const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): "; | ||
| 41 | var buf: [500]u8 = undefined; | 47 | var buf: [500]u8 = undefined; |
| 42 | const line = std.fmt.bufPrint(&buf, level_txt ++ prefix2 ++ format, args) catch l: { | 48 | const line = std.fmt.bufPrint(&buf, prefix ++ format, args) catch l: { |
| 43 | buf[buf.len - 3 ..][0..3].* = "...".*; | 49 | buf[buf.len - 3 ..][0..3].* = "...".*; |
| 44 | break :l &buf; | 50 | break :l &buf; |
| 45 | }; | 51 | }; |
| 46 | js.log(line.ptr, line.len); | 52 | js.log(@field(js.LogLevel, @tagName(message_level)), line.ptr, line.len); |
| 47 | } | 53 | } |
| 48 | 54 | ||
| 49 | export fn alloc(n: usize) [*]u8 { | 55 | export fn alloc(n: usize) [*]u8 { |
| ... | @@ -56,7 +62,7 @@ export fn unpack(tar_ptr: [*]u8, tar_len: usize) void { | ... | @@ -56,7 +62,7 @@ export fn unpack(tar_ptr: [*]u8, tar_len: usize) void { |
| 56 | //log.debug("received {d} bytes of tar file", .{tar_bytes.len}); | 62 | //log.debug("received {d} bytes of tar file", .{tar_bytes.len}); |
| 57 | 63 | ||
| 58 | unpackInner(tar_bytes) catch |err| { | 64 | unpackInner(tar_bytes) catch |err| { |
| 59 | fatal("unable to unpack tar: {s}", .{@errorName(err)}); | 65 | std.debug.panic("unable to unpack tar: {s}", .{@errorName(err)}); |
| 60 | }; | 66 | }; |
| 61 | } | 67 | } |
| 62 | 68 | ||
| ... | @@ -514,7 +520,7 @@ export fn decl_fn_proto_html(decl_index: Decl.Index, linkify_fn_name: bool) Stri | ... | @@ -514,7 +520,7 @@ export fn decl_fn_proto_html(decl_index: Decl.Index, linkify_fn_name: bool) Stri |
| 514 | .collapse_whitespace = true, | 520 | .collapse_whitespace = true, |
| 515 | .fn_link = if (linkify_fn_name) decl_index else .none, | 521 | .fn_link = if (linkify_fn_name) decl_index else .none, |
| 516 | }) catch |err| { | 522 | }) catch |err| { |
| 517 | fatal("unable to render source: {s}", .{@errorName(err)}); | 523 | std.debug.panic("unable to render source: {s}", .{@errorName(err)}); |
| 518 | }; | 524 | }; |
| 519 | return String.init(string_result.items); | 525 | return String.init(string_result.items); |
| 520 | } | 526 | } |
| ... | @@ -524,7 +530,7 @@ export fn decl_source_html(decl_index: Decl.Index) String { | ... | @@ -524,7 +530,7 @@ export fn decl_source_html(decl_index: Decl.Index) String { |
| 524 | 530 | ||
| 525 | string_result.clearRetainingCapacity(); | 531 | string_result.clearRetainingCapacity(); |
| 526 | fileSourceHtml(decl.file, &string_result, decl.ast_node, .{}) catch |err| { | 532 | fileSourceHtml(decl.file, &string_result, decl.ast_node, .{}) catch |err| { |
| 527 | fatal("unable to render source: {s}", .{@errorName(err)}); | 533 | std.debug.panic("unable to render source: {s}", .{@errorName(err)}); |
| 528 | }; | 534 | }; |
| 529 | return String.init(string_result.items); | 535 | return String.init(string_result.items); |
| 530 | } | 536 | } |
| ... | @@ -536,7 +542,7 @@ export fn decl_doctest_html(decl_index: Decl.Index) String { | ... | @@ -536,7 +542,7 @@ export fn decl_doctest_html(decl_index: Decl.Index) String { |
| 536 | 542 | ||
| 537 | string_result.clearRetainingCapacity(); | 543 | string_result.clearRetainingCapacity(); |
| 538 | fileSourceHtml(decl.file, &string_result, doctest_ast_node, .{}) catch |err| { | 544 | fileSourceHtml(decl.file, &string_result, doctest_ast_node, .{}) catch |err| { |
| 539 | fatal("unable to render source: {s}", .{@errorName(err)}); | 545 | std.debug.panic("unable to render source: {s}", .{@errorName(err)}); |
| 540 | }; | 546 | }; |
| 541 | return String.init(string_result.items); | 547 | return String.init(string_result.items); |
| 542 | } | 548 | } |
| ... | @@ -740,7 +746,7 @@ export fn decl_type_html(decl_index: Decl.Index) String { | ... | @@ -740,7 +746,7 @@ export fn decl_type_html(decl_index: Decl.Index) String { |
| 740 | .skip_comments = true, | 746 | .skip_comments = true, |
| 741 | .collapse_whitespace = true, | 747 | .collapse_whitespace = true, |
| 742 | }) catch |e| { | 748 | }) catch |e| { |
| 743 | fatal("unable to render html: {s}", .{@errorName(e)}); | 749 | std.debug.panic("unable to render html: {s}", .{@errorName(e)}); |
| 744 | }; | 750 | }; |
| 745 | string_result.appendSlice(gpa, "</code>") catch @panic("OOM"); | 751 | string_result.appendSlice(gpa, "</code>") catch @panic("OOM"); |
| 746 | break :t; | 752 | break :t; |
| ... | @@ -791,15 +797,6 @@ fn unpackInner(tar_bytes: []u8) !void { | ... | @@ -791,15 +797,6 @@ fn unpackInner(tar_bytes: []u8) !void { |
| 791 | } | 797 | } |
| 792 | } | 798 | } |
| 793 | 799 | ||
| 794 | fn fatal(comptime format: []const u8, args: anytype) noreturn { | ||
| 795 | var buf: [500]u8 = undefined; | ||
| 796 | const line = std.fmt.bufPrint(&buf, format, args) catch l: { | ||
| 797 | buf[buf.len - 3 ..][0..3].* = "...".*; | ||
| 798 | break :l &buf; | ||
| 799 | }; | ||
| 800 | js.panic(line.ptr, line.len); | ||
| 801 | } | ||
| 802 | |||
| 803 | fn ascii_lower(bytes: []u8) void { | 800 | fn ascii_lower(bytes: []u8) void { |
| 804 | for (bytes) |*b| b.* = std.ascii.toLower(b.*); | 801 | for (bytes) |*b| b.* = std.ascii.toLower(b.*); |
| 805 | } | 802 | } |