authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-19 03:03:20-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-19 03:21:47-05:00
logea623f2d397941daad20eec7114cac01a5f86d24
tree5e567db20d2ebbcf617f22d2107c58c5b8ede811
parent4b64c777ee465abb1f4a6bf2d31ba39805d5fa54

all doc code examples are now tested

improve color scheme of docs make docs depend on no external files fix broken example code in docs closes #465

5 files changed, 1390 insertions(+), 941 deletions(-)

doc/docgen.zig+400-46
......@@ -1,12 +1,16 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const io = std.io;
34const os = std.os;
45const warn = std.debug.warn;
56const mem = std.mem;
7const assert = std.debug.assert;
68
79const max_doc_file_size = 10 * 1024 * 1024;
810
911const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt();
12const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();
13const tmp_dir_name = "docgen_tmp";
1014
1115pub fn main() -> %void {
1216 // TODO use a more general purpose allocator here
......@@ -43,6 +47,8 @@ pub fn main() -> %void {
4347 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
4448 var toc = try genToc(allocator, &tokenizer);
4549
50 try os.makePath(allocator, tmp_dir_name);
51 defer os.deleteTree(allocator, tmp_dir_name) catch {};
4652 try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe);
4753 try buffered_out_stream.flush();
4854}
......@@ -68,6 +74,7 @@ const Tokenizer = struct {
6874 index: usize,
6975 state: State,
7076 source_file_name: []const u8,
77 code_node_count: usize,
7178
7279 const State = enum {
7380 Start,
......@@ -83,6 +90,7 @@ const Tokenizer = struct {
8390 .index = 0,
8491 .state = State.Start,
8592 .source_file_name = source_file_name,
93 .code_node_count = 0,
8694 };
8795 }
8896
......@@ -251,15 +259,27 @@ const SeeAlsoItem = struct {
251259 token: Token,
252260};
253261
262const ExpectedOutcome = enum {
263 Succeed,
264 Fail,
265};
266
254267const Code = struct {
255268 id: Id,
256269 name: []const u8,
257270 source_token: Token,
271 is_inline: bool,
272 mode: builtin.Mode,
273 link_objects: []const []const u8,
274 target_windows: bool,
275 link_libc: bool,
258276
259 const Id = enum {
277 const Id = union(enum) {
260278 Test,
261 Exe,
262 Error,
279 TestError: []const u8,
280 TestSafety: []const u8,
281 Exe: ExpectedOutcome,
282 Obj,
263283 };
264284};
265285
......@@ -401,28 +421,68 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) -> %Toc {
401421 }
402422 const code_kind_str = tokenizer.buffer[code_kind_tok.start..code_kind_tok.end];
403423 var code_kind_id: Code.Id = undefined;
424 var is_inline = false;
404425 if (mem.eql(u8, code_kind_str, "exe")) {
405 code_kind_id = Code.Id.Exe;
426 code_kind_id = Code.Id { .Exe = ExpectedOutcome.Succeed };
427 } else if (mem.eql(u8, code_kind_str, "exe_err")) {
428 code_kind_id = Code.Id { .Exe = ExpectedOutcome.Fail };
406429 } else if (mem.eql(u8, code_kind_str, "test")) {
407430 code_kind_id = Code.Id.Test;
408 } else if (mem.eql(u8, code_kind_str, "error")) {
409 code_kind_id = Code.Id.Error;
431 } else if (mem.eql(u8, code_kind_str, "test_err")) {
432 code_kind_id = Code.Id { .TestError = name};
433 name = "test";
434 } else if (mem.eql(u8, code_kind_str, "test_safety")) {
435 code_kind_id = Code.Id { .TestSafety = name};
436 name = "test";
437 } else if (mem.eql(u8, code_kind_str, "obj")) {
438 code_kind_id = Code.Id.Obj;
439 } else if (mem.eql(u8, code_kind_str, "syntax")) {
440 code_kind_id = Code.Id.Obj;
441 is_inline = true;
410442 } else {
411443 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", code_kind_str);
412444 }
413 const source_token = try eatToken(tokenizer, Token.Id.Content);
414 _ = try eatToken(tokenizer, Token.Id.BracketOpen);
415 const end_code_tag = try eatToken(tokenizer, Token.Id.TagContent);
416 const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end];
417 if (!mem.eql(u8, end_tag_name, "code_end")) {
418 return parseError(tokenizer, end_code_tag, "expected code_end token");
419 }
420 _ = try eatToken(tokenizer, Token.Id.BracketClose);
421 try nodes.append(Node {.Code = Code{
445
446 var mode = builtin.Mode.Debug;
447 var link_objects = std.ArrayList([]const u8).init(allocator);
448 defer link_objects.deinit();
449 var target_windows = false;
450 var link_libc = false;
451
452 const source_token = while (true) {
453 const content_tok = try eatToken(tokenizer, Token.Id.Content);
454 _ = try eatToken(tokenizer, Token.Id.BracketOpen);
455 const end_code_tag = try eatToken(tokenizer, Token.Id.TagContent);
456 const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end];
457 if (mem.eql(u8, end_tag_name, "code_release_fast")) {
458 mode = builtin.Mode.ReleaseFast;
459 } else if (mem.eql(u8, end_tag_name, "code_link_object")) {
460 _ = try eatToken(tokenizer, Token.Id.Separator);
461 const obj_tok = try eatToken(tokenizer, Token.Id.TagContent);
462 try link_objects.append(tokenizer.buffer[obj_tok.start..obj_tok.end]);
463 } else if (mem.eql(u8, end_tag_name, "target_windows")) {
464 target_windows = true;
465 } else if (mem.eql(u8, end_tag_name, "link_libc")) {
466 link_libc = true;
467 } else if (mem.eql(u8, end_tag_name, "code_end")) {
468 _ = try eatToken(tokenizer, Token.Id.BracketClose);
469 break content_tok;
470 } else {
471 return parseError(tokenizer, end_code_tag, "invalid token inside code_begin: {}", end_tag_name);
472 }
473 _ = try eatToken(tokenizer, Token.Id.BracketClose);
474 } else unreachable; // TODO issue #707
475 try nodes.append(Node {.Code = Code {
422476 .id = code_kind_id,
423477 .name = name,
424478 .source_token = source_token,
479 .is_inline = is_inline,
480 .mode = mode,
481 .link_objects = link_objects.toOwnedSlice(),
482 .target_windows = target_windows,
483 .link_libc = link_libc,
425484 }});
485 tokenizer.code_node_count += 1;
426486 } else {
427487 return parseError(tokenizer, tag_token, "unrecognized tag name: {}", tag_name);
428488 }
......@@ -476,9 +536,116 @@ fn escapeHtml(allocator: &mem.Allocator, input: []const u8) -> %[]u8 {
476536 return buf.toOwnedSlice();
477537}
478538
539//#define VT_RED "\x1b[31;1m"
540//#define VT_GREEN "\x1b[32;1m"
541//#define VT_CYAN "\x1b[36;1m"
542//#define VT_WHITE "\x1b[37;1m"
543//#define VT_BOLD "\x1b[0;1m"
544//#define VT_RESET "\x1b[0m"
545
546const TermState = enum {
547 Start,
548 Escape,
549 LBracket,
550 Number,
551 AfterNumber,
552 Arg,
553 ArgNumber,
554 ExpectEnd,
555};
556
557error UnsupportedEscape;
558
559test "term color" {
560 const input_bytes = "A\x1b[32;1mgreen\x1b[0mB";
561 const result = try termColor(std.debug.global_allocator, input_bytes);
562 assert(mem.eql(u8, result, "A<span class=\"t32\">green</span>B"));
563}
564
565fn termColor(allocator: &mem.Allocator, input: []const u8) -> %[]u8 {
566 var buf = try std.Buffer.initSize(allocator, 0);
567 defer buf.deinit();
568
569 var buf_adapter = io.BufferOutStream.init(&buf);
570 var out = &buf_adapter.stream;
571 var number_start_index: usize = undefined;
572 var first_number: usize = undefined;
573 var second_number: usize = undefined;
574 var i: usize = 0;
575 var state = TermState.Start;
576 var open_span_count: usize = 0;
577 while (i < input.len) : (i += 1) {
578 const c = input[i];
579 switch (state) {
580 TermState.Start => switch (c) {
581 '\x1b' => state = TermState.Escape,
582 else => try out.writeByte(c),
583 },
584 TermState.Escape => switch (c) {
585 '[' => state = TermState.LBracket,
586 else => return error.UnsupportedEscape,
587 },
588 TermState.LBracket => switch (c) {
589 '0'...'9' => {
590 number_start_index = i;
591 state = TermState.Number;
592 },
593 else => return error.UnsupportedEscape,
594 },
595 TermState.Number => switch (c) {
596 '0'...'9' => {},
597 else => {
598 first_number = std.fmt.parseInt(usize, input[number_start_index..i], 10) catch unreachable;
599 second_number = 0;
600 state = TermState.AfterNumber;
601 i -= 1;
602 },
603 },
604
605 TermState.AfterNumber => switch (c) {
606 ';' => state = TermState.Arg,
607 else => {
608 state = TermState.ExpectEnd;
609 i -= 1;
610 },
611 },
612 TermState.Arg => switch (c) {
613 '0'...'9' => {
614 number_start_index = i;
615 state = TermState.ArgNumber;
616 },
617 else => return error.UnsupportedEscape,
618 },
619 TermState.ArgNumber => switch (c) {
620 '0'...'9' => {},
621 else => {
622 second_number = std.fmt.parseInt(usize, input[number_start_index..i], 10) catch unreachable;
623 state = TermState.ExpectEnd;
624 i -= 1;
625 },
626 },
627 TermState.ExpectEnd => switch (c) {
628 'm' => {
629 state = TermState.Start;
630 while (open_span_count != 0) : (open_span_count -= 1) {
631 try out.write("</span>");
632 }
633 if (first_number != 0 or second_number != 0) {
634 try out.print("<span class=\"t{}_{}\">", first_number, second_number);
635 open_span_count += 1;
636 }
637 },
638 else => return error.UnsupportedEscape,
639 },
640 }
641 }
642 return buf.toOwnedSlice();
643}
644
479645error ExampleFailedToCompile;
480646
481647fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io.OutStream, zig_exe: []const u8) -> %void {
648 var code_progress_index: usize = 0;
482649 for (toc.nodes) |node| {
483650 switch (node) {
484651 Node.Content => |data| {
......@@ -502,65 +669,252 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io
502669 try out.write("</ul>\n");
503670 },
504671 Node.Code => |code| {
672 code_progress_index += 1;
673 warn("docgen example code {}/{}...", code_progress_index, tokenizer.code_node_count);
674
505675 const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];
506676 const trimmed_raw_source = mem.trim(u8, raw_source, " \n");
507677 const escaped_source = try escapeHtml(allocator, trimmed_raw_source);
678 if (!code.is_inline) {
679 try out.print("<p class=\"file\">{}.zig</p>", code.name);
680 }
508681 try out.print("<pre><code class=\"zig\">{}</code></pre>", escaped_source);
509 const tmp_dir_name = "docgen_tmp";
510 try os.makePath(allocator, tmp_dir_name);
511682 const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
512 const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);
513683 const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);
514 const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext);
515684 try io.writeFile(tmp_source_file_name, trimmed_raw_source, null);
516685
517686 switch (code.id) {
518 Code.Id.Exe => {
519 {
520 const args = [][]const u8 {zig_exe, "build-exe", tmp_source_file_name, "--output", tmp_bin_file_name};
521 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);
687 Code.Id.Exe => |expected_outcome| {
688 const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);
689 const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext);
690 var build_args = std.ArrayList([]const u8).init(allocator);
691 defer build_args.deinit();
692 try build_args.appendSlice([][]const u8 {zig_exe,
693 "build-exe", tmp_source_file_name,
694 "--output", tmp_bin_file_name,
695 });
696 try out.print("<pre><code class=\"shell\">$ zig build-exe {}.zig", code.name);
697 switch (code.mode) {
698 builtin.Mode.Debug => {},
699 builtin.Mode.ReleaseSafe => {
700 try build_args.append("--release-safe");
701 try out.print(" --release-safe");
702 },
703 builtin.Mode.ReleaseFast => {
704 try build_args.append("--release-fast");
705 try out.print(" --release-fast");
706 },
707 }
708 for (code.link_objects) |link_object| {
709 const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext);
710 const full_path_object = try os.path.join(allocator, tmp_dir_name, name_with_ext);
711 try build_args.append("--object");
712 try build_args.append(full_path_object);
713 try out.print(" --object {}", name_with_ext);
714 }
715 if (code.link_libc) {
716 try build_args.append("--library");
717 try build_args.append("c");
718 try out.print(" --library c");
719 }
720 _ = exec(allocator, build_args.toSliceConst()) catch return parseError(
721 tokenizer, code.source_token, "example failed to compile");
722
723 const run_args = [][]const u8 {tmp_bin_file_name};
724
725 const result = if (expected_outcome == ExpectedOutcome.Fail) blk: {
726 const result = try os.ChildProcess.exec(allocator, run_args, null, null, max_doc_file_size);
522727 switch (result.term) {
523728 os.ChildProcess.Term.Exited => |exit_code| {
524 if (exit_code != 0) {
525 warn("{}\nThe following command exited with code {}:\n", result.stderr, exit_code);
526 for (args) |arg| warn("{} ", arg) else warn("\n");
527 return parseError(tokenizer, code.source_token, "example failed to compile");
729 if (exit_code == 0) {
730 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
731 for (run_args) |arg| warn("{} ", arg) else warn("\n");
732 return parseError(tokenizer, code.source_token, "example incorrectly compiled");
528733 }
529734 },
530 else => {
531 warn("{}\nThe following command crashed:\n", result.stderr);
532 for (args) |arg| warn("{} ", arg) else warn("\n");
533 return parseError(tokenizer, code.source_token, "example failed to compile");
534 },
735 else => {},
535736 }
737 break :blk result;
738 } else blk: {
739 break :blk exec(allocator, run_args) catch return parseError(
740 tokenizer, code.source_token, "example crashed");
741 };
742
743
744 const escaped_stderr = try escapeHtml(allocator, result.stderr);
745 const escaped_stdout = try escapeHtml(allocator, result.stdout);
746
747 const colored_stderr = try termColor(allocator, escaped_stderr);
748 const colored_stdout = try termColor(allocator, escaped_stdout);
749
750 try out.print("\n$ ./{}\n{}{}</code></pre>\n", code.name, colored_stdout, colored_stderr);
751 },
752 Code.Id.Test => {
753 var test_args = std.ArrayList([]const u8).init(allocator);
754 defer test_args.deinit();
755
756 try test_args.appendSlice([][]const u8 {zig_exe, "test", tmp_source_file_name});
757 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
758 switch (code.mode) {
759 builtin.Mode.Debug => {},
760 builtin.Mode.ReleaseSafe => {
761 try test_args.append("--release-safe");
762 try out.print(" --release-safe");
763 },
764 builtin.Mode.ReleaseFast => {
765 try test_args.append("--release-fast");
766 try out.print(" --release-fast");
767 },
768 }
769 if (code.target_windows) {
770 try test_args.appendSlice([][]const u8{
771 "--target-os", "windows",
772 "--target-arch", "x86_64",
773 "--target-environ", "msvc",
774 });
775 }
776 const result = exec(allocator, test_args.toSliceConst()) catch return parseError(
777 tokenizer, code.source_token, "test failed");
778 const escaped_stderr = try escapeHtml(allocator, result.stderr);
779 const escaped_stdout = try escapeHtml(allocator, result.stdout);
780 try out.print("\n{}{}</code></pre>\n", escaped_stderr, escaped_stdout);
781 },
782 Code.Id.TestError => |error_match| {
783 var test_args = std.ArrayList([]const u8).init(allocator);
784 defer test_args.deinit();
785
786 try test_args.appendSlice([][]const u8 {zig_exe, "test", "--color", "on", tmp_source_file_name});
787 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
788 switch (code.mode) {
789 builtin.Mode.Debug => {},
790 builtin.Mode.ReleaseSafe => {
791 try test_args.append("--release-safe");
792 try out.print(" --release-safe");
793 },
794 builtin.Mode.ReleaseFast => {
795 try test_args.append("--release-fast");
796 try out.print(" --release-fast");
797 },
536798 }
537 const args = [][]const u8 {tmp_bin_file_name};
538 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);
799 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, null, max_doc_file_size);
539800 switch (result.term) {
540801 os.ChildProcess.Term.Exited => |exit_code| {
541 if (exit_code != 0) {
542 warn("The following command exited with code {}:\n", exit_code);
543 for (args) |arg| warn("{} ", arg) else warn("\n");
544 return parseError(tokenizer, code.source_token, "example exited with code {}", exit_code);
802 if (exit_code == 0) {
803 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
804 for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
805 return parseError(tokenizer, code.source_token, "example incorrectly compiled");
545806 }
546807 },
547808 else => {
548 warn("The following command crashed:\n");
549 for (args) |arg| warn("{} ", arg) else warn("\n");
550 return parseError(tokenizer, code.source_token, "example crashed");
809 warn("{}\nThe following command crashed:\n", result.stderr);
810 for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
811 return parseError(tokenizer, code.source_token, "example compile crashed");
551812 },
552813 }
553 try out.print("<pre><code class=\"sh\">$ zig build-exe {}.zig\n$ ./{}\n{}{}</code></pre>\n", code.name, code.name, result.stderr, result.stdout);
814 if (mem.indexOf(u8, result.stderr, error_match) == null) {
815 warn("{}\nExpected to find '{}' in stderr", result.stderr, error_match);
816 return parseError(tokenizer, code.source_token, "example did not have expected compile error");
817 }
818 const escaped_stderr = try escapeHtml(allocator, result.stderr);
819 const colored_stderr = try termColor(allocator, escaped_stderr);
820 try out.print("\n{}</code></pre>\n", colored_stderr);
554821 },
555 Code.Id.Test => {
556 @panic("TODO");
822
823 Code.Id.TestSafety => |error_match| {
824 var test_args = std.ArrayList([]const u8).init(allocator);
825 defer test_args.deinit();
826
827 try test_args.appendSlice([][]const u8 {zig_exe, "test", tmp_source_file_name});
828 switch (code.mode) {
829 builtin.Mode.Debug => {},
830 builtin.Mode.ReleaseSafe => try test_args.append("--release-safe"),
831 builtin.Mode.ReleaseFast => try test_args.append("--release-fast"),
832 }
833
834 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, null, max_doc_file_size);
835 switch (result.term) {
836 os.ChildProcess.Term.Exited => |exit_code| {
837 if (exit_code == 0) {
838 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
839 for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
840 return parseError(tokenizer, code.source_token, "example test incorrectly succeeded");
841 }
842 },
843 else => {
844 warn("{}\nThe following command crashed:\n", result.stderr);
845 for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
846 return parseError(tokenizer, code.source_token, "example compile crashed");
847 },
848 }
849 if (mem.indexOf(u8, result.stderr, error_match) == null) {
850 warn("{}\nExpected to find '{}' in stderr", result.stderr, error_match);
851 return parseError(tokenizer, code.source_token, "example did not have expected debug safety error message");
852 }
853 const escaped_stderr = try escapeHtml(allocator, result.stderr);
854 const colored_stderr = try termColor(allocator, escaped_stderr);
855 try out.print("<pre><code class=\"shell\">$ zig test {}.zig\n{}</code></pre>\n", code.name, colored_stderr);
557856 },
558 Code.Id.Error => {
559 @panic("TODO");
857 Code.Id.Obj => {
858 const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, obj_ext);
859 const tmp_obj_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_obj_ext);
860 var build_args = std.ArrayList([]const u8).init(allocator);
861 defer build_args.deinit();
862
863 try build_args.appendSlice([][]const u8 {zig_exe, "build-obj", tmp_source_file_name,
864 "--output", tmp_obj_file_name});
865
866 if (!code.is_inline) {
867 try out.print("<pre><code class=\"shell\">$ zig build-obj {}.zig", code.name);
868 }
869
870 switch (code.mode) {
871 builtin.Mode.Debug => {},
872 builtin.Mode.ReleaseSafe => {
873 try build_args.append("--release-safe");
874 if (!code.is_inline) {
875 try out.print(" --release-safe");
876 }
877 },
878 builtin.Mode.ReleaseFast => {
879 try build_args.append("--release-fast");
880 if (!code.is_inline) {
881 try out.print(" --release-fast");
882 }
883 },
884 }
885
886 _ = exec(allocator, build_args.toSliceConst()) catch return parseError(
887 tokenizer, code.source_token, "example failed to compile");
888 if (!code.is_inline) {
889 try out.print("</code></pre>\n");
890 }
560891 },
561892 }
893 warn("OK\n");
562894 },
563895 }
564896 }
565897
566898}
899
900error ChildCrashed;
901error ChildExitError;
902
903fn exec(allocator: &mem.Allocator, args: []const []const u8) -> %os.ChildProcess.ExecResult {
904 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);
905 switch (result.term) {
906 os.ChildProcess.Term.Exited => |exit_code| {
907 if (exit_code != 0) {
908 warn("{}\nThe following command exited with code {}:\n", result.stderr, exit_code);
909 for (args) |arg| warn("{} ", arg) else warn("\n");
910 return error.ChildExitError;
911 }
912 },
913 else => {
914 warn("{}\nThe following command crashed:\n", result.stderr);
915 for (args) |arg| warn("{} ", arg) else warn("\n");
916 return error.ChildCrashed;
917 },
918 }
919 return result;
920}
doc/langref.html.in+981-886
......@@ -4,7 +4,9 @@
44 <meta charset="utf-8">
55 <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
66 <title>Documentation - The Zig Programming Language</title>
7 <link rel="stylesheet" type="text/css" href="highlight/styles/default.css">
7 <style type="text/css">
8.hljs{display:block;overflow-x:auto;padding:0.5em;color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:bold}.hljs-number,.hljs-literal,.hljs-variable,.hljs-template-variable,.hljs-tag .hljs-attr{color:#008080}.hljs-string,.hljs-doctag{color:#d14}.hljs-title,.hljs-section,.hljs-selector-id{color:#900;font-weight:bold}.hljs-subst{font-weight:normal}.hljs-type,.hljs-class .hljs-title{color:#458;font-weight:bold}.hljs-tag,.hljs-name,.hljs-attribute{color:#000080;font-weight:normal}.hljs-regexp,.hljs-link{color:#009926}.hljs-symbol,.hljs-bullet{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:bold}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}
9 </style>
810 <style type="text/css">
911 table, th, td {
1012 border-collapse: collapse;
......@@ -13,6 +15,27 @@
1315 th, td {
1416 padding: 0.1em;
1517 }
18 .t0_1, .t37, .t37_1 {
19 font-weight: bold;
20 }
21 .t2_0 {
22 color: grey;
23 }
24 .t31_1 {
25 color: red;
26 }
27 .t32_1 {
28 color: green;
29 }
30 .t36_1 {
31 color: #0086b3;
32 }
33 .file {
34 text-decoration: underline;
35 }
36 pre {
37 font-size: 12pt;
38 }
1639 @media screen and (min-width: 28.75em) {
1740 #nav {
1841 width: 20em;
......@@ -53,6 +76,10 @@
5376 If you search for something specific in this documentation and do not find it,
5477 please <a href="https://github.com/zig-lang/www.ziglang.org/issues/new?title=I%20searched%20for%20___%20in%20the%20docs%20and%20didn%27t%20find%20it">file an issue</a> or <a href="https://webchat.freenode.net/?channels=%23zig">say something on IRC</a>.
5578 </p>
79 <p>
80 The code samples in this document are compiled and tested as part of the main test suite of Zig.
81 This HTML document depends on no external files, so you can use it offline.
82 </p>
5683 {#header_close#}
5784 {#header_open|Hello World#}
5885
......@@ -399,7 +426,8 @@ pub fn main() -> %void {
399426 {#see_also|Nullables|this#}
400427 {#header_close#}
401428 {#header_open|String Literals#}
402 <pre><code class="zig">const assert = @import("std").debug.assert;
429 {#code_begin|test#}
430const assert = @import("std").debug.assert;
403431const mem = @import("std").mem;
404432
405433test "string literals" {
......@@ -413,11 +441,10 @@ test "string literals" {
413441
414442 // A C string literal is a null terminated pointer.
415443 const null_terminated_bytes = c"hello";
416 assert(@typeOf(null_terminated_bytes) == &amp;const u8);
444 assert(@typeOf(null_terminated_bytes) == &const u8);
417445 assert(null_terminated_bytes[5] == 0);
418}</code></pre>
419 <pre><code class="sh">$ zig test string_literals.zig
420Test 1/1 string literals...OK</code></pre>
446}
447 {#code_end#}
421448 {#see_also|Arrays|Zig Test#}
422449 {#header_open|Escape Sequences#}
423450 <table>
......@@ -477,25 +504,29 @@ Test 1/1 string literals...OK</code></pre>
477504 However, if the next line begins with <code>\\</code> then a newline is appended and
478505 the string literal continues.
479506 </p>
480 <pre><code class="zig">const hello_world_in_c =
481 \\#include &lt;stdio.h&gt;
507 {#code_begin|syntax#}
508const hello_world_in_c =
509 \\#include <stdio.h>
482510 \\
483511 \\int main(int argc, char **argv) {
484512 \\ printf("hello world\n");
485513 \\ return 0;
486514 \\}
487;</code></pre>
515;
516 {#code_end#}
488517 <p>
489518 For a multiline C string literal, prepend <code>c</code> to each <code>\\</code>:
490519 </p>
491 <pre><code class="zig">const c_string_literal =
492 c\\#include &lt;stdio.h&gt;
520 {#code_begin|syntax#}
521const c_string_literal =
522 c\\#include <stdio.h>
493523 c\\
494524 c\\int main(int argc, char **argv) {
495525 c\\ printf("hello world\n");
496526 c\\ return 0;
497527 c\\}
498;</code></pre>
528;
529 {#code_end#}
499530 <p>
500531 In this example the variable <code>c_string_literal</code> has type <code>&amp;const char</code> and
501532 has a terminating null byte.
......@@ -505,7 +536,8 @@ Test 1/1 string literals...OK</code></pre>
505536 {#header_close#}
506537 {#header_open|Assignment#}
507538 <p>Use <code>const</code> to assign a value to an identifier:</p>
508 <pre><code class="zig">const x = 1234;
539 {#code_begin|test_err|cannot assign to constant#}
540const x = 1234;
509541
510542fn foo() {
511543 // It works at global scope as well as inside functions.
......@@ -517,13 +549,11 @@ fn foo() {
517549
518550test "assignment" {
519551 foo();
520}</code></pre>
521 <pre><code class="sh">$ zig test test.zig
522test.zig:8:7: error: cannot assign to constant
523 y += 1;
524 ^</code></pre>
552}
553 {#code_end#}
525554 <p>If you need a variable that you can modify, use <code>var</code>:</p>
526 <pre><code class="zig">const assert = @import("std").debug.assert;
555 {#code_begin|test#}
556const assert = @import("std").debug.assert;
527557
528558test "var" {
529559 var y: i32 = 5678;
......@@ -531,38 +561,37 @@ test "var" {
531561 y += 1;
532562
533563 assert(y == 5679);
534}</code></pre>
535 <pre><code class="sh">$ zig test test.zig
536Test 1/1 assignment...OK</code></pre>
564}
565 {#code_end#}
537566 <p>Variables must be initialized:</p>
538 <pre><code class="zig">test "initialization" {
567 {#code_begin|test_err#}
568test "initialization" {
539569 var x: i32;
540570
541571 x = 1;
542}</code></pre>
543 <pre><code class="sh">$ zig test test.zig
544test.zig:3:5: error: variables must be initialized
545 var x: i32;
546 ^</code></pre>
572}
573 {#code_end#}
547574 <p>Use <code>undefined</code> to leave variables uninitialized:</p>
548 <pre><code class="zig">const assert = @import("std").debug.assert;
575 {#code_begin|test#}
576const assert = @import("std").debug.assert;
549577
550578test "init with undefined" {
551579 var x: i32 = undefined;
552580 x = 1;
553581 assert(x == 1);
554}</code></pre>
555 <pre><code class="sh">$ zig test test.zig
556Test 1/1 init with undefined...OK</code></pre>
582}
583 {#code_end#}
557584 {#header_close#}
558585 {#header_close#}
559586 {#header_open|Integers#}
560587 {#header_open|Integer Literals#}
561 <pre><code class="zig">const decimal_int = 98222;
588 {#code_begin|syntax#}
589const decimal_int = 98222;
562590const hex_int = 0xff;
563591const another_hex_int = 0xFF;
564592const octal_int = 0o755;
565const binary_int = 0b11110000;</code></pre>
593const binary_int = 0b11110000;
594 {#code_end#}
566595 {#header_close#}
567596 {#header_open|Runtime Integer Values#}
568597 <p>
......@@ -573,9 +602,11 @@ const binary_int = 0b11110000;</code></pre>
573602 However, once an integer value is no longer known at compile-time, it must have a
574603 known size, and is vulnerable to undefined behavior.
575604 </p>
576 <pre><code class="zig">fn divide(a: i32, b: i32) -&gt; i32 {
605 {#code_begin|syntax#}
606fn divide(a: i32, b: i32) -> i32 {
577607 return a / b;
578}</code></pre>
608}
609 {#code_end#}
579610 <p>
580611 In this function, values <code>a</code> and <code>b</code> are known only at runtime,
581612 and thus this division operation is vulnerable to both integer overflow and
......@@ -592,48 +623,49 @@ const binary_int = 0b11110000;</code></pre>
592623 {#header_open|Floats#}
593624 {#header_close#}
594625 {#header_open|Float Literals#}
595 <pre><code class="zig">const floating_point = 123.0E+77;
626 {#code_begin|syntax#}
627const floating_point = 123.0E+77;
596628const another_float = 123.0;
597629const yet_another = 123.0e+77;
598630
599631const hex_floating_point = 0x103.70p-5;
600632const another_hex_float = 0x103.70;
601const yet_another_hex_float = 0x103.70P-5;</code></pre>
633const yet_another_hex_float = 0x103.70P-5;
634 {#code_end#}
602635 {#header_close#}
603636 {#header_open|Floating Point Operations#}
604637 <p>By default floating point operations use <code>Optimized</code> mode,
605638 but you can switch to <code>Strict</code> mode on a per-block basis:</p>
606 <p>foo.zig</p>
607 <pre><code class="zig">const builtin = @import("builtin");
608const big = f64(1 &lt;&lt; 40);
639 {#code_begin|obj|foo#}
640 {#code_release_fast#}
641const builtin = @import("builtin");
642const big = f64(1 << 40);
609643
610export fn foo_strict(x: f64) -&gt; f64 {
644export fn foo_strict(x: f64) -> f64 {
611645 @setFloatMode(this, builtin.FloatMode.Strict);
612646 return x + big - big;
613647}
614648
615export fn foo_optimized(x: f64) -&gt; f64 {
649export fn foo_optimized(x: f64) -> f64 {
616650 return x + big - big;
617}</code></pre>
618 <p>test.zig</p>
619 <pre><code class="zig">const warn = @import("std").debug.warn;
651}
652 {#code_end#}
653 <p>For this test we have to separate code into two object files -
654 otherwise the optimizer figures out all the values at compile-time,
655 which operates in strict mode.</p>
656 {#code_begin|exe|float_mode#}
657 {#code_link_object|foo#}
658const warn = @import("std").debug.warn;
620659
621extern fn foo_strict(x: f64) -&gt; f64;
622extern fn foo_optimized(x: f64) -&gt; f64;
660extern fn foo_strict(x: f64) -> f64;
661extern fn foo_optimized(x: f64) -> f64;
623662
624pub fn main() -&gt; %void {
663pub fn main() -> %void {
625664 const x = 0.001;
626665 warn("optimized = {}\n", foo_optimized(x));
627666 warn("strict = {}\n", foo_strict(x));
628}</code></pre>
629 <p>For this test we have to separate code into two object files -
630 otherwise the optimizer figures out all the values at compile-time,
631 which operates in strict mode.</p>
632 <pre><code class="sh">$ zig build-obj foo.zig --release-fast
633$ zig build-exe test.zig --object foo.o
634$ ./test
635optimized = 1.0e-2
636strict = 9.765625e-3</code></pre>
667}
668 {#code_end#}
637669 {#see_also|@setFloatMode|Division by Zero#}
638670 {#header_close#}
639671 {#header_open|Operators#}
......@@ -1244,7 +1276,8 @@ or
12441276 {#header_close#}
12451277 {#header_close#}
12461278 {#header_open|Arrays#}
1247 <pre><code class="zig">const assert = @import("std").debug.assert;
1279 {#code_begin|test|arrays#}
1280const assert = @import("std").debug.assert;
12481281const mem = @import("std").mem;
12491282
12501283// array literal
......@@ -1314,7 +1347,7 @@ comptime {
13141347}
13151348
13161349// use compile-time code to initialize an array
1317var fancy_array = {
1350var fancy_array = init: {
13181351 var initial_value: [10]Point = undefined;
13191352 for (initial_value) |*pt, i| {
13201353 *pt = Point {
......@@ -1322,7 +1355,7 @@ var fancy_array = {
13221355 .y = i32(i) * 2,
13231356 };
13241357 }
1325 initial_value
1358 break :init initial_value;
13261359};
13271360const Point = struct {
13281361 x: i32,
......@@ -1336,26 +1369,23 @@ test "compile-time array initalization" {
13361369
13371370// call a function to initialize an array
13381371var more_points = []Point{makePoint(3)} ** 10;
1339fn makePoint(x: i32) -&gt; Point {
1340 Point {
1372fn makePoint(x: i32) -> Point {
1373 return Point {
13411374 .x = x,
13421375 .y = x * 2,
1343 }
1376 };
13441377}
13451378test "array initialization with function calls" {
13461379 assert(more_points[4].x == 3);
13471380 assert(more_points[4].y == 6);
13481381 assert(more_points.len == 10);
1349}</code></pre>
1350 <pre><code class="sh">$ zig test arrays.zig
1351Test 1/4 iterate over an array...OK
1352Test 2/4 modify an array...OK
1353Test 3/4 compile-time array initalization...OK
1354Test 4/4 array initialization with function calls...OK</code></pre>
1382}
1383 {#code_end#}
13551384 {#see_also|for|Slices#}
13561385 {#header_close#}
13571386 {#header_open|Pointers#}
1358 <pre><code class="zig">const assert = @import("std").debug.assert;
1387 {#code_begin|test#}
1388const assert = @import("std").debug.assert;
13591389
13601390test "address of syntax" {
13611391 // Get the address of a variable:
......@@ -1366,12 +1396,12 @@ test "address of syntax" {
13661396 assert(*x_ptr == 1234);
13671397
13681398 // When you get the address of a const variable, you get a const pointer.
1369 assert(@typeOf(x_ptr) == &amp;const i32);
1399 assert(@typeOf(x_ptr) == &const i32);
13701400
13711401 // If you want to mutate the value, you'd need an address of a mutable variable:
13721402 var y: i32 = 5678;
13731403 const y_ptr = &y;
1374 assert(@typeOf(y_ptr) == &amp;i32);
1404 assert(@typeOf(y_ptr) == &i32);
13751405 *y_ptr += 1;
13761406 assert(*y_ptr == 5679);
13771407}
......@@ -1381,7 +1411,7 @@ test "pointer array access" {
13811411 // need such a thing, use array index syntax:
13821412
13831413 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1384 const ptr = &amp;array[1];
1414 const ptr = &array[1];
13851415
13861416 assert(array[2] == 3);
13871417 ptr[1] += 1;
......@@ -1392,10 +1422,10 @@ test "pointer slicing" {
13921422 // In Zig, we prefer using slices over null-terminated pointers.
13931423 // You can turn a pointer into a slice using slice syntax:
13941424 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1395 const ptr = &amp;array[1];
1425 const ptr = &array[1];
13961426 const slice = ptr[1..3];
13971427
1398 assert(slice.ptr == &amp;ptr[1]);
1428 assert(slice.ptr == &ptr[1]);
13991429 assert(slice.len == 2);
14001430
14011431 // Slices have bounds checking and are therefore protected
......@@ -1410,7 +1440,7 @@ comptime {
14101440 // Pointers work at compile-time too, as long as you don't use
14111441 // @ptrCast.
14121442 var x: i32 = 1;
1413 const ptr = &amp;x;
1443 const ptr = &x;
14141444 *ptr += 1;
14151445 x += 1;
14161446 assert(*ptr == 3);
......@@ -1418,7 +1448,7 @@ comptime {
14181448
14191449test "@ptrToInt and @intToPtr" {
14201450 // To convert an integer address into a pointer, use @intToPtr:
1421 const ptr = @intToPtr(&amp;i32, 0xdeadbeef);
1451 const ptr = @intToPtr(&i32, 0xdeadbeef);
14221452
14231453 // To convert a pointer to an integer, use @ptrToInt:
14241454 const addr = @ptrToInt(ptr);
......@@ -1430,7 +1460,7 @@ test "@ptrToInt and @intToPtr" {
14301460comptime {
14311461 // Zig is able to do this at compile-time, as long as
14321462 // ptr is never dereferenced.
1433 const ptr = @intToPtr(&amp;i32, 0xdeadbeef);
1463 const ptr = @intToPtr(&i32, 0xdeadbeef);
14341464 const addr = @ptrToInt(ptr);
14351465 assert(@typeOf(addr) == usize);
14361466 assert(addr == 0xdeadbeef);
......@@ -1440,34 +1470,34 @@ test "volatile" {
14401470 // In Zig, loads and stores are assumed to not have side effects.
14411471 // If a given load or store should have side effects, such as
14421472 // Memory Mapped Input/Output (MMIO), use `volatile`:
1443 const mmio_ptr = @intToPtr(&amp;volatile u8, 0x12345678);
1473 const mmio_ptr = @intToPtr(&volatile u8, 0x12345678);
14441474
14451475 // Now loads and stores with mmio_ptr are guaranteed to all happen
14461476 // and in the same order as in source code.
1447 assert(@typeOf(mmio_ptr) == &amp;volatile u8);
1477 assert(@typeOf(mmio_ptr) == &volatile u8);
14481478}
14491479
14501480test "nullable pointers" {
14511481 // Pointers cannot be null. If you want a null pointer, use the nullable
14521482 // prefix `?` to make the pointer type nullable.
1453 var ptr: ?&amp;i32 = null;
1483 var ptr: ?&i32 = null;
14541484
14551485 var x: i32 = 1;
1456 ptr = &amp;x;
1486 ptr = &x;
14571487
14581488 assert(*??ptr == 1);
14591489
14601490 // Nullable pointers are the same size as normal pointers, because pointer
14611491 // value 0 is used as the null value.
1462 assert(@sizeOf(?&amp;i32) == @sizeOf(&amp;i32));
1492 assert(@sizeOf(?&i32) == @sizeOf(&i32));
14631493}
14641494
14651495test "pointer casting" {
14661496 // To convert one pointer type to another, use @ptrCast. This is an unsafe
14671497 // operation that Zig cannot protect you against. Use @ptrCast only when other
14681498 // conversions are not possible.
1469 const bytes = []u8{0x12, 0x12, 0x12, 0x12};
1470 const u32_ptr = @ptrCast(&amp;const u32, &amp;bytes[0]);
1499 const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
1500 const u32_ptr = @ptrCast(&const u32, &bytes[0]);
14711501 assert(*u32_ptr == 0x12121212);
14721502
14731503 // Even this example is contrived - there are better ways to do the above than
......@@ -1481,17 +1511,9 @@ test "pointer casting" {
14811511
14821512test "pointer child type" {
14831513 // pointer types have a `child` field which tells you the type they point to.
1484 assert((&amp;u32).child == u32);
1485}</code></pre>
1486 <pre><code class="sh">$ zig test test.zig
1487Test 1/8 address of syntax...OK
1488Test 2/8 pointer array access...OK
1489Test 3/8 pointer slicing...OK
1490Test 4/8 @ptrToInt and @intToPtr...OK
1491Test 5/8 volatile...OK
1492Test 6/8 nullable pointers...OK
1493Test 7/8 pointer casting...OK
1494Test 8/8 pointer child type...OK</code></pre>
1514 assert((&u32).Child == u32);
1515}
1516 {#code_end#}
14951517 {#header_open|Alignment#}
14961518 <p>
14971519 Each type has an <strong>alignment</strong> - a number of bytes such that,
......@@ -1507,18 +1529,20 @@ Test 8/8 pointer child type...OK</code></pre>
15071529 In Zig, a pointer type has an alignment value. If the value is equal to the
15081530 alignment of the underlying type, it can be omitted from the type:
15091531 </p>
1510 <pre><code class="zig">const assert = @import("std").debug.assert;
1532 {#code_begin|test#}
1533const assert = @import("std").debug.assert;
15111534const builtin = @import("builtin");
15121535
15131536test "variable alignment" {
15141537 var x: i32 = 1234;
15151538 const align_of_i32 = @alignOf(@typeOf(x));
1516 assert(@typeOf(&amp;x) == &amp;i32);
1517 assert(&amp;i32 == &amp;align(align_of_i32) i32);
1539 assert(@typeOf(&x) == &i32);
1540 assert(&i32 == &align(align_of_i32) i32);
15181541 if (builtin.arch == builtin.Arch.x86_64) {
1519 assert((&amp;i32).alignment == 4);
1542 assert((&i32).alignment == 4);
15201543 }
1521}</code></pre>
1544}
1545 {#code_end#}
15221546 <p>In the same way that a <code>&amp;i32</code> can be implicitly cast to a
15231547 <code>&amp;const i32</code>, a pointer with a larger alignment can be implicitly
15241548 cast to a pointer with a smaller alignment, but not vice versa.
......@@ -1527,18 +1551,19 @@ test "variable alignment" {
15271551 You can specify alignment on variables and functions. If you do this, then
15281552 pointers to them get the specified alignment:
15291553 </p>
1530 <pre><code class="zig">const assert = @import("std").debug.assert;
1554 {#code_begin|test#}
1555const assert = @import("std").debug.assert;
15311556
15321557var foo: u8 align(4) = 100;
15331558
15341559test "global variable alignment" {
1535 assert(@typeOf(&amp;foo).alignment == 4);
1536 assert(@typeOf(&amp;foo) == &amp;align(4) u8);
1537 const slice = (&amp;foo)[0..1];
1560 assert(@typeOf(&foo).alignment == 4);
1561 assert(@typeOf(&foo) == &align(4) u8);
1562 const slice = (&foo)[0..1];
15381563 assert(@typeOf(slice) == []align(4) u8);
15391564}
15401565
1541fn derp() align(@sizeOf(usize) * 2) -&gt; i32 { 1234 }
1566fn derp() align(@sizeOf(usize) * 2) -> i32 { return 1234; }
15421567fn noop1() align(1) {}
15431568fn noop4() align(4) {}
15441569
......@@ -1548,51 +1573,28 @@ test "function alignment" {
15481573 assert(@typeOf(noop4) == fn() align(4));
15491574 noop1();
15501575 noop4();
1551}</code></pre>
1576}
1577 {#code_end#}
15521578 <p>
15531579 If you have a pointer or a slice that has a small alignment, but you know that it actually
15541580 has a bigger alignment, use <a href="#builtin-alignCast">@alignCast</a> to change the
15551581 pointer into a more aligned pointer. This is a no-op at runtime, but inserts a
15561582 <a href="#undef-incorrect-pointer-alignment">safety check</a>:
15571583 </p>
1558 <pre><code class="zig">const assert = @import("std").debug.assert;
1584 {#code_begin|test_safety|incorrect alignment#}
1585const assert = @import("std").debug.assert;
15591586
15601587test "pointer alignment safety" {
15611588 var array align(4) = []u32{0x11111111, 0x11111111};
15621589 const bytes = ([]u8)(array[0..]);
15631590 assert(foo(bytes) == 0x11111111);
15641591}
1565fn foo(bytes: []u8) -&gt; u32 {
1592fn foo(bytes: []u8) -> u32 {
15661593 const slice4 = bytes[1..5];
15671594 const int_slice = ([]u32)(@alignCast(4, slice4));
15681595 return int_slice[0];
1569}</code></pre>
1570 <pre><code class="sh">$ zig test test.zig
1571Test 1/1 pointer alignment safety...incorrect alignment
1572/home/andy/dev/zig/build/lib/zig/std/special/zigrt.zig:16:35: 0x0000000000203525 in ??? (test)
1573 @import("std").debug.panic("{}", message_ptr[0..message_len]);
1574 ^
1575/home/andy/dev/zig/build/test.zig:10:45: 0x00000000002035ec in ??? (test)
1576 const int_slice = ([]u32)(@alignCast(4, slice4));
1577 ^
1578/home/andy/dev/zig/build/test.zig:6:15: 0x0000000000203439 in ??? (test)
1579 assert(foo(bytes) == 0x11111111);
1580 ^
1581/home/andy/dev/zig/build/lib/zig/std/special/test_runner.zig:9:21: 0x00000000002162d8 in ??? (test)
1582 test_fn.func();
1583 ^
1584/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:60:21: 0x0000000000216197 in ??? (test)
1585 return root.main();
1586 ^
1587/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:47:13: 0x0000000000216050 in ??? (test)
1588 callMain(argc, argv, envp) catch std.os.posix.exit(1);
1589 ^
1590/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:34:25: 0x0000000000215fa0 in ??? (test)
1591 posixCallMainAndExit()
1592 ^
1593
1594Tests failed. Use the following command to reproduce the failure:
1595./test</code></pre>
1596}
1597 {#code_end#}
15961598 {#header_close#}
15971599 {#header_open|Type Based Alias Analysis#}
15981600 <p>Zig uses Type Based Alias Analysis (also known as Strict Aliasing) to
......@@ -1609,7 +1611,8 @@ Tests failed. Use the following command to reproduce the failure:
16091611 {#header_close#}
16101612 {#header_close#}
16111613 {#header_open|Slices#}
1612 <pre><code class="zig">const assert = @import("std").debug.assert;
1614 {#code_begin|test_safety|index out of bounds#}
1615const assert = @import("std").debug.assert;
16131616
16141617test "basic slices" {
16151618 var array = []i32{1, 2, 3, 4};
......@@ -1618,38 +1621,17 @@ test "basic slices" {
16181621 // compile-time, whereas the slice's length is known at runtime.
16191622 // Both can be accessed with the `len` field.
16201623 const slice = array[0..array.len];
1621 assert(slice.ptr == &amp;array[0]);
1624 assert(slice.ptr == &array[0]);
16221625 assert(slice.len == array.len);
16231626
16241627 // Slices have array bounds checking. If you try to access something out
16251628 // of bounds, you'll get a safety check failure:
16261629 slice[10] += 1;
1627}</code></pre>
1628 <pre><code class="sh">$ zig test test.zig
1629Test 1/1 basic slices...index out of bounds
1630lib/zig/std/special/zigrt.zig:16:35: 0x0000000000203455 in ??? (test)
1631 @import("std").debug.panic("{}", message_ptr[0..message_len]);
1632 ^
1633test.zig:15:10: 0x0000000000203334 in ??? (test)
1634 slice[10] += 1;
1635 ^
1636lib/zig/std/special/test_runner.zig:9:21: 0x0000000000214b1a in ??? (test)
1637 test_fn.func();
1638 ^
1639lib/zig/std/special/bootstrap.zig:60:21: 0x00000000002149e7 in ??? (test)
1640 return root.main();
1641 ^
1642lib/zig/std/special/bootstrap.zig:47:13: 0x00000000002148a0 in ??? (test)
1643 callMain(argc, argv, envp) catch std.os.posix.exit(1);
1644 ^
1645lib/zig/std/special/bootstrap.zig:34:25: 0x00000000002147f0 in ??? (test)
1646 posixCallMainAndExit()
1647 ^
1648
1649Tests failed. Use the following command to reproduce the failure:
1650./test</code></pre>
1630}
1631 {#code_end#}
16511632 <p>This is one reason we prefer slices to pointers.</p>
1652 <pre><code class="zig">const assert = @import("std").debug.assert;
1633 {#code_begin|test|slices#}
1634const assert = @import("std").debug.assert;
16531635const mem = @import("std").mem;
16541636const fmt = @import("std").fmt;
16551637
......@@ -1663,8 +1645,8 @@ test "using slices for strings" {
16631645 var all_together: [100]u8 = undefined;
16641646 // You can use slice syntax on an array to convert an array into a slice.
16651647 const all_together_slice = all_together[0..];
1666 // String concatenation example:
1667 const hello_world = fmt.bufPrint(all_together_slice, "{} {}", hello, world);
1648 // String concatenation example.
1649 const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", hello, world);
16681650
16691651 // Generally, you can use UTF-8 and not worry about whether something is a
16701652 // string. If you don't need to deal with individual characters, no need
......@@ -1674,7 +1656,7 @@ test "using slices for strings" {
16741656
16751657test "slice pointer" {
16761658 var array: [10]u8 = undefined;
1677 const ptr = &amp;array[0];
1659 const ptr = &array[0];
16781660
16791661 // You can use slicing syntax to convert a pointer into a slice:
16801662 const slice = ptr[0..5];
......@@ -1692,20 +1674,18 @@ test "slice pointer" {
16921674test "slice widening" {
16931675 // Zig supports slice widening and slice narrowing. Cast a slice of u8
16941676 // to a slice of anything else, and Zig will perform the length conversion.
1695 const array = []u8{0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13};
1677 const array align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13};
16961678 const slice = ([]const u32)(array[0..]);
16971679 assert(slice.len == 2);
16981680 assert(slice[0] == 0x12121212);
16991681 assert(slice[1] == 0x13131313);
1700}</code></pre>
1701 <pre><code class="sh">$ zig test test.zig
1702Test 1/3 using slices for strings...OK
1703Test 2/3 slice pointer...OK
1704Test 3/3 slice widening...OK</code></pre>
1682}
1683 {#code_end#}
17051684 {#see_also|Pointers|for|Arrays#}
17061685 {#header_close#}
17071686 {#header_open|struct#}
1708 <pre><code class="zig">// Declare a struct.
1687 {#code_begin|test|structs#}
1688// Declare a struct.
17091689// Zig gives no guarantees about the order of fields and whether or
17101690// not there will be padding.
17111691const Point = struct {
......@@ -1741,7 +1721,7 @@ const Vec3 = struct {
17411721 y: f32,
17421722 z: f32,
17431723
1744 pub fn init(x: f32, y: f32, z: f32) -&gt; Vec3 {
1724 pub fn init(x: f32, y: f32, z: f32) -> Vec3 {
17451725 return Vec3 {
17461726 .x = x,
17471727 .y = y,
......@@ -1749,7 +1729,7 @@ const Vec3 = struct {
17491729 };
17501730 }
17511731
1752 pub fn dot(self: &amp;const Vec3, other: &amp;const Vec3) -&gt; f32 {
1732 pub fn dot(self: &const Vec3, other: &const Vec3) -> f32 {
17531733 return self.x * other.x + self.y * other.y + self.z * other.z;
17541734 }
17551735};
......@@ -1781,7 +1761,7 @@ test "struct namespaced variable" {
17811761
17821762// struct field order is determined by the compiler for optimal performance.
17831763// however, you can still calculate a struct base pointer given a field pointer:
1784fn setYBasedOnX(x: &amp;f32, y: f32) {
1764fn setYBasedOnX(x: &f32, y: f32) {
17851765 const point = @fieldParentPtr(Point, "x", x);
17861766 point.y = y;
17871767}
......@@ -1790,22 +1770,22 @@ test "field parent pointer" {
17901770 .x = 0.1234,
17911771 .y = 0.5678,
17921772 };
1793 setYBasedOnX(&amp;point.x, 0.9);
1773 setYBasedOnX(&point.x, 0.9);
17941774 assert(point.y == 0.9);
17951775}
17961776
17971777// You can return a struct from a function. This is how we do generics
17981778// in Zig:
1799fn LinkedList(comptime T: type) -&gt; type {
1779fn LinkedList(comptime T: type) -> type {
18001780 return struct {
18011781 pub const Node = struct {
1802 prev: ?&amp;Node,
1803 next: ?&amp;Node,
1782 prev: ?&Node,
1783 next: ?&Node,
18041784 data: T,
18051785 };
18061786
1807 first: ?&amp;Node,
1808 last: ?&amp;Node,
1787 first: ?&Node,
1788 last: ?&Node,
18091789 len: usize,
18101790 };
18111791}
......@@ -1833,21 +1813,18 @@ test "linked list" {
18331813 .data = 1234,
18341814 };
18351815 var list2 = LinkedList(i32) {
1836 .first = &amp;node,
1837 .last = &amp;node,
1816 .first = &node,
1817 .last = &node,
18381818 .len = 1,
18391819 };
18401820 assert((??list2.first).data == 1234);
1841}</code></pre>
1842 <pre><code class="sh">$ zig test structs.zig
1843Test 1/4 dot product...OK
1844Test 2/4 struct namespaced variable...OK
1845Test 3/4 field parent pointer...OK
1846Test 4/4 linked list...OK</code></pre>
1821}
1822 {#code_end#}
18471823 {#see_also|comptime|@fieldParentPtr#}
18481824 {#header_close#}
18491825 {#header_open|enum#}
1850 <pre><code class="zig">const assert = @import("std").debug.assert;
1826 {#code_begin|test|enums#}
1827const assert = @import("std").debug.assert;
18511828const mem = @import("std").mem;
18521829
18531830// Declare an enum.
......@@ -1896,7 +1873,7 @@ const Suit = enum {
18961873 Diamonds,
18971874 Hearts,
18981875
1899 pub fn isClubs(self: Suit) -&gt; bool {
1876 pub fn isClubs(self: Suit) -> bool {
19001877 return self == Suit.Clubs;
19011878 }
19021879};
......@@ -1914,9 +1891,9 @@ const Foo = enum {
19141891test "enum variant switch" {
19151892 const p = Foo.Number;
19161893 const what_is_it = switch (p) {
1917 Foo.String =&gt; "this is a string",
1918 Foo.Number =&gt; "this is a number",
1919 Foo.None =&gt; "this is a none",
1894 Foo.String => "this is a string",
1895 Foo.Number => "this is a number",
1896 Foo.None => "this is a none",
19201897 };
19211898 assert(mem.eql(u8, what_is_it, "this is a number"));
19221899}
......@@ -1945,22 +1922,15 @@ test "@memberName" {
19451922// @tagName gives a []const u8 representation of an enum value:
19461923test "@tagName" {
19471924 assert(mem.eql(u8, @tagName(Small.Three), "Three"));
1948}</code></pre>
1925}
1926 {#code_end#}
19491927 <p>TODO extern enum</p>
19501928 <p>TODO packed enum</p>
1951 <pre><code class="sh">$ zig test enum.zig
1952Test 1/8 enum ordinal value...OK
1953Test 2/8 set enum ordinal value...OK
1954Test 3/8 enum method...OK
1955Test 4/8 enum variant switch...OK
1956Test 5/8 @TagType...OK
1957Test 6/8 @memberCount...OK
1958Test 7/8 @memberName...OK
1959Test 8/8 @tagName...OK</code></pre>
19601929 {#see_also|@memberName|@memberCount|@tagName#}
19611930 {#header_close#}
19621931 {#header_open|union#}
1963 <pre><code class="zig">const assert = @import("std").debug.assert;
1932 {#code_begin|test|union#}
1933const assert = @import("std").debug.assert;
19641934const mem = @import("std").mem;
19651935
19661936// A union has only 1 active field at a time.
......@@ -2008,19 +1978,19 @@ test "union variant switch" {
20081978 const p = Foo { .Number = 54 };
20091979 const what_is_it = switch (p) {
20101980 // Capture by reference
2011 Foo.String =&gt; |*x| {
2012 "this is a string"
1981 Foo.String => |*x| blk: {
1982 break :blk "this is a string";
20131983 },
20141984
20151985 // Capture by value
2016 Foo.Number =&gt; |x| {
1986 Foo.Number => |x| blk: {
20171987 assert(x == 54);
2018 "this is a number"
1988 break :blk "this is a number";
20191989 },
20201990
2021 Foo.None =&gt; {
2022 "this is a none"
2023 }
1991 Foo.None => blk: {
1992 break :blk "this is a none";
1993 },
20241994 };
20251995 assert(mem.eql(u8, what_is_it, "this is a number"));
20261996}
......@@ -2053,22 +2023,16 @@ const Small2 = union(enum) {
20532023};
20542024test "@tagName" {
20552025 assert(mem.eql(u8, @tagName(Small2.C), "C"));
2056}</code></pre>
2057 <pre><code class="sh">$ zig test union.zig
2058Test 1/7 simple union...OK
2059Test 2/7 declare union value...OK
2060Test 3/7 @TagType...OK
2061Test 4/7 union variant switch...OK
2062Test 5/7 @memberCount...OK
2063Test 6/7 @memberName...OK
2064Test 7/7 @tagName...OK</code></pre>
2026}
2027 {#code_end#}
20652028 <p>
20662029 Unions with an enum tag are generated as a struct with a tag field and union field. Zig
20672030 sorts the order of the tag and union field by the largest alignment.
20682031 </p>
20692032 {#header_close#}
20702033 {#header_open|switch#}
2071 <pre><code class="zig">const assert = @import("std").debug.assert;
2034 {#code_begin|test|switch#}
2035const assert = @import("std").debug.assert;
20722036const builtin = @import("builtin");
20732037
20742038test "switch simple" {
......@@ -2082,59 +2046,59 @@ test "switch simple" {
20822046 // the cases and use an if.
20832047 const b = switch (a) {
20842048 // Multiple cases can be combined via a ','
2085 1, 2, 3 =&gt; 0,
2049 1, 2, 3 => 0,
20862050
20872051 // Ranges can be specified using the ... syntax. These are inclusive
20882052 // both ends.
2089 5 ... 100 =&gt; 1,
2053 5 ... 100 => 1,
20902054
20912055 // Branches can be arbitrarily complex.
2092 101 =&gt; {
2056 101 => blk: {
20932057 const c: u64 = 5;
2094 c * 2 + 1
2058 break :blk c * 2 + 1;
20952059 },
20962060
20972061 // Switching on arbitrary expressions is allowed as long as the
20982062 // expression is known at compile-time.
2099 zz =&gt; zz,
2100 comptime {
2063 zz => zz,
2064 comptime blk: {
21012065 const d: u32 = 5;
21022066 const e: u32 = 100;
2103 d + e
2104 } =&gt; 107,
2067 break :blk d + e;
2068 } => 107,
21052069
21062070 // The else branch catches everything not already captured.
21072071 // Else branches are mandatory unless the entire range of values
21082072 // is handled.
2109 else =&gt; 9,
2073 else => 9,
21102074 };
21112075
21122076 assert(b == 1);
21132077}
21142078
21152079test "switch enum" {
2116 const Item = enum {
2080 const Item = union(enum) {
21172081 A: u32,
21182082 C: struct { x: u8, y: u8 },
21192083 D,
21202084 };
21212085
2122 var a = Item.A { 3 };
2086 var a = Item { .A = 3 };
21232087
21242088 // Switching on more complex enums is allowed.
21252089 const b = switch (a) {
21262090 // A capture group is allowed on a match, and will return the enum
21272091 // value matched.
2128 Item.A =&gt; |item| item,
2092 Item.A => |item| item,
21292093
21302094 // A reference to the matched value can be obtained using `*` syntax.
2131 Item.C =&gt; |*item| {
2095 Item.C => |*item| blk: {
21322096 (*item).x += 1;
2133 6
2097 break :blk 6;
21342098 },
21352099
21362100 // No else is required if the types cases was exhaustively handled
2137 Item.D =&gt; 8,
2101 Item.D => 8,
21382102 };
21392103
21402104 assert(b == 3);
......@@ -2142,37 +2106,35 @@ test "switch enum" {
21422106
21432107// Switch expressions can be used outside a function:
21442108const os_msg = switch (builtin.os) {
2145 builtin.Os.linux =&gt; "we found a linux user",
2146 else =&gt; "not a linux user",
2109 builtin.Os.linux => "we found a linux user",
2110 else => "not a linux user",
21472111};
21482112
21492113// Inside a function, switch statements implicitly are compile-time
21502114// evaluated if the target expression is compile-time known.
21512115test "switch inside function" {
21522116 switch (builtin.os) {
2153 builtin.Os.windows =&gt; {
2117 builtin.Os.windows => {
21542118 // On an OS other than windows, block is not even analyzed,
21552119 // so this compile error is not triggered.
21562120 // On windows this compile error would be triggered.
21572121 @compileError("windows not supported");
21582122 },
2159 else =&gt; {},
2160 };
2161}</code></pre>
2162 <pre><code class="sh">$ zig test switch.zig
2163Test 1/2 switch simple...OK
2164Test 2/2 switch enum...OK
2165Test 3/3 switch inside function...OK</code></pre>
2123 else => {},
2124 }
2125}
2126 {#code_end#}
21662127 {#see_also|comptime|enum|@compileError|Compile Variables#}
21672128 {#header_close#}
21682129 {#header_open|while#}
2169 <pre><code class="zig">const assert = @import("std").debug.assert;
2130 {#code_begin|test|while#}
2131const assert = @import("std").debug.assert;
21702132
21712133test "while basic" {
21722134 // A while loop is used to repeatedly execute an expression until
21732135 // some condition is no longer true.
21742136 var i: usize = 0;
2175 while (i &lt; 10) {
2137 while (i < 10) {
21762138 i += 1;
21772139 }
21782140 assert(i == 10);
......@@ -2194,7 +2156,7 @@ test "while continue" {
21942156 var i: usize = 0;
21952157 while (true) {
21962158 i += 1;
2197 if (i &lt; 10)
2159 if (i < 10)
21982160 continue;
21992161 break;
22002162 }
......@@ -2205,7 +2167,7 @@ test "while loop continuation expression" {
22052167 // You can give an expression to the while loop to execute when
22062168 // the loop is continued. This is respected by the continue control flow.
22072169 var i: usize = 0;
2208 while (i &lt; 10) : (i += 1) {}
2170 while (i < 10) : (i += 1) {}
22092171 assert(i == 10);
22102172}
22112173
......@@ -2214,9 +2176,9 @@ test "while loop continuation expression, more complicated" {
22142176 // expression.
22152177 var i1: usize = 1;
22162178 var j1: usize = 1;
2217 while (i1 * j1 &lt; 2000) : ({ i1 *= 2; j1 *= 3; }) {
2179 while (i1 * j1 < 2000) : ({ i1 *= 2; j1 *= 3; }) {
22182180 const my_ij1 = i1 * j1;
2219 assert(my_ij1 &lt; 2000);
2181 assert(my_ij1 < 2000);
22202182 }
22212183}
22222184
......@@ -2225,12 +2187,12 @@ test "while else" {
22252187 assert(!rangeHasNumber(0, 10, 15));
22262188}
22272189
2228fn rangeHasNumber(begin: usize, end: usize, number: usize) -&gt; bool {
2190fn rangeHasNumber(begin: usize, end: usize, number: usize) -> bool {
22292191 var i = begin;
22302192 // While loops are expressions. The result of the expression is the
22312193 // result of the else clause of a while loop, which is executed when
22322194 // the condition of the while loop is tested as false.
2233 return while (i &lt; end) : (i += 1) {
2195 return while (i < end) : (i += 1) {
22342196 if (i == number) {
22352197 // break expressions, like return expressions, accept a value
22362198 // parameter. This is the result of the while expression.
......@@ -2238,9 +2200,7 @@ fn rangeHasNumber(begin: usize, end: usize, number: usize) -&gt; bool {
22382200 // evaluated.
22392201 break true;
22402202 }
2241 } else {
2242 false
2243 }
2203 } else false;
22442204}
22452205
22462206test "while null capture" {
......@@ -2278,22 +2238,18 @@ test "while null capture" {
22782238}
22792239
22802240var numbers_left: u32 = undefined;
2281fn eventuallyNullSequence() -&gt; ?u32 {
2282 return if (numbers_left == 0) {
2283 null
2284 } else {
2241fn eventuallyNullSequence() -> ?u32 {
2242 return if (numbers_left == 0) null else blk: {
22852243 numbers_left -= 1;
2286 numbers_left
2287 }
2244 break :blk numbers_left;
2245 };
22882246}
22892247error ReachedZero;
2290fn eventuallyErrorSequence() -&gt; %u32 {
2291 return if (numbers_left == 0) {
2292 error.ReachedZero
2293 } else {
2248fn eventuallyErrorSequence() -> %u32 {
2249 return if (numbers_left == 0) error.ReachedZero else blk: {
22942250 numbers_left -= 1;
2295 numbers_left
2296 }
2251 break :blk numbers_left;
2252 };
22972253}
22982254
22992255test "inline while loop" {
......@@ -2302,34 +2258,27 @@ test "inline while loop" {
23022258 // such as use types as first class values.
23032259 comptime var i = 0;
23042260 var sum: usize = 0;
2305 inline while (i &lt; 3) : (i += 1) {
2261 inline while (i < 3) : (i += 1) {
23062262 const T = switch (i) {
2307 0 =&gt; f32,
2308 1 =&gt; i8,
2309 2 =&gt; bool,
2310 else =&gt; unreachable,
2263 0 => f32,
2264 1 => i8,
2265 2 => bool,
2266 else => unreachable,
23112267 };
23122268 sum += typeNameLength(T);
23132269 }
23142270 assert(sum == 9);
23152271}
23162272
2317fn typeNameLength(comptime T: type) -&gt; usize {
2273fn typeNameLength(comptime T: type) -> usize {
23182274 return @typeName(T).len;
2319}</code></pre>
2320 <pre><code class="sh">$ zig while.zig
2321Test 1/8 while basic...OK
2322Test 2/8 while break...OK
2323Test 3/8 while continue...OK
2324Test 4/8 while loop continuation expression...OK
2325Test 5/8 while loop continuation expression, more complicated...OK
2326Test 6/8 while else...OK
2327Test 7/8 while null capture...OK
2328Test 8/8 inline while loop...OK</code></pre>
2275}
2276 {#code_end#}
23292277 {#see_also|if|Nullables|Errors|comptime|unreachable#}
23302278 {#header_close#}
23312279 {#header_open|for#}
2332 <pre><code class="zig">const assert = @import("std").debug.assert;
2280 {#code_begin|test|for#}
2281const assert = @import("std").debug.assert;
23332282
23342283test "for basics" {
23352284 const items = []i32 { 4, 5, 3, 4, 0 };
......@@ -2387,9 +2336,9 @@ test "for else" {
23872336 } else {
23882337 sum += ??value;
23892338 }
2390 } else {
2339 } else blk: {
23912340 assert(sum == 7);
2392 sum
2341 break :blk sum;
23932342 };
23942343}
23952344
......@@ -2404,28 +2353,25 @@ test "inline for loop" {
24042353 var sum: usize = 0;
24052354 inline for (nums) |i| {
24062355 const T = switch (i) {
2407 2 =&gt; f32,
2408 4 =&gt; i8,
2409 6 =&gt; bool,
2410 else =&gt; unreachable,
2356 2 => f32,
2357 4 => i8,
2358 6 => bool,
2359 else => unreachable,
24112360 };
24122361 sum += typeNameLength(T);
24132362 }
24142363 assert(sum == 9);
24152364}
24162365
2417fn typeNameLength(comptime T: type) -&gt; usize {
2366fn typeNameLength(comptime T: type) -> usize {
24182367 return @typeName(T).len;
2419}</code></pre>
2420 <pre><code class="sh">$ zig test for.zig
2421Test 1/4 for basics...OK
2422Test 2/4 for reference...OK
2423Test 3/4 for else...OK
2424Test 4/4 inline for loop...OK</code></pre>
2368}
2369 {#code_end#}
24252370 {#see_also|while|comptime|Arrays|Slices#}
24262371 {#header_close#}
24272372 {#header_open|if#}
2428 <pre><code class="zig">// If expressions have three uses, corresponding to the three types:
2373 {#code_begin|test|if#}
2374// If expressions have three uses, corresponding to the three types:
24292375// * bool
24302376// * ?T
24312377// * %T
......@@ -2439,9 +2385,9 @@ test "if boolean" {
24392385 if (a != b) {
24402386 assert(true);
24412387 } else if (a == 9) {
2442 unreachable
2388 unreachable;
24432389 } else {
2444 unreachable
2390 unreachable;
24452391 }
24462392
24472393 // If expressions are used instead of a ternary expression.
......@@ -2499,12 +2445,12 @@ test "if error union" {
24992445 if (a) |value| {
25002446 assert(value == 0);
25012447 } else |err| {
2502 unreachable
2448 unreachable;
25032449 }
25042450
25052451 const b: %u32 = error.BadValue;
25062452 if (b) |value| {
2507 unreachable
2453 unreachable;
25082454 } else |err| {
25092455 assert(err == error.BadValue);
25102456 }
......@@ -2524,27 +2470,26 @@ test "if error union" {
25242470 if (c) |*value| {
25252471 *value = 9;
25262472 } else |err| {
2527 unreachable
2473 unreachable;
25282474 }
25292475
25302476 if (c) |value| {
25312477 assert(value == 9);
25322478 } else |err| {
2533 unreachable
2479 unreachable;
25342480 }
2535}</code></pre>
2536 <pre><code class="sh">$ zig test if.zig
2537Test 1/3 if boolean...OK
2538Test 2/3 if nullable...OK
2539Test 3/3 if error union...OK</code></pre>
2481}
2482 {#code_end#}
25402483 {#see_also|Nullables|Errors#}
25412484 {#header_close#}
25422485 {#header_open|defer#}
2543 <pre><code class="zig">const assert = @import("std").debug.assert;
2544const printf = @import("std").io.stdout.printf;
2486 {#code_begin|test|defer#}
2487const std = @import("std");
2488const assert = std.debug.assert;
2489const warn = std.debug.warn;
25452490
25462491// defer will execute an expression at the end of the current scope.
2547fn deferExample() -&gt; usize {
2492fn deferExample() -> usize {
25482493 var a: usize = 1;
25492494
25502495 {
......@@ -2554,7 +2499,7 @@ fn deferExample() -&gt; usize {
25542499 assert(a == 2);
25552500
25562501 a = 5;
2557 a
2502 return a;
25582503}
25592504
25602505test "defer basics" {
......@@ -2564,24 +2509,24 @@ test "defer basics" {
25642509// If multiple defer statements are specified, they will be executed in
25652510// the reverse order they were run.
25662511fn deferUnwindExample() {
2567 %%printf("\n");
2512 warn("\n");
25682513
25692514 defer {
2570 %%printf("1 ");
2515 warn("1 ");
25712516 }
25722517 defer {
2573 %%printf("2 ");
2518 warn("2 ");
25742519 }
25752520 if (false) {
25762521 // defers are not run if they are never executed.
25772522 defer {
2578 %%printf("3 ");
2523 warn("3 ");
25792524 }
25802525 }
25812526}
25822527
25832528test "defer unwinding" {
2584 deferUnwindExample()
2529 deferUnwindExample();
25852530}
25862531
25872532// The %defer keyword is similar to defer, but will only execute if the
......@@ -2590,16 +2535,16 @@ test "defer unwinding" {
25902535// This is especially useful in allowing a function to clean up properly
25912536// on error, and replaces goto error handling tactics as seen in c.
25922537error DeferError;
2593fn deferErrorExample(is_error: bool) -&gt; %void {
2594 %%printf("\nstart of function\n");
2538fn deferErrorExample(is_error: bool) -> %void {
2539 warn("\nstart of function\n");
25952540
25962541 // This will always be executed on exit
25972542 defer {
2598 %%printf("end of function\n");
2543 warn("end of function\n");
25992544 }
26002545
26012546 %defer {
2602 %%printf("encountered an error!\n");
2547 warn("encountered an error!\n");
26032548 }
26042549
26052550 if (is_error) {
......@@ -2611,20 +2556,7 @@ test "%defer unwinding" {
26112556 _ = deferErrorExample(false);
26122557 _ = deferErrorExample(true);
26132558}
2614</code></pre>
2615 <pre><code class="sh">$ zig test defer.zig
2616Test 1/3 defer basics...OK
2617Test 2/3 defer unwinding...
26182 1 OK
2619Test 3/3 %defer unwinding...
2620start of function
2621end of function
2622
2623start of function
2624encountered an error!
2625end of function
2626OK
2627</code></pre>
2559 {#code_end#}
26282560 {#see_also|Errors#}
26292561 {#header_close#}
26302562 {#header_open|unreachable#}
......@@ -2638,7 +2570,8 @@ OK
26382570 still emits <code>unreachable</code> as calls to <code>panic</code>.
26392571 </p>
26402572 {#header_open|Basics#}
2641 <pre><code class="zig">// unreachable is used to assert that control flow will never happen upon a
2573 {#code_begin|test#}
2574// unreachable is used to assert that control flow will never happen upon a
26422575// particular location:
26432576test "basic math" {
26442577 const x = 1;
......@@ -2647,8 +2580,9 @@ test "basic math" {
26472580 unreachable;
26482581 }
26492582}
2650
2651// in fact, this is how assert is implemented:
2583 {#code_end#}
2584 <p>In fact, this is how assert is implemented:</p>
2585 {#code_begin|test_err#}
26522586fn assert(ok: bool) {
26532587 if (!ok) unreachable; // assertion failure
26542588}
......@@ -2656,47 +2590,24 @@ fn assert(ok: bool) {
26562590// This test will fail because we hit unreachable.
26572591test "this will fail" {
26582592 assert(false);
2659}</code></pre>
2660 <pre><code class="sh">$ zig test test.zig
2661Test 1/2 basic math...OK
2662Test 2/2 this will fail...reached unreachable code
2663test.zig:13:14: 0x00000000002033ac in ??? (test)
2664 if (!ok) unreachable; // assertion failure
2665 ^
2666test.zig:18:11: 0x000000000020329b in ??? (test)
2667 assert(false);
2668 ^
2669lib/zig/std/special/test_runner.zig:9:21: 0x0000000000214a7a in ??? (test)
2670 test_fn.func();
2671 ^
2672lib/zig/std/special/bootstrap.zig:60:21: 0x0000000000214947 in ??? (test)
2673 return root.main();
2674 ^
2675lib/zig/std/special/bootstrap.zig:47:13: 0x0000000000214800 in ??? (test)
2676 callMain(argc, argv, envp) catch std.os.posix.exit(1);
2677 ^
2678lib/zig/std/special/bootstrap.zig:34:25: 0x0000000000214750 in ??? (test)
2679 posixCallMainAndExit()
2680 ^
2681
2682Tests failed. Use the following command to reproduce the failure:
2683./test</code></pre>
2593}
2594 {#code_end#}
26842595 {#header_close#}
26852596 {#header_open|At Compile-Time#}
2686 <pre><code class="zig">const assert = @import("std").debug.assert;
2597 {#code_begin|test_err|unreachable code#}
2598const assert = @import("std").debug.assert;
26872599
2688comptime {
2689 // The type of unreachable is noreturn.
2600test "type of unreachable" {
2601 comptime {
2602 // The type of unreachable is noreturn.
26902603
2691 // However this assertion will still fail because
2692 // evaluating unreachable at compile-time is a compile error.
2604 // However this assertion will still fail because
2605 // evaluating unreachable at compile-time is a compile error.
26932606
2694 assert(@typeOf(unreachable) == noreturn);
2695}</code></pre>
2696 <pre><code class="sh">$ zig build-obj test.zig
2697test.zig:9:12: error: unreachable code
2698 assert(@typeOf(unreachable) == noreturn);
2699 ^</code></pre>
2607 assert(@typeOf(unreachable) == noreturn);
2608 }
2609}
2610 {#code_end#}
27002611 {#see_also|Zig Test|Build Mode|comptime#}
27012612 {#header_close#}
27022613 {#header_close#}
......@@ -2715,31 +2626,38 @@ test.zig:9:12: error: unreachable code
27152626 <p>When resolving types together, such as <code>if</code> clauses or <code>switch</code> prongs,
27162627 the <code>noreturn</code> type is compatible with every other type. Consider:
27172628 </p>
2718 <pre><code class="zig">fn foo(condition: bool, b: u32) {
2629 {#code_begin|test#}
2630fn foo(condition: bool, b: u32) {
27192631 const a = if (condition) b else return;
2720 bar(a);
2632 @panic("do something with a");
27212633}
2722
2723extern fn bar(value: u32);</code></pre>
2634test "noreturn" {
2635 foo(false, 1);
2636}
2637 {#code_end#}
27242638 <p>Another use case for <code>noreturn</code> is the <code>exit</code> function:</p>
2725 <pre><code class="zig">pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: c_uint) -&gt; noreturn;
2639 {#code_begin|test#}
2640 {#target_windows#}
2641pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: c_uint) -> noreturn;
27262642
2727fn foo() {
2643test "foo" {
27282644 const value = bar() catch ExitProcess(1);
27292645 assert(value == 1234);
27302646}
27312647
2732fn bar() -&gt; %u32 {
2648fn bar() -> %u32 {
27332649 return 1234;
27342650}
27352651
2736const assert = @import("std").debug.assert;</code></pre>
2652const assert = @import("std").debug.assert;
2653 {#code_end#}
27372654 {#header_close#}
27382655 {#header_open|Functions#}
2739 <pre><code class="zig">const assert = @import("std").debug.assert;
2656 {#code_begin|test|functions#}
2657const assert = @import("std").debug.assert;
27402658
27412659// Functions are declared like this
2742fn add(a: i8, b: i8) -&gt; i8 {
2660fn add(a: i8, b: i8) -> i8 {
27432661 if (a == 0) {
27442662 // You can still return manually if needed.
27452663 return b;
......@@ -2750,84 +2668,83 @@ fn add(a: i8, b: i8) -&gt; i8 {
27502668
27512669// The export specifier makes a function externally visible in the generated
27522670// object file, and makes it use the C ABI.
2753export fn sub(a: i8, b: i8) -&gt; i8 { a - b }
2671export fn sub(a: i8, b: i8) -> i8 { return a - b; }
27542672
27552673// The extern specifier is used to declare a function that will be resolved
27562674// at link time, when linking statically, or at runtime, when linking
27572675// dynamically.
27582676// The stdcallcc specifier changes the calling convention of the function.
2759extern "kernel32" stdcallcc fn ExitProcess(exit_code: u32) -&gt; noreturn;
2760extern "c" fn atan2(a: f64, b: f64) -&gt; f64;
2677extern "kernel32" stdcallcc fn ExitProcess(exit_code: u32) -> noreturn;
2678extern "c" fn atan2(a: f64, b: f64) -> f64;
27612679
27622680// coldcc makes a function use the cold calling convention.
2763coldcc fn abort() -&gt; noreturn {
2681coldcc fn abort() -> noreturn {
27642682 while (true) {}
27652683}
27662684
27672685// nakedcc makes a function not have any function prologue or epilogue.
27682686// This can be useful when integrating with assembly.
2769nakedcc fn _start() -&gt; noreturn {
2687nakedcc fn _start() -> noreturn {
27702688 abort();
27712689}
27722690
27732691// The pub specifier allows the function to be visible when importing.
27742692// Another file can use @import and call sub2
2775pub fn sub2(a: i8, b: i8) -&gt; i8 { a - b }
2693pub fn sub2(a: i8, b: i8) -> i8 { return a - b; }
27762694
27772695// Functions can be used as values and are equivalent to pointers.
2778const call2_op = fn (a: i8, b: i8) -&gt; i8;
2779fn do_op(fn_call: call2_op, op1: i8, op2: i8) -&gt; i8 {
2780 fn_call(op1, op2)
2696const call2_op = fn (a: i8, b: i8) -> i8;
2697fn do_op(fn_call: call2_op, op1: i8, op2: i8) -> i8 {
2698 return fn_call(op1, op2);
27812699}
27822700
27832701test "function" {
27842702 assert(do_op(add, 5, 6) == 11);
27852703 assert(do_op(sub2, 5, 6) == -1);
2786}</code></pre>
2787 <pre><code class="sh">$ zig test function.zig
2788Test 1/1 function...OK
2789</code></pre>
2704}
2705 {#code_end#}
27902706 <p>Function values are like pointers:</p>
2791 <pre><code class="zig">const assert = @import("std").debug.assert;
2707 {#code_begin|obj#}
2708const assert = @import("std").debug.assert;
27922709
27932710comptime {
27942711 assert(@typeOf(foo) == fn());
27952712 assert(@sizeOf(fn()) == @sizeOf(?fn()));
27962713}
27972714
2798fn foo() { }</code></pre>
2799 <pre><code class="sh">$ zig build-obj test.zig</code></pre>
2715fn foo() { }
2716 {#code_end#}
28002717 {#header_open|Pass-by-value Parameters#}
28012718 <p>
28022719 In Zig, structs, unions, and enums with payloads cannot be passed by value
28032720 to a function.
28042721 </p>
2805 <pre><code class="zig">const Foo = struct {
2722 {#code_begin|test_err|not copyable; cannot pass by value#}
2723const Foo = struct {
28062724 x: i32,
28072725};
28082726
28092727fn bar(foo: Foo) {}
28102728
2811export fn entry() {
2729test "pass aggregate type by value to function" {
28122730 bar(Foo {.x = 12,});
2813}</code></pre>
2814 <pre><code class="sh">$ ./zig build-obj test.zig
2815/home/andy/dev/zig/build/test.zig:5:13: error: type 'Foo' is not copyable; cannot pass by value
2816fn bar(foo: Foo) {}
2817 ^</code></pre>
2731}
2732 {#code_end#}
28182733 <p>
28192734 Instead, one must use <code>&amp;const</code>. Zig allows implicitly casting something
28202735 to a const pointer to it:
28212736 </p>
2822 <pre><code class="zig">const Foo = struct {
2737 {#code_begin|test#}
2738const Foo = struct {
28232739 x: i32,
28242740};
28252741
2826fn bar(foo: &amp;const Foo) {}
2742fn bar(foo: &const Foo) {}
28272743
2828export fn entry() {
2744test "implicitly cast to const pointer" {
28292745 bar(Foo {.x = 12,});
2830}</code></pre>
2746}
2747 {#code_end#}
28312748 <p>
28322749 However,
28332750 the C ABI does allow passing structs and unions by value. So functions which
......@@ -2842,9 +2759,11 @@ export fn entry() {
28422759 <p>
28432760 Among the top level declarations available is the error value declaration:
28442761 </p>
2845 <pre><code class="zig">error FileNotFound;
2762 {#code_begin|syntax#}
2763error FileNotFound;
28462764error OutOfMemory;
2847error UnexpectedToken;</code></pre>
2765error UnexpectedToken;
2766 {#code_end#}
28482767 <p>
28492768 These error values are assigned an unsigned integer value greater than 0 at
28502769 compile time. You are allowed to declare the same error value more than once,
......@@ -2862,7 +2781,7 @@ error UnexpectedToken;</code></pre>
28622781 The pure error type is one of the error values, and in the same way that pointers
28632782 cannot be null, a pure error is always an error.
28642783 </p>
2865 <pre><code class="zig">const pure_error = error.FileNotFound;</code></pre>
2784 {#code_begin|syntax#}const pure_error = error.FileNotFound;{#code_end#}
28662785 <p>
28672786 Most of the time you will not find yourself using a pure error type. Instead,
28682787 likely you will be using the error union type. This is when you take a normal type,
......@@ -2871,32 +2790,48 @@ error UnexpectedToken;</code></pre>
28712790 <p>
28722791 Here is a function to parse a string into a 64-bit integer:
28732792 </p>
2874 <pre><code class="zig">error InvalidChar;
2793 {#code_begin|test#}
2794error InvalidChar;
28752795error Overflow;
28762796
2877pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
2797pub fn parseU64(buf: []const u8, radix: u8) -> %u64 {
28782798 var x: u64 = 0;
28792799
28802800 for (buf) |c| {
28812801 const digit = charToDigit(c);
28822802
2883 if (digit &gt;= radix) {
2803 if (digit >= radix) {
28842804 return error.InvalidChar;
28852805 }
28862806
28872807 // x *= radix
2888 if (@mulWithOverflow(u64, x, radix, &amp;x)) {
2808 if (@mulWithOverflow(u64, x, radix, &x)) {
28892809 return error.Overflow;
28902810 }
28912811
28922812 // x += digit
2893 if (@addWithOverflow(u64, x, digit, &amp;x)) {
2813 if (@addWithOverflow(u64, x, digit, &x)) {
28942814 return error.Overflow;
28952815 }
28962816 }
28972817
28982818 return x;
2899}</code></pre>
2819}
2820
2821fn charToDigit(c: u8) -> u8 {
2822 return switch (c) {
2823 '0' ... '9' => c - '0',
2824 'A' ... 'Z' => c - 'A' + 10,
2825 'a' ... 'z' => c - 'a' + 10,
2826 else => @maxValue(u8),
2827 };
2828}
2829
2830test "parse u64" {
2831 const result = try parseU64("1234", 10);
2832 @import("std").debug.assert(result == 1234);
2833}
2834 {#code_end#}
29002835 <p>
29012836 Notice the return type is <code>%u64</code>. This means that the function
29022837 either returns an unsigned 64 bit integer, or an error.
......@@ -2916,29 +2851,35 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
29162851 <li>You know with complete certainty it will not return an error, so want to unconditionally unwrap it.</li>
29172852 <li>You want to take a different action for each possible error.</li>
29182853 </ul>
2919 <p>If you want to provide a default value, you can use the <code>%%</code> binary operator:</p>
2920 <pre><code class="zig">fn doAThing(str: []u8) {
2854 <p>If you want to provide a default value, you can use the <code>catch</code> binary operator:</p>
2855 {#code_begin|syntax#}
2856fn doAThing(str: []u8) {
29212857 const number = parseU64(str, 10) catch 13;
29222858 // ...
2923}</code></pre>
2859}
2860 {#code_end#}
29242861 <p>
29252862 In this code, <code>number</code> will be equal to the successfully parsed string, or
2926 a default value of 13. The type of the right hand side of the binary <code>%%</code> operator must
2863 a default value of 13. The type of the right hand side of the binary <code>catch</code> operator must
29272864 match the unwrapped error union type, or be of type <code>noreturn</code>.
29282865 </p>
29292866 <p>Let's say you wanted to return the error if you got one, otherwise continue with the
29302867 function logic:</p>
2931 <pre><code class="zig">fn doAThing(str: []u8) -&gt; %void {
2868 {#code_begin|syntax#}
2869fn doAThing(str: []u8) -> %void {
29322870 const number = parseU64(str, 10) catch |err| return err;
29332871 // ...
2934}</code></pre>
2872}
2873 {#code_end#}
29352874 <p>
29362875 There is a shortcut for this. The <code>try</code> expression:
29372876 </p>
2938 <pre><code class="zig">fn doAThing(str: []u8) -&gt; %void {
2877 {#code_begin|syntax#}
2878fn doAThing(str: []u8) -> %void {
29392879 const number = try parseU64(str, 10);
29402880 // ...
2941}</code></pre>
2881}
2882 {#code_end#}
29422883 <p>
29432884 <code>try</code> evaluates an error union expression. If it is an error, it returns
29442885 from the current function with the same error. Otherwise, the expression results in
......@@ -2948,35 +2889,32 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
29482889 Maybe you know with complete certainty that an expression will never be an error.
29492890 In this case you can do this:
29502891 </p>
2951 <pre><code class="zig">const number = parseU64("1234", 10) catch unreachable;</code></pre>
2892 {#code_begin|syntax#}const number = parseU64("1234", 10) catch unreachable;{#code_end#}
29522893 <p>
29532894 Here we know for sure that "1234" will parse successfully. So we put the
29542895 <code>unreachable</code> value on the right hand side. <code>unreachable</code> generates
29552896 a panic in Debug and ReleaseSafe modes and undefined behavior in ReleaseFast mode. So, while we're debugging the
29562897 application, if there <em>was</em> a surprise error here, the application would crash
29572898 appropriately.
2958 </p>
2959 <p>Again there is a syntactic shortcut for this:</p>
2960 <pre><code class="zig">const number = %%parseU64("1234", 10);</code></pre>
2961 <p>
2962 The <code>%%</code> <em>prefix</em> operator is equivalent to <code class="zig">expression catch unreachable</code>. It unwraps an error union type,
2963 and panics in debug mode if the value was an error.
2899 TODO: mention error return traces
29642900 </p>
29652901 <p>
29662902 Finally, you may want to take a different action for every situation. For that, we combine
29672903 the <code>if</code> and <code>switch</code> expression:
29682904 </p>
2969 <pre><code class="zig">fn doAThing(str: []u8) {
2905 {#code_begin|syntax#}
2906fn doAThing(str: []u8) {
29702907 if (parseU64(str, 10)) |number| {
29712908 doSomethingWithNumber(number);
29722909 } else |err| switch (err) {
2973 error.Overflow =&gt; {
2910 error.Overflow => {
29742911 // handle overflow...
29752912 },
29762913 // we promise that InvalidChar won't happen (or crash in debug mode if it does)
2977 error.InvalidChar =&gt; unreachable,
2914 error.InvalidChar => unreachable,
29782915 }
2979}</code></pre>
2916}
2917 {#code_end#}
29802918 <p>
29812919 The other component to error handling is defer statements.
29822920 In addition to an unconditional <code>defer</code>, Zig has <code>%defer</code>,
......@@ -2986,7 +2924,8 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
29862924 <p>
29872925 Example:
29882926 </p>
2989 <pre><code class="zig">fn createFoo(param: i32) -&gt; %Foo {
2927 {#code_begin|syntax#}
2928fn createFoo(param: i32) -> %Foo {
29902929 const foo = try tryToAllocateFoo();
29912930 // now we have allocated foo. we need to free it if the function fails.
29922931 // but we want to return it if the function succeeds.
......@@ -2997,12 +2936,13 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
29972936 // before this block leaves scope
29982937 defer deallocateTmpBuffer(tmp_buf);
29992938
3000 if (param &gt; 1337) return error.InvalidParam;
2939 if (param > 1337) return error.InvalidParam;
30012940
30022941 // here the %defer will not run since we're returning success from the function.
30032942 // but the defer will run!
30042943 return foo;
3005}</code></pre>
2944}
2945 {#code_end#}
30062946 <p>
30072947 The neat thing about this is that you get robust error handling without
30082948 the verbosity and cognitive overhead of trying to make sure every exit path
......@@ -3014,7 +2954,7 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
30142954 <ul>
30152955 <li>These primitives give enough expressiveness that it's completely practical
30162956 to have failing to check for an error be a compile error. If you really want
3017 to ignore the error, you can use the <code>%%</code> prefix operator and
2957 to ignore the error, you can add <code>catch unreachable</code> and
30182958 get the added benefit of crashing in Debug and ReleaseSafe modes if your assumption was wrong.
30192959 </li>
30202960 <li>
......@@ -3034,11 +2974,13 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
30342974 The question mark symbolizes the nullable type. You can convert a type to a nullable
30352975 type by putting a question mark in front of it, like this:
30362976 </p>
3037 <pre><code class="zig">// normal integer
2977 {#code_begin|syntax#}
2978// normal integer
30382979const normal_int: i32 = 1234;
30392980
30402981// nullable integer
3041const nullable_int: ?i32 = 5678;</code></pre>
2982const nullable_int: ?i32 = 5678;
2983 {#code_end#}
30422984 <p>
30432985 Now the variable <code>nullable_int</code> could be an <code>i32</code>, or <code>null</code>.
30442986 </p>
......@@ -3061,7 +3003,7 @@ const nullable_int: ?i32 = 5678;</code></pre>
30613003 Task: call malloc, if the result is null, return null.
30623004 </p>
30633005 <p>C code</p>
3064 <pre><code class="c">// malloc prototype included for reference
3006 <pre><code class="cpp">// malloc prototype included for reference
30653007void *malloc(size_t size);
30663008
30673009struct Foo *do_a_thing(void) {
......@@ -3070,23 +3012,25 @@ struct Foo *do_a_thing(void) {
30703012 // ...
30713013}</code></pre>
30723014 <p>Zig code</p>
3073 <pre><code class="zig">// malloc prototype included for reference
3074extern fn malloc(size: size_t) -&gt; ?&amp;u8;
3015 {#code_begin|syntax#}
3016// malloc prototype included for reference
3017extern fn malloc(size: size_t) -> ?&u8;
30753018
3076fn doAThing() -&gt; ?&amp;Foo {
3019fn doAThing() -> ?&Foo {
30773020 const ptr = malloc(1234) ?? return null;
30783021 // ...
3079}</code></pre>
3022}
3023 {#code_end#}
30803024 <p>
30813025 Here, Zig is at least as convenient, if not more, than C. And, the type of "ptr"
3082 is <code>&amp;u8</code> <em>not</em> <code>?&amp;u8</code>. The <code>??</code> operator
3026 is <code>&u8</code> <em>not</em> <code>?&u8</code>. The <code>??</code> operator
30833027 unwrapped the nullable type and therefore <code>ptr</code> is guaranteed to be non-null everywhere
30843028 it is used in the function.
30853029 </p>
30863030 <p>
30873031 The other form of checking against NULL you might see looks like this:
30883032 </p>
3089 <pre><code class="c">void do_a_thing(struct Foo *foo) {
3033 <pre><code class="cpp">void do_a_thing(struct Foo *foo) {
30903034 // do some stuff
30913035
30923036 if (foo) {
......@@ -3098,7 +3042,8 @@ fn doAThing() -&gt; ?&amp;Foo {
30983042 <p>
30993043 In Zig you can accomplish the same thing:
31003044 </p>
3101 <pre><code class="zig">fn doAThing(nullable_foo: ?&amp;Foo) {
3045 {#code_begin|syntax#}
3046fn doAThing(nullable_foo: ?&Foo) {
31023047 // do some stuff
31033048
31043049 if (nullable_foo) |foo| {
......@@ -3106,7 +3051,8 @@ fn doAThing() -&gt; ?&amp;Foo {
31063051 }
31073052
31083053 // do some stuff
3109}</code></pre>
3054}
3055 {#code_end#}
31103056 <p>
31113057 Once again, the notable thing here is that inside the if block,
31123058 <code>foo</code> is no longer a nullable pointer, it is a pointer, which
......@@ -3153,15 +3099,17 @@ fn doAThing() -&gt; ?&amp;Foo {
31533099 <p>
31543100 Compile-time parameters is how Zig implements generics. It is compile-time duck typing.
31553101 </p>
3156 <pre><code class="zig">fn max(comptime T: type, a: T, b: T) -&gt; T {
3157 if (a &gt; b) a else b
3102 {#code_begin|syntax#}
3103fn max(comptime T: type, a: T, b: T) -> T {
3104 return if (a > b) a else b;
31583105}
3159fn gimmeTheBiggerFloat(a: f32, b: f32) -&gt; f32 {
3160 max(f32, a, b)
3106fn gimmeTheBiggerFloat(a: f32, b: f32) -> f32 {
3107 return max(f32, a, b);
31613108}
3162fn gimmeTheBiggerInteger(a: u64, b: u64) -&gt; u64 {
3163 max(u64, a, b)
3164}</code></pre>
3109fn gimmeTheBiggerInteger(a: u64, b: u64) -> u64 {
3110 return max(u64, a, b);
3111}
3112 {#code_end#}
31653113 <p>
31663114 In Zig, types are first-class citizens. They can be assigned to variables, passed as parameters to functions,
31673115 and returned from functions. However, they can only be used in expressions which are known at <em>compile-time</em>,
......@@ -3179,21 +3127,20 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) -&gt; u64 {
31793127 <p>
31803128 For example, if we were to introduce another function to the above snippet:
31813129 </p>
3182 <pre><code class="zig">fn max(comptime T: type, a: T, b: T) -&gt; T {
3183 if (a &gt; b) a else b
3130 {#code_begin|test_err|unable to evaluate constant expression#}
3131fn max(comptime T: type, a: T, b: T) -> T {
3132 return if (a > b) a else b;
31843133}
3185fn letsTryToPassARuntimeType(condition: bool) {
3134test "try to pass a runtime type" {
3135 foo(false);
3136}
3137fn foo(condition: bool) {
31863138 const result = max(
31873139 if (condition) f32 else u64,
31883140 1234,
31893141 5678);
3190}</code></pre>
3191 <p>
3192 Then we get this result from the compiler:
3193 </p>
3194 <pre><code class="sh">./test.zig:6:9: error: unable to evaluate constant expression
3195 if (condition) f32 else u64,
3196 ^</code></pre>
3142}
3143 {#code_end#}
31973144 <p>
31983145 This is an error because the programmer attempted to pass a value only known at run-time
31993146 to a function which expects a value known at compile-time.
......@@ -3205,38 +3152,33 @@ fn letsTryToPassARuntimeType(condition: bool) {
32053152 <p>
32063153 For example:
32073154 </p>
3208 <pre><code class="zig">fn max(comptime T: type, a: T, b: T) -&gt; T {
3209 if (a &gt; b) a else b
3155 {#code_begin|test_err|operator not allowed for type 'bool'#}
3156fn max(comptime T: type, a: T, b: T) -> T {
3157 return if (a > b) a else b;
32103158}
3211fn letsTryToCompareBools(a: bool, b: bool) -&gt; bool {
3212 max(bool, a, b)
3213}</code></pre>
3214 <p>
3215 The code produces this error message:
3216 </p>
3217 <pre><code>./test.zig:2:11: error: operator not allowed for type 'bool'
3218 if (a &gt; b) a else b
3219 ^
3220./test.zig:5:8: note: called from here
3221 max(bool, a, b)
3222 ^</code></pre>
3159test "try to compare bools" {
3160 _ = max(bool, true, false);
3161}
3162 {#code_end#}
32233163 <p>
32243164 On the flip side, inside the function definition with the <code>comptime</code> parameter, the
32253165 value is known at compile-time. This means that we actually could make this work for the bool type
32263166 if we wanted to:
32273167 </p>
3228 <pre><code class="zig">fn max(comptime T: type, a: T, b: T) -&gt; T {
3168 {#code_begin|test#}
3169fn max(comptime T: type, a: T, b: T) -> T {
32293170 if (T == bool) {
32303171 return a or b;
3231 } else if (a &gt; b) {
3172 } else if (a > b) {
32323173 return a;
32333174 } else {
32343175 return b;
32353176 }
32363177}
3237fn letsTryToCompareBools(a: bool, b: bool) -&gt; bool {
3238 max(bool, a, b)
3239}</code></pre>
3178test "try to compare bools" {
3179 @import("std").debug.assert(max(bool, false, true) == true);
3180}
3181 {#code_end#}
32403182 <p>
32413183 This works because Zig implicitly inlines <code>if</code> expressions when the condition
32423184 is known at compile-time, and the compiler guarantees that it will skip analysis of
......@@ -3246,9 +3188,11 @@ fn letsTryToCompareBools(a: bool, b: bool) -&gt; bool {
32463188 This means that the actual function generated for <code>max</code> in this situation looks like
32473189 this:
32483190 </p>
3249 <pre><code class="zig">fn max(a: bool, b: bool) -&gt; bool {
3191 {#code_begin|syntax#}
3192fn max(a: bool, b: bool) -> bool {
32503193 return a or b;
3251}</code></pre>
3194}
3195 {#code_end#}
32523196 <p>
32533197 All the code that dealt with compile-time known values is eliminated and we are left with only
32543198 the necessary run-time code to accomplish the task.
......@@ -3271,11 +3215,12 @@ fn letsTryToCompareBools(a: bool, b: bool) -&gt; bool {
32713215 <p>
32723216 For example:
32733217 </p>
3274 <pre><code class="zig">const assert = @import("std").debug.assert;
3218 {#code_begin|test|comptime_vars#}
3219const assert = @import("std").debug.assert;
32753220
32763221const CmdFn = struct {
32773222 name: []const u8,
3278 func: fn(i32) -&gt; i32,
3223 func: fn(i32) -> i32,
32793224};
32803225
32813226const cmd_fns = []CmdFn{
......@@ -3283,14 +3228,14 @@ const cmd_fns = []CmdFn{
32833228 CmdFn {.name = "two", .func = two},
32843229 CmdFn {.name = "three", .func = three},
32853230};
3286fn one(value: i32) -&gt; i32 { value + 1 }
3287fn two(value: i32) -&gt; i32 { value + 2 }
3288fn three(value: i32) -&gt; i32 { value + 3 }
3231fn one(value: i32) -> i32 { return value + 1; }
3232fn two(value: i32) -> i32 { return value + 2; }
3233fn three(value: i32) -> i32 { return value + 3; }
32893234
3290fn performFn(comptime prefix_char: u8, start_value: i32) -&gt; i32 {
3235fn performFn(comptime prefix_char: u8, start_value: i32) -> i32 {
32913236 var result: i32 = start_value;
32923237 comptime var i = 0;
3293 inline while (i &lt; cmd_fns.len) : (i += 1) {
3238 inline while (i < cmd_fns.len) : (i += 1) {
32943239 if (cmd_fns[i].name[0] == prefix_char) {
32953240 result = cmd_fns[i].func(result);
32963241 }
......@@ -3302,37 +3247,42 @@ test "perform fn" {
33023247 assert(performFn('t', 1) == 6);
33033248 assert(performFn('o', 0) == 1);
33043249 assert(performFn('w', 99) == 99);
3305}</code></pre>
3250}
3251 {#code_end#}
33063252 <p>
33073253 This example is a bit contrived, because the compile-time evaluation component is unnecessary;
33083254 this code would work fine if it was all done at run-time. But it does end up generating
33093255 different code. In this example, the function <code>performFn</code> is generated three different times,
33103256 for the different values of <code>prefix_char</code> provided:
33113257 </p>
3312 <pre><code class="zig">// From the line:
3258 {#code_begin|syntax#}
3259// From the line:
33133260// assert(performFn('t', 1) == 6);
3314fn performFn(start_value: i32) -&gt; i32 {
3261fn performFn(start_value: i32) -> i32 {
33153262 var result: i32 = start_value;
33163263 result = two(result);
33173264 result = three(result);
33183265 return result;
33193266}
3320
3267 {#code_end#}
3268 {#code_begin|syntax#}
33213269// From the line:
33223270// assert(performFn('o', 0) == 1);
3323fn performFn(start_value: i32) -&gt; i32 {
3271fn performFn(start_value: i32) -> i32 {
33243272 var result: i32 = start_value;
33253273 result = one(result);
33263274 return result;
33273275}
3328
3276 {#code_end#}
3277 {#code_begin|syntax#}
33293278// From the line:
33303279// assert(performFn('w', 99) == 99);
3331fn performFn(start_value: i32) -&gt; i32 {
3280fn performFn(start_value: i32) -> i32 {
33323281 var result: i32 = start_value;
33333282 return result;
3334}</code></pre>
3335 <p>
3283}
3284 {#code_end#}
3285 <p>
33363286 Note that this happens even in a debug build; in a release build these generated functions still
33373287 pass through rigorous LLVM optimizations. The important thing to note, however, is not that this
33383288 is a way to write more optimized code, but that it is a way to make sure that what <em>should</em> happen
......@@ -3347,16 +3297,15 @@ fn performFn(start_value: i32) -&gt; i32 {
33473297 use a <code>comptime</code> expression to guarantee that the expression will be evaluated at compile-time.
33483298 If this cannot be accomplished, the compiler will emit an error. For example:
33493299 </p>
3350 <pre><code class="zig">extern fn exit() -&gt; unreachable;
3300 {#code_begin|test_err|unable to evaluate constant expression#}
3301extern fn exit() -> noreturn;
33513302
3352fn foo() {
3303test "foo" {
33533304 comptime {
33543305 exit();
33553306 }
3356}</code></pre>
3357 <pre><code>./test.zig:5:9: error: unable to evaluate constant expression
3358 exit();
3359 ^</code></pre>
3307}
3308 {#code_end#}
33603309 <p>
33613310 It doesn't make sense that a program could call <code>exit()</code> (or any other external function)
33623311 at compile-time, so this is a compile error. However, a <code>comptime</code> expression does much
......@@ -3379,10 +3328,11 @@ fn foo() {
33793328 <p>
33803329 Let's look at an example:
33813330 </p>
3382 <pre><code class="zig">const assert = @import("std").debug.assert;
3331 {#code_begin|test#}
3332const assert = @import("std").debug.assert;
33833333
3384fn fibonacci(index: u32) -&gt; u32 {
3385 if (index &lt; 2) return index;
3334fn fibonacci(index: u32) -> u32 {
3335 if (index < 2) return index;
33863336 return fibonacci(index - 1) + fibonacci(index - 2);
33873337}
33883338
......@@ -3394,16 +3344,16 @@ test "fibonacci" {
33943344 comptime {
33953345 assert(fibonacci(7) == 13);
33963346 }
3397}</code></pre>
3398 <pre><code>$ zig test test.zig
3399Test 1/1 testFibonacci...OK</code></pre>
3347}
3348 {#code_end#}
34003349 <p>
34013350 Imagine if we had forgotten the base case of the recursive function and tried to run the tests:
34023351 </p>
3403 <pre><code class="zig">const assert = @import("std").debug.assert;
3352 {#code_begin|test_err|operation caused overflow#}
3353const assert = @import("std").debug.assert;
34043354
3405fn fibonacci(index: u32) -&gt; u32 {
3406 //if (index &lt; 2) return index;
3355fn fibonacci(index: u32) -> u32 {
3356 //if (index < 2) return index;
34073357 return fibonacci(index - 1) + fibonacci(index - 2);
34083358}
34093359
......@@ -3411,35 +3361,8 @@ test "fibonacci" {
34113361 comptime {
34123362 assert(fibonacci(7) == 13);
34133363 }
3414}</code></pre>
3415 <pre><code>$ zig test test.zig
3416./test.zig:3:28: error: operation caused overflow
3417 return fibonacci(index - 1) + fibonacci(index - 2);
3418 ^
3419./test.zig:3:21: note: called from here
3420 return fibonacci(index - 1) + fibonacci(index - 2);
3421 ^
3422./test.zig:3:21: note: called from here
3423 return fibonacci(index - 1) + fibonacci(index - 2);
3424 ^
3425./test.zig:3:21: note: called from here
3426 return fibonacci(index - 1) + fibonacci(index - 2);
3427 ^
3428./test.zig:3:21: note: called from here
3429 return fibonacci(index - 1) + fibonacci(index - 2);
3430 ^
3431./test.zig:3:21: note: called from here
3432 return fibonacci(index - 1) + fibonacci(index - 2);
3433 ^
3434./test.zig:3:21: note: called from here
3435 return fibonacci(index - 1) + fibonacci(index - 2);
3436 ^
3437./test.zig:3:21: note: called from here
3438 return fibonacci(index - 1) + fibonacci(index - 2);
3439 ^
3440./test.zig:14:25: note: called from here
3441 assert(fibonacci(7) == 13);
3442 ^</code></pre>
3364}
3365 {#code_end#}
34433366 <p>
34443367 The compiler produces an error which is a stack trace from trying to evaluate the
34453368 function at compile-time.
......@@ -3449,10 +3372,11 @@ test "fibonacci" {
34493372 undefined behavior, which is always a compile error if the compiler knows it happened.
34503373 But what would have happened if we used a signed integer?
34513374 </p>
3452 <pre><code class="zig">const assert = @import("std").debug.assert;
3375 {#code_begin|test_err|evaluation exceeded 1000 backwards branches#}
3376const assert = @import("std").debug.assert;
34533377
3454fn fibonacci(index: i32) -&gt; i32 {
3455 //if (index &lt; 2) return index;
3378fn fibonacci(index: i32) -> i32 {
3379 //if (index < 2) return index;
34563380 return fibonacci(index - 1) + fibonacci(index - 2);
34573381}
34583382
......@@ -3460,43 +3384,8 @@ test "fibonacci" {
34603384 comptime {
34613385 assert(fibonacci(7) == 13);
34623386 }
3463}</code></pre>
3464 <pre><code>./test.zig:3:21: error: evaluation exceeded 1000 backwards branches
3465 return fibonacci(index - 1) + fibonacci(index - 2);
3466 ^
3467./test.zig:3:21: note: called from here
3468 return fibonacci(index - 1) + fibonacci(index - 2);
3469 ^
3470./test.zig:3:21: note: called from here
3471 return fibonacci(index - 1) + fibonacci(index - 2);
3472 ^
3473./test.zig:3:21: note: called from here
3474 return fibonacci(index - 1) + fibonacci(index - 2);
3475 ^
3476./test.zig:3:21: note: called from here
3477 return fibonacci(index - 1) + fibonacci(index - 2);
3478 ^
3479./test.zig:3:21: note: called from here
3480 return fibonacci(index - 1) + fibonacci(index - 2);
3481 ^
3482./test.zig:3:21: note: called from here
3483 return fibonacci(index - 1) + fibonacci(index - 2);
3484 ^
3485./test.zig:3:21: note: called from here
3486 return fibonacci(index - 1) + fibonacci(index - 2);
3487 ^
3488./test.zig:3:21: note: called from here
3489 return fibonacci(index - 1) + fibonacci(index - 2);
3490 ^
3491./test.zig:3:21: note: called from here
3492 return fibonacci(index - 1) + fibonacci(index - 2);
3493 ^
3494./test.zig:3:21: note: called from here
3495 return fibonacci(index - 1) + fibonacci(index - 2);
3496 ^
3497./test.zig:3:21: note: called from here
3498 return fibonacci(index - 1) + fibonacci(index - 2);
3499 ^</code></pre>
3387}
3388 {#code_end#}
35003389 <p>
35013390 The compiler noticed that evaluating this function at compile-time took a long time,
35023391 and thus emitted a compile error and gave up. If the programmer wants to increase
......@@ -3506,15 +3395,20 @@ test "fibonacci" {
35063395 <p>
35073396 What if we fix the base case, but put the wrong value in the <code>assert</code> line?
35083397 </p>
3509 <pre><code class="zig">comptime {
3510 assert(fibonacci(7) == 99999);
3511}</code></pre>
3512 <pre><code>./test.zig:15:14: error: unable to evaluate constant expression
3513 if (!ok) unreachable;
3514 ^
3515./test.zig:10:15: note: called from here
3398 {#code_begin|test_err|encountered @panic at compile-time#}
3399const assert = @import("std").debug.assert;
3400
3401fn fibonacci(index: i32) -> i32 {
3402 if (index < 2) return index;
3403 return fibonacci(index - 1) + fibonacci(index - 2);
3404}
3405
3406test "fibonacci" {
3407 comptime {
35163408 assert(fibonacci(7) == 99999);
3517 ^</code></pre>
3409 }
3410}
3411 {#code_end#}
35183412 <p>
35193413 What happened is Zig started interpreting the <code>assert</code> function with the
35203414 parameter <code>ok</code> set to <code>false</code>. When the interpreter hit
......@@ -3528,17 +3422,18 @@ test "fibonacci" {
35283422 <code>comptime</code> expressions. This means that we can use functions to
35293423 initialize complex static data. For example:
35303424 </p>
3531 <pre><code class="zig">const first_25_primes = firstNPrimes(25);
3425 {#code_begin|test#}
3426const first_25_primes = firstNPrimes(25);
35323427const sum_of_first_25_primes = sum(first_25_primes);
35333428
3534fn firstNPrimes(comptime n: usize) -&gt; [n]i32 {
3429fn firstNPrimes(comptime n: usize) -> [n]i32 {
35353430 var prime_list: [n]i32 = undefined;
35363431 var next_index: usize = 0;
35373432 var test_number: i32 = 2;
3538 while (next_index &lt; prime_list.len) : (test_number += 1) {
3433 while (next_index < prime_list.len) : (test_number += 1) {
35393434 var test_prime_index: usize = 0;
35403435 var is_prime = true;
3541 while (test_prime_index &lt; next_index) : (test_prime_index += 1) {
3436 while (test_prime_index < next_index) : (test_prime_index += 1) {
35423437 if (test_number % prime_list[test_prime_index] == 0) {
35433438 is_prime = false;
35443439 break;
......@@ -3552,19 +3447,24 @@ fn firstNPrimes(comptime n: usize) -&gt; [n]i32 {
35523447 return prime_list;
35533448}
35543449
3555fn sum(numbers: []i32) -&gt; i32 {
3450fn sum(numbers: []const i32) -> i32 {
35563451 var result: i32 = 0;
35573452 for (numbers) |x| {
35583453 result += x;
35593454 }
35603455 return result;
3561}</code></pre>
3456}
3457
3458test "variable values" {
3459 @import("std").debug.assert(sum_of_first_25_primes == 1060);
3460}
3461 {#code_end#}
35623462 <p>
35633463 When we compile this program, Zig generates the constants
35643464 with the answer pre-computed. Here are the lines from the generated LLVM IR:
35653465 </p>
3566 <pre><code>@0 = internal unnamed_addr constant [25 x i32] [i32 2, i32 3, i32 5, i32 7, i32 11, i32 13, i32 17, i32 19, i32 23, i32 29, i32 31, i32 37, i32 41, i32 43, i32 47, i32 53, i32 59, i32 61, i32 67, i32 71, i32 73, i32 79, i32 83, i32 89, i32 97]
3567 @1 = internal unnamed_addr constant i32 1060</code></pre>
3466 <pre><code class="llvm">@0 = internal unnamed_addr constant [25 x i32] [i32 2, i32 3, i32 5, i32 7, i32 11, i32 13, i32 17, i32 19, i32 23, i32 29, i32 31, i32 37, i32 41, i32 43, i32 47, i32 53, i32 59, i32 61, i32 67, i32 71, i32 73, i32 79, i32 83, i32 89, i32 97]
3467@1 = internal unnamed_addr constant i32 1060</code></pre>
35683468 <p>
35693469 Note that we did not have to do anything special with the syntax of these functions. For example,
35703470 we could call the <code>sum</code> function as is with a slice of numbers whose length and values were
......@@ -3582,12 +3482,14 @@ fn sum(numbers: []i32) -&gt; i32 {
35823482 Here is an example of a generic <code>List</code> data structure, that we will instantiate with
35833483 the type <code>i32</code>. In Zig we refer to the type as <code>List(i32)</code>.
35843484 </p>
3585 <pre><code class="zig">fn List(comptime T: type) -&gt; type {
3586 struct {
3485 {#code_begin|syntax#}
3486fn List(comptime T: type) -> type {
3487 return struct {
35873488 items: []T,
35883489 len: usize,
3589 }
3590}</code></pre>
3490 };
3491}
3492 {#code_end#}
35913493 <p>
35923494 That's it. It's a function that returns an anonymous <code>struct</code>. For the purposes of error messages
35933495 and debugging, Zig infers the name <code>"List(i32)"</code> from the function name and parameters invoked when creating
......@@ -3597,10 +3499,12 @@ fn sum(numbers: []i32) -&gt; i32 {
35973499 To keep the language small and uniform, all aggregate types in Zig are anonymous. To give a type
35983500 a name, we assign it to a constant:
35993501 </p>
3600 <pre><code class="zig">const Node = struct {
3601 next: &amp;Node,
3502 {#code_begin|syntax#}
3503const Node = struct {
3504 next: &Node,
36023505 name: []u8,
3603};</code></pre>
3506};
3507 {#code_end#}
36043508 <p>
36053509 This works because all top level declarations are order-independent, and as long as there isn't
36063510 an actual infinite regression, values can refer to themselves, directly or indirectly. In this case,
......@@ -3627,8 +3531,9 @@ pub fn main() {
36273531 Let's crack open the implementation of this and see how it works:
36283532 </p>
36293533
3630 <pre><code class="zig">/// Calls print and then flushes the buffer.
3631pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt; %void {
3534 {#code_begin|syntax#}
3535/// Calls print and then flushes the buffer.
3536pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) -> %void {
36323537 const State = enum {
36333538 Start,
36343539 OpenBrace,
......@@ -3641,36 +3546,36 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt
36413546
36423547 inline for (format) |c, i| {
36433548 switch (state) {
3644 State.Start =&gt; switch (c) {
3645 '{' =&gt; {
3646 if (start_index &lt; i) try self.write(format[start_index...i]);
3549 State.Start => switch (c) {
3550 '{' => {
3551 if (start_index < i) try self.write(format[start_index..i]);
36473552 state = State.OpenBrace;
36483553 },
3649 '}' =&gt; {
3650 if (start_index &lt; i) try self.write(format[start_index...i]);
3554 '}' => {
3555 if (start_index < i) try self.write(format[start_index..i]);
36513556 state = State.CloseBrace;
36523557 },
3653 else =&gt; {},
3558 else => {},
36543559 },
3655 State.OpenBrace =&gt; switch (c) {
3656 '{' =&gt; {
3560 State.OpenBrace => switch (c) {
3561 '{' => {
36573562 state = State.Start;
36583563 start_index = i;
36593564 },
3660 '}' =&gt; {
3565 '}' => {
36613566 try self.printValue(args[next_arg]);
36623567 next_arg += 1;
36633568 state = State.Start;
36643569 start_index = i + 1;
36653570 },
3666 else =&gt; @compileError("Unknown format character: " ++ c),
3571 else => @compileError("Unknown format character: " ++ c),
36673572 },
3668 State.CloseBrace =&gt; switch (c) {
3669 '}' =&gt; {
3573 State.CloseBrace => switch (c) {
3574 '}' => {
36703575 state = State.Start;
36713576 start_index = i;
36723577 },
3673 else =&gt; @compileError("Single '}' encountered in format string"),
3578 else => @compileError("Single '}' encountered in format string"),
36743579 },
36753580 }
36763581 }
......@@ -3682,11 +3587,12 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt
36823587 @compileError("Incomplete format string: " ++ format);
36833588 }
36843589 }
3685 if (start_index &lt; format.len) {
3686 try self.write(format[start_index...format.len]);
3590 if (start_index < format.len) {
3591 try self.write(format[start_index..format.len]);
36873592 }
36883593 try self.flush();
3689}</code></pre>
3594}
3595 {#code_end#}
36903596 <p>
36913597 This is a proof of concept implementation; the actual function in the standard library has more
36923598 formatting capabilities.
......@@ -3698,19 +3604,22 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt
36983604 When this function is analyzed from our example code above, Zig partially evaluates the function
36993605 and emits a function that actually looks like this:
37003606 </p>
3701 <pre><code class="zig">pub fn printf(self: &amp;OutStream, arg0: i32, arg1: []const u8) -&gt; %void {
3607 {#code_begin|syntax#}
3608pub fn printf(self: &OutStream, arg0: i32, arg1: []const u8) -> %void {
37023609 try self.write("here is a string: '");
37033610 try self.printValue(arg0);
37043611 try self.write("' here is a number: ");
37053612 try self.printValue(arg1);
37063613 try self.write("\n");
37073614 try self.flush();
3708}</code></pre>
3615}
3616 {#code_end#}
37093617 <p>
37103618 <code>printValue</code> is a function that takes a parameter of any type, and does different things depending
37113619 on the type:
37123620 </p>
3713 <pre><code class="zig">pub fn printValue(self: &amp;OutStream, value: var) -&gt; %void {
3621 {#code_begin|syntax#}
3622pub fn printValue(self: &OutStream, value: var) -> %void {
37143623 const T = @typeOf(value);
37153624 if (@isInteger(T)) {
37163625 return self.printInt(T, value);
......@@ -3722,18 +3631,22 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt
37223631 } else {
37233632 @compileError("Unable to print type '" ++ @typeName(T) ++ "'");
37243633 }
3725}</code></pre>
3634}
3635 {#code_end#}
37263636 <p>
37273637 And now, what happens if we give too many arguments to <code>printf</code>?
37283638 </p>
3729 <pre><code class="zig">warn("here is a string: '{}' here is a number: {}\n",
3730 a_string, a_number, a_number);</code></pre>
3731 <pre><code>.../std/io.zig:147:17: error: Unused arguments
3732 @compileError("Unused arguments");
3733 ^
3734./test.zig:7:23: note: called from here
3735 warn("here is a number: {} and here is a string: {}\n",
3736 ^</code></pre>
3639 {#code_begin|test_err|Unused arguments#}
3640const warn = @import("std").debug.warn;
3641
3642const a_number: i32 = 1234;
3643const a_string = "foobar";
3644
3645test "printf too many arguments" {
3646 warn("here is a string: '{}' here is a number: {}\n",
3647 a_string, a_number, a_number);
3648}
3649 {#code_end#}
37373650 <p>
37383651 Zig gives programmers the tools needed to protect themselves against their own mistakes.
37393652 </p>
......@@ -3786,7 +3699,7 @@ pub fn main() {
37863699 at compile time.
37873700 </p>
37883701 {#header_open|@addWithOverflow#}
3789 <pre><code class="zig">@addWithOverflow(comptime T: type, a: T, b: T, result: &amp;T) -&gt; bool</code></pre>
3702 <pre><code class="zig">@addWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
37903703 <p>
37913704 Performs <code>*result = a + b</code>. If overflow or underflow occurs,
37923705 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
......@@ -3849,7 +3762,7 @@ pub fn main() {
38493762 </p>
38503763 <pre><code class="zig">const assert = @import("std").debug.assert;
38513764comptime {
3852 assert(&amp;u32 == &amp;align(@alignOf(u32)) u32);
3765 assert(&u32 == &align(@alignOf(u32)) u32);
38533766}</code></pre>
38543767 <p>
38553768 The result is a target-specific compile time constant. It is guaranteed to be
......@@ -3933,7 +3846,7 @@ comptime {
39333846
39343847 {#header_close#}
39353848 {#header_open|@cmpxchg#}
3936 <pre><code class="zig">@cmpxchg(ptr: &amp;T, cmp: T, new: T, success_order: AtomicOrder, fail_order: AtomicOrder) -&gt; bool</code></pre>
3849 <pre><code class="zig">@cmpxchg(ptr: &T, cmp: T, new: T, success_order: AtomicOrder, fail_order: AtomicOrder) -&gt; bool</code></pre>
39373850 <p>
39383851 This function performs an atomic compare exchange operation.
39393852 </p>
......@@ -3970,42 +3883,46 @@ comptime {
39703883 This function can be used to do "printf debugging" on
39713884 compile-time executing code.
39723885 </p>
3973<pre><code class="zig">const warn = @import("std").debug.warn;
3886 {#code_begin|test_err|found compile log statement#}
3887const warn = @import("std").debug.warn;
39743888
3975const num1 = {
3889const num1 = blk: {
39763890 var val1: i32 = 99;
39773891 @compileLog("comptime val1 = ", val1);
39783892 val1 = val1 + 1;
3979 val1
3893 break :blk val1;
39803894};
39813895
3982pub fn main() -&gt; %void {
3896test "main" {
39833897 @compileLog("comptime in main");
39843898
39853899 warn("Runtime in main, num1 = {}.\n", num1);
3986}</code></pre>
3987
3900}
3901 {#code_end#}
39883902 </p>
39893903 <p>
39903904 will ouput:
39913905 </p>
3992
3993<pre><code class="sh">$ zig build-exe test.zig
3994| "comptime in main"
3995| "comptime val1 = ", 99
3996test.zig:14:5: error: found compile log statement
3997 @compileLog("comptime in main");
3998 ^
3999test.zig:6:2: error: found compile log statement
4000 @compileLog("comptime val1 = ", val1);
4001 ^</code></pre>
40023906 <p>
40033907 If all <code>@compileLog</code> calls are removed or
40043908 not encountered by analysis, the
40053909 program compiles successfully and the generated executable prints:
40063910 </p>
4007<pre><code class="sh">Runtime in main, num1 = 100.</code></pre>
4008{{@ctheader_open:z}}
3911 {#code_begin|test#}
3912const warn = @import("std").debug.warn;
3913
3914const num1 = blk: {
3915 var val1: i32 = 99;
3916 val1 = val1 + 1;
3917 break :blk val1;
3918};
3919
3920test "main" {
3921 warn("Runtime in main, num1 = {}.\n", num1);
3922}
3923 {#code_end#}
3924 {#header_close#}
3925 {#header_open|@ctz#}
40093926 <pre><code class="zig">@ctz(x: T) -&gt; U</code></pre>
40103927 <p>
40113928 This function counts the number of trailing zeroes in <code>x</code> which is an integer
......@@ -4110,7 +4027,7 @@ test.zig:6:2: error: found compile log statement
41104027 </p>
41114028 {#header_close#}
41124029 {#header_open|@errorReturnTrace#}
4113 <pre><code class="zig">@errorReturnTrace() -&gt; ?&amp;builtin.StackTrace</code></pre>
4030 <pre><code class="zig">@errorReturnTrace() -&gt; ?&builtin.StackTrace</code></pre>
41144031 <p>
41154032 If the binary is built with error return tracing, and this function is invoked in a
41164033 function that calls a function with an error or error union return type, returns a
......@@ -4129,7 +4046,7 @@ test.zig:6:2: error: found compile log statement
41294046 {#header_close#}
41304047 {#header_open|@fieldParentPtr#}
41314048 <pre><code class="zig">@fieldParentPtr(comptime ParentType: type, comptime field_name: []const u8,
4132 field_ptr: &amp;T) -&gt; &amp;ParentType</code></pre>
4049 field_ptr: &T) -&gt; &ParentType</code></pre>
41334050 <p>
41344051 Given a pointer to a field, returns the base pointer of a struct.
41354052 </p>
......@@ -4173,12 +4090,15 @@ test.zig:6:2: error: found compile log statement
41734090 <p>
41744091 This calls a function, in the same way that invoking an expression with parentheses does:
41754092 </p>
4176 <pre><code class="zig">const assert = @import("std").debug.assert;
4093 {#code_begin|test#}
4094const assert = @import("std").debug.assert;
4095
41774096test "inline function call" {
41784097 assert(@inlineCall(add, 3, 9) == 12);
41794098}
41804099
4181fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
4100fn add(a: i32, b: i32) -> i32 { return a + b; }
4101 {#code_end#}
41824102 <p>
41834103 Unlike a normal function call, however, <code>@inlineCall</code> guarantees that the call
41844104 will be inlined. If the call cannot be inlined, a compile error is emitted.
......@@ -4222,7 +4142,7 @@ fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
42224142 <p>TODO</p>
42234143 {#header_close#}
42244144 {#header_open|@memcpy#}
4225 <pre><code class="zig">@memcpy(noalias dest: &amp;u8, noalias source: &amp;const u8, byte_count: usize)</code></pre>
4145 <pre><code class="zig">@memcpy(noalias dest: &u8, noalias source: &const u8, byte_count: usize)</code></pre>
42264146 <p>
42274147 This function copies bytes from one region of memory to another. <code>dest</code> and
42284148 <code>source</code> are both pointers and must not overlap.
......@@ -4240,7 +4160,7 @@ fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
42404160mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre>
42414161 {#header_close#}
42424162 {#header_open|@memset#}
4243 <pre><code class="zig">@memset(dest: &amp;u8, c: u8, byte_count: usize)</code></pre>
4163 <pre><code class="zig">@memset(dest: &u8, c: u8, byte_count: usize)</code></pre>
42444164 <p>
42454165 This function sets a region of memory to <code>c</code>. <code>dest</code> is a pointer.
42464166 </p>
......@@ -4279,7 +4199,7 @@ mem.set(u8, dest, c);</code></pre>
42794199 {#see_also|@rem#}
42804200 {#header_close#}
42814201 {#header_open|@mulWithOverflow#}
4282 <pre><code class="zig">@mulWithOverflow(comptime T: type, a: T, b: T, result: &amp;T) -&gt; bool</code></pre>
4202 <pre><code class="zig">@mulWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
42834203 <p>
42844204 Performs <code>*result = a * b</code>. If overflow or underflow occurs,
42854205 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
......@@ -4318,17 +4238,19 @@ fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
43184238 This is typically used for type safety when interacting with C code that does not expose struct details.
43194239 Example:
43204240 </p>
4321 <pre><code class="zig">const Derp = @OpaqueType();
4241 {#code_begin|test_err|expected type '&Derp', found '&Wat'#}
4242const Derp = @OpaqueType();
43224243const Wat = @OpaqueType();
43234244
4324extern fn bar(d: &amp;Derp);
4325export fn foo(w: &amp;Wat) {
4245extern fn bar(d: &Derp);
4246export fn foo(w: &Wat) {
43264247 bar(w);
4327}</code></pre>
4328 <pre><code class="sh">$ ./zig build-obj test.zig
4329test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'
4330 bar(w);
4331 ^</code></pre>
4248}
4249
4250test "call foo" {
4251 foo(undefined);
4252}
4253 {#code_end#}
43324254 {#header_close#}
43334255 {#header_open|@panic#}
43344256 <pre><code class="zig">@panic(message: []const u8) -&gt; noreturn</code></pre>
......@@ -4413,22 +4335,24 @@ test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'
44134335 <p>
44144336 Example:
44154337 </p>
4416 <pre><code class="zig">comptime {
4417 var i = 0;
4418 while (i &lt; 1001) : (i += 1) {}
4419}</code></pre>
4420 <pre><code class="sh">$ ./zig build-obj test.zig
4421/home/andy/dev/zig/build/test.zig:3:5: error: evaluation exceeded 1000 backwards branches
4422 while (i &lt; 1001) : (i += 1) {}
4423 ^</code></pre>
4424 <p>Now we use <code>@setEvalBranchQuota</code>:</p>
4425 <pre><code class="zig">comptime {
4426 @setEvalBranchQuota(1001);
4427 var i = 0;
4428 while (i &lt; 1001) : (i += 1) {}
4429}</code></pre>
4430 <pre><code class="sh">$ ./zig build-obj test.zig</code></pre>
4431 <p>(no output because it worked fine)</p>
4338 {#code_begin|test_err|evaluation exceeded 1000 backwards branches#}
4339test "foo" {
4340 comptime {
4341 var i = 0;
4342 while (i < 1001) : (i += 1) {}
4343 }
4344}
4345 {#code_end#}
4346 <p>Now we use <code class="zig">@setEvalBranchQuota</code>:</p>
4347 {#code_begin|test#}
4348test "foo" {
4349 comptime {
4350 @setEvalBranchQuota(1001);
4351 var i = 0;
4352 while (i < 1001) : (i += 1) {}
4353 }
4354}
4355 {#code_end#}
44324356
44334357 {#see_also|comptime#}
44344358 {#header_close#}
......@@ -4437,10 +4361,12 @@ test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'
44374361 <p>
44384362 Sets the floating point mode for a given scope. Possible values are:
44394363 </p>
4440 <pre><code class="zig">pub const FloatMode = enum {
4364 {#code_begin|syntax#}
4365pub const FloatMode = enum {
44414366 Optimized,
44424367 Strict,
4443};</code></pre>
4368};
4369 {#code_end#}
44444370 <ul>
44454371 <li>
44464372 <code>Optimized</code> (default) - Floating point operations may do all of the following:
......@@ -4486,7 +4412,7 @@ test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'
44864412 {#see_also|@shrExact|@shlWithOverflow#}
44874413 {#header_close#}
44884414 {#header_open|@shlWithOverflow#}
4489 <pre><code class="zig">@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: &amp;T) -&gt; bool</code></pre>
4415 <pre><code class="zig">@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: &T) -&gt; bool</code></pre>
44904416 <p>
44914417 Performs <code>*result = a &lt;&lt; b</code>. If overflow or underflow occurs,
44924418 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
......@@ -4520,7 +4446,7 @@ test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'
45204446 </p>
45214447 {#header_close#}
45224448 {#header_open|@subWithOverflow#}
4523 <pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: &amp;T) -&gt; bool</code></pre>
4449 <pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
45244450 <p>
45254451 Performs <code>*result = a - b</code>. If overflow or underflow occurs,
45264452 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
......@@ -4556,7 +4482,8 @@ const b: u8 = @truncate(u8, a);
45564482 <p>
45574483 Returns which kind of type something is. Possible values:
45584484 </p>
4559 <pre><code class="zig">pub const TypeId = enum {
4485 {#code_begin|syntax#}
4486pub const TypeId = enum {
45604487 Type,
45614488 Void,
45624489 Bool,
......@@ -4574,7 +4501,6 @@ const b: u8 = @truncate(u8, a);
45744501 ErrorUnion,
45754502 Error,
45764503 Enum,
4577 EnumTag,
45784504 Union,
45794505 Fn,
45804506 Namespace,
......@@ -4582,8 +4508,8 @@ const b: u8 = @truncate(u8, a);
45824508 BoundFn,
45834509 ArgTuple,
45844510 Opaque,
4585};</code></pre>
4586
4511};
4512 {#code_end#}
45874513 {#header_close#}
45884514 {#header_open|@typeName#}
45894515 <pre><code class="zig">@typeName(T: type) -&gt; []u8</code></pre>
......@@ -4613,20 +4539,22 @@ const b: u8 = @truncate(u8, a);
46134539 <p>
46144540 To add standard build options to a <code>build.zig</code> file:
46154541 </p>
4616 <pre><code class="sh">const Builder = @import("std").build.Builder;
4542 {#code_begin|syntax#}
4543const Builder = @import("std").build.Builder;
46174544
4618pub fn build(b: &amp;Builder) {
4545pub fn build(b: &Builder) -> %void {
46194546 const exe = b.addExecutable("example", "example.zig");
46204547 exe.setBuildMode(b.standardReleaseOptions());
4621 b.default_step.dependOn(&amp;exe.step);
4622}</code></pre>
4548 b.default_step.dependOn(&exe.step);
4549}
4550 {#code_end#}
46234551 <p>
46244552 This causes these options to be available:
46254553 </p>
4626 <pre><code class="sh"> -Drelease-safe=(bool) optimizations on and safety on
4554 <pre><code class="shell"> -Drelease-safe=(bool) optimizations on and safety on
46274555 -Drelease-fast=(bool) optimizations on and safety off</code></pre>
46284556 {#header_open|Debug#}
4629 <pre><code class="sh">$ zig build-exe example.zig</code></pre>
4557 <pre><code class="shell">$ zig build-exe example.zig</code></pre>
46304558 <ul>
46314559 <li>Fast compilation speed</li>
46324560 <li>Safety checks enabled</li>
......@@ -4634,7 +4562,7 @@ pub fn build(b: &amp;Builder) {
46344562 </ul>
46354563 {#header_close#}
46364564 {#header_open|ReleaseFast#}
4637 <pre><code class="sh">$ zig build-exe example.zig --release-fast</code></pre>
4565 <pre><code class="shell">$ zig build-exe example.zig --release-fast</code></pre>
46384566 <ul>
46394567 <li>Fast runtime performance</li>
46404568 <li>Safety checks disabled</li>
......@@ -4642,7 +4570,7 @@ pub fn build(b: &amp;Builder) {
46424570 </ul>
46434571 {#header_close#}
46444572 {#header_open|ReleaseSafe#}
4645 <pre><code class="sh">$ zig build-exe example.zig --release-safe</code></pre>
4573 <pre><code class="shell">$ zig build-exe example.zig --release-safe</code></pre>
46464574 <ul>
46474575 <li>Medium runtime performance</li>
46484576 <li>Safety checks enabled</li>
......@@ -4663,73 +4591,41 @@ pub fn build(b: &amp;Builder) {
46634591 <p>
46644592 When a safety check fails, Zig crashes with a stack trace, like this:
46654593 </p>
4666 <pre><code class="zig">test "safety check" {
4667 unreachable;
4668}</code></pre>
4669 <pre><code class="sh">$ zig test test.zig
4670Test 1/1 safety check...reached unreachable code
4671/home/andy/dev/zig/build/lib/zig/std/special/zigrt.zig:16:35: 0x000000000020331c in ??? (test)
4672 @import("std").debug.panic("{}", message_ptr[0...message_len]);
4673 ^
4674/home/andy/dev/zig/build/test.zig:2:5: 0x0000000000203297 in ??? (test)
4594 {#code_begin|test_err|reached unreachable code#}
4595test "safety check" {
46754596 unreachable;
4676 ^
4677/home/andy/dev/zig/build/lib/zig/std/special/test_runner.zig:9:21: 0x0000000000214b0a in ??? (test)
4678 test_fn.func();
4679 ^
4680/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:50:21: 0x0000000000214a17 in ??? (test)
4681 return root.main();
4682 ^
4683/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:37:13: 0x00000000002148d0 in ??? (test)
4684 callMain(argc, argv, envp) catch exit(1);
4685 ^
4686/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:30:20: 0x0000000000214820 in ??? (test)
4687 callMainAndExit()
4688 ^
4689
4690Tests failed. Use the following command to reproduce the failure:
4691./test</code></pre>
4597}
4598 {#code_end#}
46924599 {#header_open|Reaching Unreachable Code#}
46934600 <p>At compile-time:</p>
4694 <pre><code class="zig">comptime {
4601 {#code_begin|test_err|unable to evaluate constant expression#}
4602comptime {
46954603 assert(false);
46964604}
46974605fn assert(ok: bool) {
46984606 if (!ok) unreachable; // assertion failure
4699}</code></pre>
4700 <pre><code class="sh">$ zig build-obj test.zig
4701/home/andy/dev/zig/build/test.zig:5:14: error: unable to evaluate constant expression
4702 if (!ok) unreachable; // assertion failure
4703 ^
4704/home/andy/dev/zig/build/test.zig:2:11: note: called from here
4705 assert(false);
4706 ^
4707/home/andy/dev/zig/build/test.zig:1:10: note: called from here
4708comptime {
4709 ^</code></pre>
4607}
4608 {#code_end#}
47104609 <p>At runtime crashes with the message <code>reached unreachable code</code> and a stack trace.</p>
47114610 {#header_close#}
47124611 {#header_open|Index out of Bounds#}
47134612 <p>At compile-time:</p>
4714 <pre><code class="zig">comptime {
4613 {#code_begin|test_err|index 5 outside array of size 5#}
4614comptime {
47154615 const array = "hello";
47164616 const garbage = array[5];
4717}</code></pre>
4718 <pre><code class="sh">$ zig build-obj test.zig
4719/home/andy/dev/zig/build/test.zig:3:26: error: index 5 outside array of size 5
4720 const garbage = array[5];
4721 ^</code></pre>
4617}
4618 {#code_end#}
47224619 <p>At runtime crashes with the message <code>index out of bounds</code> and a stack trace.</p>
47234620 {#header_close#}
47244621 {#header_open|Cast Negative Number to Unsigned Integer#}
47254622 <p>At compile-time:</p>
4726 <pre><code class="zig">comptime {
4623 {#code_begin|test_err|attempt to cast negative value to unsigned integer#}
4624comptime {
47274625 const value: i32 = -1;
47284626 const unsigned = u32(value);
4729}</code></pre>
4730 <pre><code class="sh">$ zig build-obj test.zig test.zig:3:25: error: attempt to cast negative value to unsigned integer
4731 const unsigned = u32(value);
4732 ^</code></pre>
4627}
4628 {#code_end#}
47334629 <p>At runtime crashes with the message <code>attempt to cast negative value to unsigned integer</code> and a stack trace.</p>
47344630 <p>
47354631 If you are trying to obtain the maximum value of an unsigned integer, use <code>@maxValue(T)</code>,
......@@ -4738,14 +4634,12 @@ comptime {
47384634 {#header_close#}
47394635 {#header_open|Cast Truncates Data#}
47404636 <p>At compile-time:</p>
4741 <pre><code class="zig">comptime {
4637 {#code_begin|test_err|cast from 'u16' to 'u8' truncates bits#}
4638comptime {
47424639 const spartan_count: u16 = 300;
47434640 const byte = u8(spartan_count);
4744}</code></pre>
4745 <pre><code class="sh">$ zig build-obj test.zig
4746test.zig:3:20: error: cast from 'u16' to 'u8' truncates bits
4747 const byte = u8(spartan_count);
4748 ^</code></pre>
4641}
4642 {#code_end#}
47494643 <p>At runtime crashes with the message <code>integer cast truncated bits</code> and a stack trace.</p>
47504644 <p>
47514645 If you are trying to truncate bits, use <code>@truncate(T, value)</code>,
......@@ -4767,14 +4661,12 @@ test.zig:3:20: error: cast from 'u16' to 'u8' truncates bits
47674661 <li><code>@divExact</code> (division)</li>
47684662 </ul>
47694663 <p>Example with addition at compile-time:</p>
4770 <pre><code class="zig">comptime {
4664 {#code_begin|test_err|operation caused overflow#}
4665comptime {
47714666 var byte: u8 = 255;
47724667 byte += 1;
4773}</code></pre>
4774 <pre><code class="sh">$ zig build-obj test.zig
4775/home/andy/dev/zig/build/test.zig:3:10: error: operation caused overflow
4776 byte += 1;
4777 ^</code></pre>
4668}
4669 {#code_end#}
47784670 <p>At runtime crashes with the message <code>integer overflow</code> and a stack trace.</p>
47794671 {#header_close#}
47804672 {#header_open|Standard Library Math Functions#}
......@@ -4789,23 +4681,20 @@ test.zig:3:20: error: cast from 'u16' to 'u8' truncates bits
47894681 <li><code>@import("std").math.shl</code></li>
47904682 </ul>
47914683 <p>Example of catching an overflow for addition:</p>
4792 <pre><code class="zig">const math = @import("std").math;
4684 {#code_begin|exe_err#}
4685const math = @import("std").math;
47934686const warn = @import("std").debug.warn;
4794pub fn main() -&gt; %void {
4687pub fn main() -> %void {
47954688 var byte: u8 = 255;
47964689
4797 byte = if (math.add(u8, byte, 1)) |result| {
4798 result
4799 } else |err| {
4690 byte = if (math.add(u8, byte, 1)) |result| result else |err| {
48004691 warn("unable to add one: {}\n", @errorName(err));
48014692 return err;
48024693 };
48034694
48044695 warn("result: {}\n", byte);
4805}</code></pre>
4806 <pre><code class="sh">$ zig build-exe test.zig
4807$ ./test
4808unable to add one: Overflow</code></pre>
4696}
4697 {#code_end#}
48094698 {#header_close#}
48104699 {#header_open|Builtin Overflow Functions#}
48114700 <p>
......@@ -4821,20 +4710,19 @@ unable to add one: Overflow</code></pre>
48214710 <p>
48224711 Example of <code>@addWithOverflow</code>:
48234712 </p>
4824 <pre><code class="zig">const warn = @import("std").debug.warn;
4825pub fn main() -&gt; %void {
4713 {#code_begin|exe#}
4714const warn = @import("std").debug.warn;
4715pub fn main() -> %void {
48264716 var byte: u8 = 255;
48274717
48284718 var result: u8 = undefined;
4829 if (@addWithOverflow(u8, byte, 10, &amp;result)) {
4719 if (@addWithOverflow(u8, byte, 10, &result)) {
48304720 warn("overflowed result: {}\n", result);
48314721 } else {
48324722 warn("result: {}\n", result);
48334723 }
4834}</code></pre>
4835 <pre><code class="sh">$ zig build-exe test.zig
4836$ ./test
4837overflowed result: 9</code></pre>
4724}
4725 {#code_end#}
48384726 {#header_close#}
48394727 {#header_open|Wrapping Operations#}
48404728 <p>
......@@ -4846,7 +4734,8 @@ overflowed result: 9</code></pre>
48464734 <li><code>-%</code> (wraparound negation)</li>
48474735 <li><code>*%</code> (wraparound multiplication)</li>
48484736 </ul>
4849 <pre><code class="zig">const assert = @import("std").debug.assert;
4737 {#code_begin|test#}
4738const assert = @import("std").debug.assert;
48504739
48514740test "wraparound addition and subtraction" {
48524741 const x: i32 = @maxValue(i32);
......@@ -4854,56 +4743,49 @@ test "wraparound addition and subtraction" {
48544743 assert(min_val == @minValue(i32));
48554744 const max_val = min_val -% 1;
48564745 assert(max_val == @maxValue(i32));
4857}</code></pre>
4746}
4747 {#code_end#}
48584748 {#header_close#}
48594749 {#header_close#}
48604750 {#header_open|Exact Left Shift Overflow#}
48614751 <p>At compile-time:</p>
4862 <pre><code class="zig">comptime {
4863 const x = @shlExact(u8(0b01010101), 2);
4864}</code></pre>
4865 <pre><code class="sh">$ zig build-obj test.zig
4866/home/andy/dev/zig/build/test.zig:2:15: error: operation caused overflow
4752 {#code_begin|test_err|operation caused overflow#}
4753comptime {
48674754 const x = @shlExact(u8(0b01010101), 2);
4868 ^</code></pre>
4755}
4756 {#code_end#}
48694757 <p>At runtime crashes with the message <code>left shift overflowed bits</code> and a stack trace.</p>
48704758 {#header_close#}
48714759 {#header_open|Exact Right Shift Overflow#}
48724760 <p>At compile-time:</p>
4873 <pre><code class="zig">comptime {
4874 const x = @shrExact(u8(0b10101010), 2);
4875}</code></pre>
4876 <pre><code class="sh">$ zig build-obj test.zig
4877/home/andy/dev/zig/build/test.zig:2:15: error: exact shift shifted out 1 bits
4761 {#code_begin|test_err|exact shift shifted out 1 bits#}
4762comptime {
48784763 const x = @shrExact(u8(0b10101010), 2);
4879 ^</code></pre>
4764}
4765 {#code_end#}
48804766 <p>At runtime crashes with the message <code>right shift overflowed bits</code> and a stack trace.</p>
48814767 {#header_close#}
48824768 {#header_open|Division by Zero#}
48834769 <p>At compile-time:</p>
4884 <pre><code class="zig">comptime {
4770 {#code_begin|test_err|division by zero#}
4771comptime {
48854772 const a: i32 = 1;
48864773 const b: i32 = 0;
48874774 const c = a / b;
4888}</code></pre>
4889 <pre><code class="sh">$ zig build-obj test.zig
4890/home/andy/dev/zig/build/test.zig:4:17: error: division by zero is undefined
4891 const c = a / b;
4892 ^</code></pre>
4775}
4776 {#code_end#}
48934777 <p>At runtime crashes with the message <code>division by zero</code> and a stack trace.</p>
48944778
48954779 {#header_close#}
48964780 {#header_open|Remainder Division by Zero#}
48974781 <p>At compile-time:</p>
4898 <pre><code class="zig">comptime {
4782 {#code_begin|test_err|division by zero#}
4783comptime {
48994784 const a: i32 = 10;
49004785 const b: i32 = 0;
49014786 const c = a % b;
4902}</code></pre>
4903 <pre><code class="sh">$ zig build-obj test.zig
4904/home/andy/dev/zig/build/test.zig:4:17: error: division by zero is undefined
4905 const c = a % b;
4906 ^</code></pre>
4787}
4788 {#code_end#}
49074789 <p>At runtime crashes with the message <code>remainder division by zero</code> and a stack trace.</p>
49084790
49094791 {#header_close#}
......@@ -4915,14 +4797,12 @@ test "wraparound addition and subtraction" {
49154797 {#header_close#}
49164798 {#header_open|Attempt to Unwrap Null#}
49174799 <p>At compile-time:</p>
4918 <pre><code class="zig">comptime {
4800 {#code_begin|test_err|unable to unwrap null#}
4801comptime {
49194802 const nullable_number: ?i32 = null;
49204803 const number = ??nullable_number;
4921}</code></pre>
4922 <pre><code class="sh">$ zig build-obj test.zig
4923/home/andy/dev/zig/build/test.zig:3:20: error: unable to unwrap null
4924 const number = ??nullable_number;
4925 ^</code></pre>
4804}
4805 {#code_end#}
49264806 <p>At runtime crashes with the message <code>attempt to unwrap null</code> and a stack trace.</p>
49274807 <p>One way to avoid this crash is to test for null instead of assuming non-null, with
49284808 the <code>if</code> expression:</p>
......@@ -4941,23 +4821,21 @@ pub fn main() {
49414821 {#header_close#}
49424822 {#header_open|Attempt to Unwrap Error#}
49434823 <p>At compile-time:</p>
4944 <pre><code class="zig">comptime {
4945 const number = %%getNumberOrFail();
4824 {#code_begin|test_err|unable to unwrap error 'UnableToReturnNumber'#}
4825comptime {
4826 const number = getNumberOrFail() catch unreachable;
49464827}
49474828
49484829error UnableToReturnNumber;
49494830
4950fn getNumberOrFail() -&gt; %i32 {
4831fn getNumberOrFail() -> %i32 {
49514832 return error.UnableToReturnNumber;
4952}</code></pre>
4953 <pre><code class="sh">$ zig build-obj test.zig
4954/home/andy/dev/zig/build/test.zig:2:20: error: unable to unwrap error 'UnableToReturnNumber'
4955 const number = %%getNumberOrFail();
4956 ^</code></pre>
4833}
4834 {#code_end#}
49574835 <p>At runtime crashes with the message <code>attempt to unwrap error: ErrorCode</code> and a stack trace.</p>
49584836 <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with
49594837 the <code>if</code> expression:</p>
4960 {#code_begin|exe|test#}
4838 {#code_begin|exe#}
49614839const warn = @import("std").debug.warn;
49624840
49634841pub fn main() {
......@@ -4979,16 +4857,14 @@ fn getNumberOrFail() -> %i32 {
49794857 {#header_close#}
49804858 {#header_open|Invalid Error Code#}
49814859 <p>At compile-time:</p>
4982 <pre><code class="zig">error AnError;
4860 {#code_begin|test_err|integer value 11 represents no error#}
4861error AnError;
49834862comptime {
49844863 const err = error.AnError;
49854864 const number = u32(err) + 10;
49864865 const invalid_err = error(number);
4987}</code></pre>
4988 <pre><code class="sh">$ zig build-obj test.zig
4989/home/andy/dev/zig/build/test.zig:5:30: error: integer value 11 represents no error
4990 const invalid_err = error(number);
4991 ^</code></pre>
4866}
4867 {#code_end#}
49924868 <p>At runtime crashes with the message <code>invalid error code</code> and a stack trace.</p>
49934869 {#header_close#}
49944870 {#header_open|Invalid Enum Cast#}
......@@ -5020,17 +4896,26 @@ comptime {
50204896 which the compiler makes available to every Zig source file. It contains
50214897 compile-time constants such as the current target, endianness, and release mode.
50224898 </p>
5023 <pre><code class="zig">const builtin = @import("builtin");
5024const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';</code></pre>
4899 {#code_begin|syntax#}
4900const builtin = @import("builtin");
4901const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';
4902 {#code_end#}
50254903 <p>
50264904 Example of what is imported with <code>@import("builtin")</code>:
50274905 </p>
5028 <pre><code class="zig">pub const Os = enum {
4906 {#code_begin|syntax#}
4907pub const StackTrace = struct {
4908 index: usize,
4909 instruction_addresses: []usize,
4910};
4911
4912pub const Os = enum {
50294913 freestanding,
4914 ananas,
50304915 cloudabi,
5031 darwin,
50324916 dragonfly,
50334917 freebsd,
4918 fuchsia,
50344919 ios,
50354920 kfreebsd,
50364921 linux,
......@@ -5055,12 +4940,15 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';</code></p
50554940 tvos,
50564941 watchos,
50574942 mesa3d,
4943 contiki,
4944 zen,
50584945};
50594946
50604947pub const Arch = enum {
50614948 armv8_2a,
50624949 armv8_1a,
50634950 armv8,
4951 armv8r,
50644952 armv8m_baseline,
50654953 armv8m_mainline,
50664954 armv7,
......@@ -5068,6 +4956,7 @@ pub const Arch = enum {
50684956 armv7m,
50694957 armv7s,
50704958 armv7k,
4959 armv7ve,
50714960 armv6,
50724961 armv6m,
50734962 armv6k,
......@@ -5087,16 +4976,20 @@ pub const Arch = enum {
50874976 mips64,
50884977 mips64el,
50894978 msp430,
4979 nios2,
50904980 powerpc,
50914981 powerpc64,
50924982 powerpc64le,
50934983 r600,
50944984 amdgcn,
4985 riscv32,
4986 riscv64,
50954987 sparc,
50964988 sparcv9,
50974989 sparcel,
50984990 s390x,
50994991 tce,
4992 tcele,
51004993 thumb,
51014994 thumbeb,
51024995 i386,
......@@ -5122,7 +5015,9 @@ pub const Arch = enum {
51225015 renderscript32,
51235016 renderscript64,
51245017};
5018
51255019pub const Environ = enum {
5020 unknown,
51265021 gnu,
51275022 gnuabi64,
51285023 gnueabi,
......@@ -5140,6 +5035,7 @@ pub const Environ = enum {
51405035 cygnus,
51415036 amdopencl,
51425037 coreclr,
5038 opencl,
51435039};
51445040
51455041pub const ObjectFormat = enum {
......@@ -5147,6 +5043,7 @@ pub const ObjectFormat = enum {
51475043 coff,
51485044 elf,
51495045 macho,
5046 wasm,
51505047};
51515048
51525049pub const GlobalLinkage = enum {
......@@ -5171,15 +5068,53 @@ pub const Mode = enum {
51715068 ReleaseFast,
51725069};
51735070
5174pub const is_big_endian = false;
5071pub const TypeId = enum {
5072 Type,
5073 Void,
5074 Bool,
5075 NoReturn,
5076 Int,
5077 Float,
5078 Pointer,
5079 Array,
5080 Struct,
5081 FloatLiteral,
5082 IntLiteral,
5083 UndefinedLiteral,
5084 NullLiteral,
5085 Nullable,
5086 ErrorUnion,
5087 Error,
5088 Enum,
5089 Union,
5090 Fn,
5091 Namespace,
5092 Block,
5093 BoundFn,
5094 ArgTuple,
5095 Opaque,
5096};
5097
5098pub const FloatMode = enum {
5099 Optimized,
5100 Strict,
5101};
5102
5103pub const Endian = enum {
5104 Big,
5105 Little,
5106};
5107
5108pub const endian = Endian.Little;
51755109pub const is_test = false;
51765110pub const os = Os.linux;
51775111pub const arch = Arch.x86_64;
51785112pub const environ = Environ.gnu;
51795113pub const object_format = ObjectFormat.elf;
5180pub const mode = Mode.ReleaseFast;
5181pub const link_libs = [][]const u8 {
5182};</code></pre>
5114pub const mode = Mode.Debug;
5115pub const link_libc = false;
5116pub const have_error_return_tracing = true;
5117 {#code_end#}
51835118 {#see_also|Build Mode#}
51845119 {#header_close#}
51855120 {#header_open|Root Source File#}
......@@ -5230,16 +5165,19 @@ pub const link_libs = [][]const u8 {
52305165 {#see_also|Primitive Types#}
52315166 {#header_close#}
52325167 {#header_open|C String Literals#}
5233 <pre><code class="zig">extern fn puts(&amp;const u8);
5168 {#code_begin|exe#}
5169 {#link_libc#}
5170extern fn puts(&const u8);
52345171
5235pub fn main() -&gt; %void {
5172pub fn main() {
52365173 puts(c"this has a null terminator");
52375174 puts(
52385175 c\\and so
52395176 c\\does this
52405177 c\\multiline C string literal
52415178 );
5242}</code></pre>
5179}
5180 {#code_end#}
52435181 {#see_also|String Literals#}
52445182 {#header_close#}
52455183 {#header_open|Import from C Header File#}
......@@ -5247,28 +5185,33 @@ pub fn main() -&gt; %void {
52475185 The <code>@cImport</code> builtin function can be used
52485186 to directly import symbols from .h files:
52495187 </p>
5250 <pre><code class="zig">const c = @cImport(@cInclude("stdio.h"));
5251pub fn main() -&gt; %void {
5252 c.printf("hello\n");
5253}</code></pre>
5188 {#code_begin|exe#}
5189 {#link_libc#}
5190const c = @cImport(@cInclude("stdio.h"));
5191pub fn main() {
5192 _ = c.printf(c"hello\n");
5193}
5194 {#code_end#}
52545195 <p>
52555196 The <code>@cImport</code> function takes an expression as a parameter.
52565197 This expression is evaluated at compile-time and is used to control
52575198 preprocessor directives and include multiple .h files:
52585199 </p>
5259 <pre><code class="zig">const builtin = @import("builtin");
5200 {#code_begin|syntax#}
5201const builtin = @import("builtin");
52605202
52615203const c = @cImport({
52625204 @cDefine("NDEBUG", builtin.mode == builtin.Mode.ReleaseFast);
52635205 if (something) {
52645206 @cDefine("_GNU_SOURCE", {});
52655207 }
5266 @cInclude("stdlib.h")
5208 @cInclude("stdlib.h");
52675209 if (something) {
52685210 @cUndef("_GNU_SOURCE");
52695211 }
52705212 @cInclude("soundio.h");
5271});</code></pre>
5213});
5214 {#code_end#}
52725215 {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
52735216 {#header_close#}
52745217 {#header_open|Mixing Object Files#}
......@@ -5277,10 +5220,11 @@ const c = @cImport({
52775220 </p>
52785221 {#header_close#}
52795222 {#header_open|base64.zig#}
5280 <pre><code class="zig">const base64 = @import("std").base64;
5223 {#code_begin|obj#}
5224const base64 = @import("std").base64;
52815225
5282export fn decode_base_64(dest_ptr: &amp;u8, dest_len: usize,
5283 source_ptr: &amp;const u8, source_len: usize) -&gt; usize
5226export fn decode_base_64(dest_ptr: &u8, dest_len: usize,
5227 source_ptr: &const u8, source_len: usize) -> usize
52845228{
52855229 const src = source_ptr[0..source_len];
52865230 const dest = dest_ptr[0..dest_len];
......@@ -5289,9 +5233,10 @@ export fn decode_base_64(dest_ptr: &amp;u8, dest_len: usize,
52895233 base64_decoder.decode(dest[0..decoded_size], src);
52905234 return decoded_size;
52915235}
5292</code></pre>
5293{{teheader_open:st.c}}
5294 <pre><code class="c">// This header is generated by zig from base64.zig
5236 {#code_end#}
5237 {#header_close#}
5238 {#header_open|test.c#}
5239 <pre><code class="cpp">// This header is generated by zig from base64.zig
52955240#include "base64.h"
52965241
52975242#include &lt;string.h&gt;
......@@ -5309,9 +5254,10 @@ int main(int argc, char **argv) {
53095254}</code></pre>
53105255 {#header_close#}
53115256 {#header_open|build.zig#}
5312 <pre><code class="zig">const Builder = @import("std").build.Builder;
5257 {#code_begin|syntax#}
5258const Builder = @import("std").build.Builder;
53135259
5314pub fn build(b: &amp;Builder) {
5260pub fn build(b: &Builder) -> %void {
53155261 const obj = b.addObject("base64", "base64.zig");
53165262
53175263 const exe = b.addCExecutable("test");
......@@ -5322,11 +5268,12 @@ pub fn build(b: &amp;Builder) {
53225268 exe.addObject(obj);
53235269 exe.setOutputPath(".");
53245270
5325 b.default_step.dependOn(&amp;exe.step);
5326}</code></pre>
5271 b.default_step.dependOn(&exe.step);
5272}
5273 {#code_end#}
53275274 {#header_close#}
53285275 {#header_open|Terminal#}
5329 <pre><code class="sh">$ zig build
5276 <pre><code class="shell">$ zig build
53305277$ ./test
53315278all your base are belong to us</code></pre>
53325279 {#see_also|Targets|Zig Build System#}
......@@ -5338,11 +5285,12 @@ all your base are belong to us</code></pre>
53385285 what it looks like to execute <code>zig targets</code> on a Linux x86_64
53395286 computer:
53405287 </p>
5341 <pre><code class="sh">$ zig targets
5288 <pre><code class="shell">$ zig targets
53425289Architectures:
53435290 armv8_2a
53445291 armv8_1a
53455292 armv8
5293 armv8r
53465294 armv8m_baseline
53475295 armv8m_mainline
53485296 armv7
......@@ -5350,6 +5298,7 @@ Architectures:
53505298 armv7m
53515299 armv7s
53525300 armv7k
5301 armv7ve
53535302 armv6
53545303 armv6m
53555304 armv6k
......@@ -5369,16 +5318,20 @@ Architectures:
53695318 mips64
53705319 mips64el
53715320 msp430
5321 nios2
53725322 powerpc
53735323 powerpc64
53745324 powerpc64le
53755325 r600
53765326 amdgcn
5327 riscv32
5328 riscv64
53775329 sparc
53785330 sparcv9
53795331 sparcel
53805332 s390x
53815333 tce
5334 tcele
53825335 thumb
53835336 thumbeb
53845337 i386
......@@ -5392,6 +5345,7 @@ Architectures:
53925345 amdil64
53935346 hsail
53945347 hsail64
5348 spir
53955349 spir64
53965350 kalimbav3
53975351 kalimbav4
......@@ -5405,10 +5359,11 @@ Architectures:
54055359
54065360Operating Systems:
54075361 freestanding
5362 ananas
54085363 cloudabi
5409 darwin
54105364 dragonfly
54115365 freebsd
5366 fuchsia
54125367 ios
54135368 kfreebsd
54145369 linux (native)
......@@ -5433,8 +5388,11 @@ Operating Systems:
54335388 tvos
54345389 watchos
54355390 mesa3d
5391 contiki
5392 zen
54365393
54375394Environments:
5395 unknown
54385396 gnu (native)
54395397 gnuabi64
54405398 gnueabi
......@@ -5451,7 +5409,8 @@ Environments:
54515409 itanium
54525410 cygnus
54535411 amdopencl
5454 coreclr</code></pre>
5412 coreclr
5413 opencl</code></pre>
54555414 <p>
54565415 The Zig Standard Library (<code>@import("std")</code>) has architecture, environment, and operating sytsem
54575416 abstractions, and thus takes additional work to support more platforms. It currently supports
......@@ -5518,7 +5477,8 @@ coding style.
55185477 </p>
55195478 {#header_close#}
55205479 {#header_open|Examples#}
5521 <pre><code class="zig">const namespace_name = @import("dir_name/file_name.zig");
5480 {#code_begin|syntax#}
5481const namespace_name = @import("dir_name/file_name.zig");
55225482var global_var: i32 = undefined;
55235483const const_name = 42;
55245484const primitive_type_alias = f32;
......@@ -5535,34 +5495,35 @@ fn functionName(param_name: TypeName) {
55355495}
55365496const functionAlias = functionName;
55375497
5538fn ListTemplateFunction(comptime ChildType: type, comptime fixed_size: usize) -&gt; type {
5498fn ListTemplateFunction(comptime ChildType: type, comptime fixed_size: usize) -> type {
55395499 return List(ChildType, fixed_size);
55405500}
55415501
5542fn ShortList(comptime T: type, comptime n: usize) -&gt; type {
5543 struct {
5502fn ShortList(comptime T: type, comptime n: usize) -> type {
5503 return struct {
55445504 field_name: [n]T,
55455505 fn methodName() {}
5546 }
5506 };
55475507}
55485508
55495509// The word XML loses its casing when used in Zig identifiers.
55505510const xml_document =
5551 \\&lt;?xml version="1.0" encoding="UTF-8"?&gt;
5552 \\&lt;document&gt;
5553 \\&lt;/document&gt;
5511 \\<?xml version="1.0" encoding="UTF-8"?>
5512 \\<document>
5513 \\</document>
55545514;
55555515const XmlParser = struct {};
55565516
55575517// The initials BE (Big Endian) are just another word in Zig identifier names.
5558fn readU32Be() -&gt; u32 {}</code></pre>
5518fn readU32Be() -> u32 {}
5519 {#code_end#}
55595520 <p>
55605521 See the Zig Standard Library for more examples.
55615522 </p>
55625523 {#header_close#}
55635524 {#header_close#}
55645525 {#header_open|Grammar#}
5565 <pre><code>Root = many(TopLevelItem) EOF
5526 <pre><code class="nohighlight">Root = many(TopLevelItem) EOF
55665527
55675528TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl
55685529
......@@ -5733,8 +5694,142 @@ ContainerDecl = option("extern" | "packed")
57335694 <p>TODO: document changes from a31b23c46ba2a8c28df01adc1aa0b4d878b9a5cf (compile time reflection additions)</p>
57345695 {#header_close#}
57355696 </div>
5736 <script src="highlight/highlight.pack.js"></script>
5737 <script>hljs.initHighlightingOnLoad();</script>
5697 <script>
5698/*! highlight.js v9.12.0 | BSD3 License | git.io/hljslicense */
5699!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset<r[0].offset?e:r:"start"===r[0].event?e:r:e.length?e:r}function o(e){function r(e){return" "+e.nodeName+'="'+n(e.value).replace('"',"&quot;")+'"'}s+="<"+t(e)+E.map.call(e.attributes,r).join("")+">"}function u(e){s+="</"+t(e)+">"}function c(e){("start"===e.event?o:u)(e.node)}for(var l=0,s="",f=[];e.length||r.length;){var g=i();if(s+=n(a.substring(l,g[0].offset)),l=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===l);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return s+n(a.substr(l))}function l(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},u=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?u("keyword",a.k):x(a.k).forEach(function(e){u(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return l("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var c=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=c.length?t(c.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function l(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?"":I.classPrefix,i='<span class="'+a,o=t?"":C;return i+=e+'">',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=l(E,r),e?(B+=e[1],a+=p(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!y[E.sL])return n(k);var t=e?f(E.sL,k,!0,x[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(B+=t.r),e&&(x[E.sL]=t.top),p(t.language,t.value,!1,!0)}function b(){L+=null!=E.sL?d():h(),k=""}function v(e){L+=e.cN?p(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(k+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),b(),t.rB||t.eB||(k=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),b(),a.eE&&(k=n));do E.cN&&(L+=C),E.skip||(B+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"<unnamed>")+'"');return k+=n,n.length||1}var N=w(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var R,E=i||N,x={},L="";for(R=E;R!==N;R=R.parent)R.cN&&(L=p(R.cN,"",!0)+L);var k="",B=0;try{for(var M,j,O=0;;){if(E.t.lastIndex=O,M=E.t.exec(t),!M)break;j=m(t.substring(O,M.index),M[0]),O=M.index+j}for(m(t.substr(O)),R=E;R.parent;R=R.parent)R.cN&&(L+=C);return{r:B,value:L,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function g(e,t){t=t||I.languages||x(y);var r={r:0,value:n(e)},a=r;return t.filter(w).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return I.tabReplace||I.useBR?e.replace(M,function(e,n){return I.useBR&&"\n"===e?"<br>":I.tabReplace?n.replace(/\t/g,I.tabReplace):""}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function d(e){var n,t,r,o,l,s=i(e);a(s)||(I.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/<br[ \/]*>/g,"\n")):n=e,l=n.textContent,r=s?f(s,l,!0):g(l),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),l)),r.value=p(r.value),e.innerHTML=r.value,e.className=h(e.className,s,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){I=o(I,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,d)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=y[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function R(){return x(y)}function w(e){return e=(e||"").toLowerCase(),y[e]||y[L[e]]}var E=[],x=Object.keys,y={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="</span>",I={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=d,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("cpp",function(t){var e={cN:"keyword",b:"\\b[a-z\\d_]*_t\\b"},r={cN:"string",v:[{b:'(u8?|U)?L?"',e:'"',i:"\\n",c:[t.BE]},{b:'(u8?|U)?R"',e:'"',c:[t.BE]},{b:"'\\\\?.",e:"'",i:"."}]},s={cN:"number",v:[{b:"\\b(0b[01']+)"},{b:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{b:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],r:0},i={cN:"meta",b:/#\s*[a-z]+\b/,e:/$/,k:{"meta-keyword":"if else elif endif define undef warning error line pragma ifdef ifndef include"},c:[{b:/\\\n/,r:0},t.inherit(r,{cN:"meta-string"}),{cN:"meta-string",b:/<[^\n>]*>/,e:/$/,i:"\\n"},t.CLCM,t.CBCM]},a=t.IR+"\\s*\\(",c={keyword:"int float while private char catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignof constexpr decltype noexcept static_assert thread_local restrict _Bool complex _Complex _Imaginary atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and or not",built_in:"std string cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr",literal:"true false nullptr NULL"},n=[e,t.CLCM,t.CBCM,s,r];return{aliases:["c","cc","h","c++","h++","hpp"],k:c,i:"</",c:n.concat([i,{b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:c,c:["self",e]},{b:t.IR+"::",k:c},{v:[{b:/=/,e:/;/},{b:/\(/,e:/\)/},{bK:"new throw return else",e:/;/}],k:c,c:n.concat([{b:/\(/,e:/\)/,k:c,c:n.concat(["self"]),r:0}]),r:0},{cN:"function",b:"("+t.IR+"[\\*&\\s]+)+"+a,rB:!0,e:/[{;=]/,eE:!0,k:c,i:/[^\w\s\*&]/,c:[{b:a,rB:!0,c:[t.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:c,r:0,c:[t.CLCM,t.CBCM,r,s,e]},t.CLCM,t.CBCM,i]},{cN:"class",bK:"class struct",e:/[{;:]/,c:[{b:/</,e:/>/,c:["self"]},t.TM]}]),exports:{preprocessor:i,strings:r,k:c}}});hljs.registerLanguage("llvm",function(e){var n="([-a-zA-Z$._][\\w\\-$.]*)";return{k:"begin end true false declare define global constant private linker_private internal available_externally linkonce linkonce_odr weak weak_odr appending dllimport dllexport common default hidden protected extern_weak external thread_local zeroinitializer undef null to tail target triple datalayout volatile nuw nsw nnan ninf nsz arcp fast exact inbounds align addrspace section alias module asm sideeffect gc dbg linker_private_weak attributes blockaddress initialexec localdynamic localexec prefix unnamed_addr ccc fastcc coldcc x86_stdcallcc x86_fastcallcc arm_apcscc arm_aapcscc arm_aapcs_vfpcc ptx_device ptx_kernel intel_ocl_bicc msp430_intrcc spir_func spir_kernel x86_64_sysvcc x86_64_win64cc x86_thiscallcc cc c signext zeroext inreg sret nounwind noreturn noalias nocapture byval nest readnone readonly inlinehint noinline alwaysinline optsize ssp sspreq noredzone noimplicitfloat naked builtin cold nobuiltin noduplicate nonlazybind optnone returns_twice sanitize_address sanitize_memory sanitize_thread sspstrong uwtable returned type opaque eq ne slt sgt sle sge ult ugt ule uge oeq one olt ogt ole oge ord uno ueq une x acq_rel acquire alignstack atomic catch cleanup filter inteldialect max min monotonic nand personality release seq_cst singlethread umax umin unordered xchg add fadd sub fsub mul fmul udiv sdiv fdiv urem srem frem shl lshr ashr and or xor icmp fcmp phi call trunc zext sext fptrunc fpext uitofp sitofp fptoui fptosi inttoptr ptrtoint bitcast addrspacecast select va_arg ret br switch invoke unwind unreachable indirectbr landingpad resume malloc alloca free load store getelementptr extractelement insertelement shufflevector getresult extractvalue insertvalue atomicrmw cmpxchg fence argmemonly double",c:[{cN:"keyword",b:"i\\d+"},e.C(";","\\n",{r:0}),e.QSM,{cN:"string",v:[{b:'"',e:'[^\\\\]"'}],r:0},{cN:"title",v:[{b:"@"+n},{b:"@\\d+"},{b:"!"+n},{b:"!\\d+"+n}]},{cN:"symbol",v:[{b:"%"+n},{b:"%\\d+"},{b:"#\\d+"}]},{cN:"number",v:[{b:"0[xX][a-fA-F0-9]+"},{b:"-?\\d+(?:[.]\\d+)?(?:[eE][-+]?\\d+(?:[.]\\d+)?)?"}],r:0}]}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("shell",function(s){return{aliases:["console"],c:[{cN:"meta",b:"^\\s{0,3}[\\w\\d\\[\\]()@-]*[>%$#]",starts:{e:"$",sL:"bash"}}]}});
5700 </script>
5701 <script>
5702hljs.registerLanguage("zig", function(t) {
5703 var e = {
5704 cN: "keyword",
5705 b: "\\b[a-z\\d_]*_t\\b"
5706 },
5707 r = {
5708 cN: "string",
5709 v: [{
5710 b: '(u8?|U)?L?"',
5711 e: '"',
5712 i: "\\n",
5713 c: [t.BE]
5714 }, {
5715 b: '(u8?|U)?R"',
5716 e: '"',
5717 c: [t.BE]
5718 }, {
5719 b: "'\\\\?.",
5720 e: "'",
5721 i: "."
5722 }]
5723 },
5724 s = {
5725 cN: "number",
5726 v: [{
5727 b: "\\b(0b[01']+)"
5728 }, {
5729 b: "(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"
5730 }, {
5731 b: "(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
5732 }],
5733 r: 0
5734 },
5735 i = {
5736 cN: "meta",
5737 b: /#\s*[a-z]+\b/,
5738 e: /$/,
5739 k: {
5740 "meta-keyword": "zzzzzzdisable"
5741 },
5742 c: [{
5743 b: /\\\n/,
5744 r: 0
5745 }, t.inherit(r, {
5746 cN: "meta-string"
5747 }), {
5748 cN: "meta-string",
5749 b: /<[^\n>]*>/,
5750 e: /$/,
5751 i: "\\n"
5752 }, t.CLCM, t.CBCM]
5753 },
5754 a = t.IR + "\\s*\\(",
5755 c = {
5756 keyword: "const align var extern stdcallcc coldcc nakedcc volatile export pub noalias inline struct packed enum union goto break return try catch test continue unreachable comptime and or asm defer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
5757 built_in: "breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setDebugSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchg fence divExact truncate",
5758 literal: "true false null undefined"
5759 },
5760 n = [e, t.CLCM, t.CBCM, s, r];
5761 return {
5762 aliases: ["c", "cc", "h", "c++", "h++", "hpp"],
5763 k: c,
5764 i: "</",
5765 c: n.concat([i, {
5766 b: "\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",
5767 e: ">",
5768 k: c,
5769 c: ["self", e]
5770 }, {
5771 b: t.IR + "::",
5772 k: c
5773 }, {
5774 v: [{
5775 b: /=/,
5776 e: /;/
5777 }, {
5778 b: /\(/,
5779 e: /\)/
5780 }, {
5781 bK: "new throw return else",
5782 e: /;/
5783 }],
5784 k: c,
5785 c: n.concat([{
5786 b: /\(/,
5787 e: /\)/,
5788 k: c,
5789 c: n.concat(["self"]),
5790 r: 0
5791 }]),
5792 r: 0
5793 }, {
5794 cN: "function",
5795 b: "(" + t.IR + "[\\*&\\s]+)+" + a,
5796 rB: !0,
5797 e: /[{;=]/,
5798 eE: !0,
5799 k: c,
5800 i: /[^\w\s\*&]/,
5801 c: [{
5802 b: a,
5803 rB: !0,
5804 c: [t.TM],
5805 r: 0
5806 }, {
5807 cN: "params",
5808 b: /\(/,
5809 e: /\)/,
5810 k: c,
5811 r: 0,
5812 c: [t.CLCM, t.CBCM, r, s, e]
5813 }, t.CLCM, t.CBCM, i]
5814 }, {
5815 cN: "class",
5816 bK: "class struct",
5817 e: /[{;:]/,
5818 c: [{
5819 b: /</,
5820 e: />/,
5821 c: ["self"]
5822 }, t.TM]
5823 }]),
5824 exports: {
5825 preprocessor: i,
5826 strings: r,
5827 k: c
5828 }
5829 }
5830});
5831 hljs.initHighlightingOnLoad();
5832 </script>
57385833 </body>
57395834</html>
57405835
src/ir.cpp+1-1
......@@ -9009,7 +9009,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
90099009 int err;
90109010 if ((err = ir_eval_math_op(resolved_type, op1_val, op_id, op2_val, out_val))) {
90119011 if (err == ErrorDivByZero) {
9012 ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("division by zero is undefined"));
9012 ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("division by zero"));
90139013 return ira->codegen->builtin_types.entry_invalid;
90149014 } else if (err == ErrorOverflow) {
90159015 ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("operation caused overflow"));
src/main.cpp+1-1
......@@ -462,7 +462,7 @@ int main(int argc, char **argv) {
462462 Termination term;
463463 os_spawn_process(buf_ptr(path_to_build_exe), args, &term);
464464 if (term.how != TerminationIdClean || term.code != 0) {
465 fprintf(stderr, "\nBuild failed. Use the following command to reproduce the failure:\n");
465 fprintf(stderr, "\nBuild failed. The following command failed:\n");
466466 fprintf(stderr, "%s", buf_ptr(path_to_build_exe));
467467 for (size_t i = 0; i < args.length; i += 1) {
468468 fprintf(stderr, " %s", args.at(i));
test/compile_errors.zig+7-7
......@@ -861,10 +861,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
861861 \\export fn entry3() -> usize { return @sizeOf(@typeOf(int_x)); }
862862 \\export fn entry4() -> usize { return @sizeOf(@typeOf(float_x)); }
863863 ,
864 ".tmp_source.zig:1:21: error: division by zero is undefined",
865 ".tmp_source.zig:2:25: error: division by zero is undefined",
866 ".tmp_source.zig:3:22: error: division by zero is undefined",
867 ".tmp_source.zig:4:26: error: division by zero is undefined");
864 ".tmp_source.zig:1:21: error: division by zero",
865 ".tmp_source.zig:2:25: error: division by zero",
866 ".tmp_source.zig:3:22: error: division by zero",
867 ".tmp_source.zig:4:26: error: division by zero");
868868
869869
870870 cases.add("normal string with newline",
......@@ -911,7 +911,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
911911 \\
912912 \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
913913 ,
914 ".tmp_source.zig:3:14: error: division by zero is undefined",
914 ".tmp_source.zig:3:14: error: division by zero",
915915 ".tmp_source.zig:1:14: note: called from here");
916916
917917 cases.add("branch on undefined value",
......@@ -1816,7 +1816,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
18161816 \\ const c = a / b;
18171817 \\}
18181818 ,
1819 ".tmp_source.zig:4:17: error: division by zero is undefined");
1819 ".tmp_source.zig:4:17: error: division by zero");
18201820
18211821 cases.add("compile-time remainder division by zero",
18221822 \\comptime {
......@@ -1825,7 +1825,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
18251825 \\ const c = a % b;
18261826 \\}
18271827 ,
1828 ".tmp_source.zig:4:17: error: division by zero is undefined");
1828 ".tmp_source.zig:4:17: error: division by zero");
18291829
18301830 cases.add("compile-time integer cast truncates bits",
18311831 \\comptime {