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 @@...@@ -1,12 +1,16 @@
1const builtin = @import("builtin");
1const std = @import("std");2const std = @import("std");
2const io = std.io;3const io = std.io;
3const os = std.os;4const os = std.os;
4const warn = std.debug.warn;5const warn = std.debug.warn;
5const mem = std.mem;6const mem = std.mem;
7const assert = std.debug.assert;
68
7const max_doc_file_size = 10 * 1024 * 1024;9const max_doc_file_size = 10 * 1024 * 1024;
810
9const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt();11const 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
11pub fn main() -> %void {15pub fn main() -> %void {
12 // TODO use a more general purpose allocator here16 // TODO use a more general purpose allocator here
...@@ -43,6 +47,8 @@ pub fn main() -> %void {...@@ -43,6 +47,8 @@ pub fn main() -> %void {
43 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);47 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
44 var toc = try genToc(allocator, &tokenizer);48 var toc = try genToc(allocator, &tokenizer);
4549
50 try os.makePath(allocator, tmp_dir_name);
51 defer os.deleteTree(allocator, tmp_dir_name) catch {};
46 try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe);52 try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe);
47 try buffered_out_stream.flush();53 try buffered_out_stream.flush();
48}54}
...@@ -68,6 +74,7 @@ const Tokenizer = struct {...@@ -68,6 +74,7 @@ const Tokenizer = struct {
68 index: usize,74 index: usize,
69 state: State,75 state: State,
70 source_file_name: []const u8,76 source_file_name: []const u8,
77 code_node_count: usize,
7178
72 const State = enum {79 const State = enum {
73 Start,80 Start,
...@@ -83,6 +90,7 @@ const Tokenizer = struct {...@@ -83,6 +90,7 @@ const Tokenizer = struct {
83 .index = 0,90 .index = 0,
84 .state = State.Start,91 .state = State.Start,
85 .source_file_name = source_file_name,92 .source_file_name = source_file_name,
93 .code_node_count = 0,
86 };94 };
87 }95 }
8896
...@@ -251,15 +259,27 @@ const SeeAlsoItem = struct {...@@ -251,15 +259,27 @@ const SeeAlsoItem = struct {
251 token: Token,259 token: Token,
252};260};
253261
262const ExpectedOutcome = enum {
263 Succeed,
264 Fail,
265};
266
254const Code = struct {267const Code = struct {
255 id: Id,268 id: Id,
256 name: []const u8,269 name: []const u8,
257 source_token: Token,270 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) {
260 Test,278 Test,
261 Exe,279 TestError: []const u8,
262 Error,280 TestSafety: []const u8,
281 Exe: ExpectedOutcome,
282 Obj,
263 };283 };
264};284};
265285
...@@ -401,28 +421,68 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) -> %Toc {...@@ -401,28 +421,68 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) -> %Toc {
401 }421 }
402 const code_kind_str = tokenizer.buffer[code_kind_tok.start..code_kind_tok.end];422 const code_kind_str = tokenizer.buffer[code_kind_tok.start..code_kind_tok.end];
403 var code_kind_id: Code.Id = undefined;423 var code_kind_id: Code.Id = undefined;
424 var is_inline = false;
404 if (mem.eql(u8, code_kind_str, "exe")) {425 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 };
406 } else if (mem.eql(u8, code_kind_str, "test")) {429 } else if (mem.eql(u8, code_kind_str, "test")) {
407 code_kind_id = Code.Id.Test;430 code_kind_id = Code.Id.Test;
408 } else if (mem.eql(u8, code_kind_str, "error")) {431 } else if (mem.eql(u8, code_kind_str, "test_err")) {
409 code_kind_id = Code.Id.Error;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;
410 } else {442 } else {
411 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", code_kind_str);443 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", code_kind_str);
412 }444 }
413 const source_token = try eatToken(tokenizer, Token.Id.Content);445
414 _ = try eatToken(tokenizer, Token.Id.BracketOpen);446 var mode = builtin.Mode.Debug;
415 const end_code_tag = try eatToken(tokenizer, Token.Id.TagContent);447 var link_objects = std.ArrayList([]const u8).init(allocator);
416 const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end];448 defer link_objects.deinit();
417 if (!mem.eql(u8, end_tag_name, "code_end")) {449 var target_windows = false;
418 return parseError(tokenizer, end_code_tag, "expected code_end token");450 var link_libc = false;
419 }451
420 _ = try eatToken(tokenizer, Token.Id.BracketClose);452 const source_token = while (true) {
421 try nodes.append(Node {.Code = Code{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 {
422 .id = code_kind_id,476 .id = code_kind_id,
423 .name = name,477 .name = name,
424 .source_token = source_token,478 .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,
425 }});484 }});
485 tokenizer.code_node_count += 1;
426 } else {486 } else {
427 return parseError(tokenizer, tag_token, "unrecognized tag name: {}", tag_name);487 return parseError(tokenizer, tag_token, "unrecognized tag name: {}", tag_name);
428 }488 }
...@@ -476,9 +536,116 @@ fn escapeHtml(allocator: &mem.Allocator, input: []const u8) -> %[]u8 {...@@ -476,9 +536,116 @@ fn escapeHtml(allocator: &mem.Allocator, input: []const u8) -> %[]u8 {
476 return buf.toOwnedSlice();536 return buf.toOwnedSlice();
477}537}
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
479error ExampleFailedToCompile;645error ExampleFailedToCompile;
480646
481fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io.OutStream, zig_exe: []const u8) -> %void {647fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io.OutStream, zig_exe: []const u8) -> %void {
648 var code_progress_index: usize = 0;
482 for (toc.nodes) |node| {649 for (toc.nodes) |node| {
483 switch (node) {650 switch (node) {
484 Node.Content => |data| {651 Node.Content => |data| {
...@@ -502,65 +669,252 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io...@@ -502,65 +669,252 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io
502 try out.write("</ul>\n");669 try out.write("</ul>\n");
503 },670 },
504 Node.Code => |code| {671 Node.Code => |code| {
672 code_progress_index += 1;
673 warn("docgen example code {}/{}...", code_progress_index, tokenizer.code_node_count);
674
505 const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];675 const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];
506 const trimmed_raw_source = mem.trim(u8, raw_source, " \n");676 const trimmed_raw_source = mem.trim(u8, raw_source, " \n");
507 const escaped_source = try escapeHtml(allocator, trimmed_raw_source);677 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 }
508 try out.print("<pre><code class=\"zig\">{}</code></pre>", escaped_source);681 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);
511 const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);682 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);
513 const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);683 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);
515 try io.writeFile(tmp_source_file_name, trimmed_raw_source, null);684 try io.writeFile(tmp_source_file_name, trimmed_raw_source, null);
516 685
517 switch (code.id) {686 switch (code.id) {
518 Code.Id.Exe => {687 Code.Id.Exe => |expected_outcome| {
519 {688 const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);
520 const args = [][]const u8 {zig_exe, "build-exe", tmp_source_file_name, "--output", tmp_bin_file_name};689 const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext);
521 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);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);
522 switch (result.term) {727 switch (result.term) {
523 os.ChildProcess.Term.Exited => |exit_code| {728 os.ChildProcess.Term.Exited => |exit_code| {
524 if (exit_code != 0) {729 if (exit_code == 0) {
525 warn("{}\nThe following command exited with code {}:\n", result.stderr, exit_code);730 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
526 for (args) |arg| warn("{} ", arg) else warn("\n");731 for (run_args) |arg| warn("{} ", arg) else warn("\n");
527 return parseError(tokenizer, code.source_token, "example failed to compile");732 return parseError(tokenizer, code.source_token, "example incorrectly compiled");
528 }733 }
529 },734 },
530 else => {735 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 },
535 }736 }
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 },
536 }798 }
537 const args = [][]const u8 {tmp_bin_file_name};799 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, null, max_doc_file_size);
538 const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size);
539 switch (result.term) {800 switch (result.term) {
540 os.ChildProcess.Term.Exited => |exit_code| {801 os.ChildProcess.Term.Exited => |exit_code| {
541 if (exit_code != 0) {802 if (exit_code == 0) {
542 warn("The following command exited with code {}:\n", exit_code);803 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
543 for (args) |arg| warn("{} ", arg) else warn("\n");804 for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
544 return parseError(tokenizer, code.source_token, "example exited with code {}", exit_code);805 return parseError(tokenizer, code.source_token, "example incorrectly compiled");
545 }806 }
546 },807 },
547 else => {808 else => {
548 warn("The following command crashed:\n");809 warn("{}\nThe following command crashed:\n", result.stderr);
549 for (args) |arg| warn("{} ", arg) else warn("\n");810 for (test_args.toSliceConst()) |arg| warn("{} ", arg) else warn("\n");
550 return parseError(tokenizer, code.source_token, "example crashed");811 return parseError(tokenizer, code.source_token, "example compile crashed");
551 },812 },
552 }813 }
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);
554 },821 },
555 Code.Id.Test => {822
556 @panic("TODO");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);
557 },856 },
558 Code.Id.Error => {857 Code.Id.Obj => {
559 @panic("TODO");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 }
560 },891 },
561 }892 }
893 warn("OK\n");
562 },894 },
563 }895 }
564 }896 }
565897
566}898}
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 @@...@@ -4,7 +4,9 @@
4 <meta charset="utf-8">4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />5 <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
6 <title>Documentation - The Zig Programming Language</title>6 <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>
8 <style type="text/css">10 <style type="text/css">
9 table, th, td {11 table, th, td {
10 border-collapse: collapse;12 border-collapse: collapse;
...@@ -13,6 +15,27 @@...@@ -13,6 +15,27 @@
13 th, td {15 th, td {
14 padding: 0.1em;16 padding: 0.1em;
15 }17 }
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 }
16 @media screen and (min-width: 28.75em) {39 @media screen and (min-width: 28.75em) {
17 #nav {40 #nav {
18 width: 20em;41 width: 20em;
...@@ -53,6 +76,10 @@...@@ -53,6 +76,10 @@
53 If you search for something specific in this documentation and do not find it,76 If you search for something specific in this documentation and do not find it,
54 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>.77 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>.
55 </p>78 </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>
56 {#header_close#}83 {#header_close#}
57 {#header_open|Hello World#}84 {#header_open|Hello World#}
5885
...@@ -399,7 +426,8 @@ pub fn main() -> %void {...@@ -399,7 +426,8 @@ pub fn main() -> %void {
399 {#see_also|Nullables|this#}426 {#see_also|Nullables|this#}
400 {#header_close#}427 {#header_close#}
401 {#header_open|String Literals#}428 {#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;
403const mem = @import("std").mem;431const mem = @import("std").mem;
404432
405test "string literals" {433test "string literals" {
...@@ -413,11 +441,10 @@ test "string literals" {...@@ -413,11 +441,10 @@ test "string literals" {
413441
414 // A C string literal is a null terminated pointer.442 // A C string literal is a null terminated pointer.
415 const null_terminated_bytes = c"hello";443 const null_terminated_bytes = c"hello";
416 assert(@typeOf(null_terminated_bytes) == &amp;const u8);444 assert(@typeOf(null_terminated_bytes) == &const u8);
417 assert(null_terminated_bytes[5] == 0);445 assert(null_terminated_bytes[5] == 0);
418}</code></pre>446}
419 <pre><code class="sh">$ zig test string_literals.zig447 {#code_end#}
420Test 1/1 string literals...OK</code></pre>
421 {#see_also|Arrays|Zig Test#}448 {#see_also|Arrays|Zig Test#}
422 {#header_open|Escape Sequences#}449 {#header_open|Escape Sequences#}
423 <table>450 <table>
...@@ -477,25 +504,29 @@ Test 1/1 string literals...OK</code></pre>...@@ -477,25 +504,29 @@ Test 1/1 string literals...OK</code></pre>
477 However, if the next line begins with <code>\\</code> then a newline is appended and504 However, if the next line begins with <code>\\</code> then a newline is appended and
478 the string literal continues.505 the string literal continues.
479 </p>506 </p>
480 <pre><code class="zig">const hello_world_in_c =507 {#code_begin|syntax#}
481 \\#include &lt;stdio.h&gt;508const hello_world_in_c =
509 \\#include <stdio.h>
482 \\510 \\
483 \\int main(int argc, char **argv) {511 \\int main(int argc, char **argv) {
484 \\ printf("hello world\n");512 \\ printf("hello world\n");
485 \\ return 0;513 \\ return 0;
486 \\}514 \\}
487;</code></pre>515;
516 {#code_end#}
488 <p>517 <p>
489 For a multiline C string literal, prepend <code>c</code> to each <code>\\</code>:518 For a multiline C string literal, prepend <code>c</code> to each <code>\\</code>:
490 </p>519 </p>
491 <pre><code class="zig">const c_string_literal =520 {#code_begin|syntax#}
492 c\\#include &lt;stdio.h&gt;521const c_string_literal =
522 c\\#include <stdio.h>
493 c\\523 c\\
494 c\\int main(int argc, char **argv) {524 c\\int main(int argc, char **argv) {
495 c\\ printf("hello world\n");525 c\\ printf("hello world\n");
496 c\\ return 0;526 c\\ return 0;
497 c\\}527 c\\}
498;</code></pre>528;
529 {#code_end#}
499 <p>530 <p>
500 In this example the variable <code>c_string_literal</code> has type <code>&amp;const char</code> and531 In this example the variable <code>c_string_literal</code> has type <code>&amp;const char</code> and
501 has a terminating null byte.532 has a terminating null byte.
...@@ -505,7 +536,8 @@ Test 1/1 string literals...OK</code></pre>...@@ -505,7 +536,8 @@ Test 1/1 string literals...OK</code></pre>
505 {#header_close#}536 {#header_close#}
506 {#header_open|Assignment#}537 {#header_open|Assignment#}
507 <p>Use <code>const</code> to assign a value to an identifier:</p>538 <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
510fn foo() {542fn foo() {
511 // It works at global scope as well as inside functions.543 // It works at global scope as well as inside functions.
...@@ -517,13 +549,11 @@ fn foo() {...@@ -517,13 +549,11 @@ fn foo() {
517549
518test "assignment" {550test "assignment" {
519 foo();551 foo();
520}</code></pre>552}
521 <pre><code class="sh">$ zig test test.zig553 {#code_end#}
522test.zig:8:7: error: cannot assign to constant
523 y += 1;
524 ^</code></pre>
525 <p>If you need a variable that you can modify, use <code>var</code>:</p>554 <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
528test "var" {558test "var" {
529 var y: i32 = 5678;559 var y: i32 = 5678;
...@@ -531,38 +561,37 @@ test "var" {...@@ -531,38 +561,37 @@ test "var" {
531 y += 1;561 y += 1;
532562
533 assert(y == 5679);563 assert(y == 5679);
534}</code></pre>564}
535 <pre><code class="sh">$ zig test test.zig565 {#code_end#}
536Test 1/1 assignment...OK</code></pre>
537 <p>Variables must be initialized:</p>566 <p>Variables must be initialized:</p>
538 <pre><code class="zig">test "initialization" {567 {#code_begin|test_err#}
568test "initialization" {
539 var x: i32;569 var x: i32;
540570
541 x = 1;571 x = 1;
542}</code></pre>572}
543 <pre><code class="sh">$ zig test test.zig573 {#code_end#}
544test.zig:3:5: error: variables must be initialized
545 var x: i32;
546 ^</code></pre>
547 <p>Use <code>undefined</code> to leave variables uninitialized:</p>574 <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
550test "init with undefined" {578test "init with undefined" {
551 var x: i32 = undefined;579 var x: i32 = undefined;
552 x = 1;580 x = 1;
553 assert(x == 1);581 assert(x == 1);
554}</code></pre>582}
555 <pre><code class="sh">$ zig test test.zig583 {#code_end#}
556Test 1/1 init with undefined...OK</code></pre>
557 {#header_close#}584 {#header_close#}
558 {#header_close#}585 {#header_close#}
559 {#header_open|Integers#}586 {#header_open|Integers#}
560 {#header_open|Integer Literals#}587 {#header_open|Integer Literals#}
561 <pre><code class="zig">const decimal_int = 98222;588 {#code_begin|syntax#}
589const decimal_int = 98222;
562const hex_int = 0xff;590const hex_int = 0xff;
563const another_hex_int = 0xFF;591const another_hex_int = 0xFF;
564const octal_int = 0o755;592const octal_int = 0o755;
565const binary_int = 0b11110000;</code></pre>593const binary_int = 0b11110000;
594 {#code_end#}
566 {#header_close#}595 {#header_close#}
567 {#header_open|Runtime Integer Values#}596 {#header_open|Runtime Integer Values#}
568 <p>597 <p>
...@@ -573,9 +602,11 @@ const binary_int = 0b11110000;</code></pre>...@@ -573,9 +602,11 @@ const binary_int = 0b11110000;</code></pre>
573 However, once an integer value is no longer known at compile-time, it must have a602 However, once an integer value is no longer known at compile-time, it must have a
574 known size, and is vulnerable to undefined behavior.603 known size, and is vulnerable to undefined behavior.
575 </p>604 </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 {
577 return a / b;607 return a / b;
578}</code></pre>608}
609 {#code_end#}
579 <p>610 <p>
580 In this function, values <code>a</code> and <code>b</code> are known only at runtime,611 In this function, values <code>a</code> and <code>b</code> are known only at runtime,
581 and thus this division operation is vulnerable to both integer overflow and612 and thus this division operation is vulnerable to both integer overflow and
...@@ -592,48 +623,49 @@ const binary_int = 0b11110000;</code></pre>...@@ -592,48 +623,49 @@ const binary_int = 0b11110000;</code></pre>
592 {#header_open|Floats#}623 {#header_open|Floats#}
593 {#header_close#}624 {#header_close#}
594 {#header_open|Float Literals#}625 {#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;
596const another_float = 123.0;628const another_float = 123.0;
597const yet_another = 123.0e+77;629const yet_another = 123.0e+77;
598630
599const hex_floating_point = 0x103.70p-5;631const hex_floating_point = 0x103.70p-5;
600const another_hex_float = 0x103.70;632const 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#}
602 {#header_close#}635 {#header_close#}
603 {#header_open|Floating Point Operations#}636 {#header_open|Floating Point Operations#}
604 <p>By default floating point operations use <code>Optimized</code> mode,637 <p>By default floating point operations use <code>Optimized</code> mode,
605 but you can switch to <code>Strict</code> mode on a per-block basis:</p>638 but you can switch to <code>Strict</code> mode on a per-block basis:</p>
606 <p>foo.zig</p>639 {#code_begin|obj|foo#}
607 <pre><code class="zig">const builtin = @import("builtin");640 {#code_release_fast#}
608const big = f64(1 &lt;&lt; 40);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 {
611 @setFloatMode(this, builtin.FloatMode.Strict);645 @setFloatMode(this, builtin.FloatMode.Strict);
612 return x + big - big;646 return x + big - big;
613}647}
614648
615export fn foo_optimized(x: f64) -&gt; f64 {649export fn foo_optimized(x: f64) -> f64 {
616 return x + big - big;650 return x + big - big;
617}</code></pre>651}
618 <p>test.zig</p>652 {#code_end#}
619 <pre><code class="zig">const warn = @import("std").debug.warn;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;660extern fn foo_strict(x: f64) -> f64;
622extern fn foo_optimized(x: f64) -&gt; f64;661extern fn foo_optimized(x: f64) -> f64;
623662
624pub fn main() -&gt; %void {663pub fn main() -> %void {
625 const x = 0.001;664 const x = 0.001;
626 warn("optimized = {}\n", foo_optimized(x));665 warn("optimized = {}\n", foo_optimized(x));
627 warn("strict = {}\n", foo_strict(x));666 warn("strict = {}\n", foo_strict(x));
628}</code></pre>667}
629 <p>For this test we have to separate code into two object files -668 {#code_end#}
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>
637 {#see_also|@setFloatMode|Division by Zero#}669 {#see_also|@setFloatMode|Division by Zero#}
638 {#header_close#}670 {#header_close#}
639 {#header_open|Operators#}671 {#header_open|Operators#}
...@@ -1244,7 +1276,8 @@ or...@@ -1244,7 +1276,8 @@ or
1244 {#header_close#}1276 {#header_close#}
1245 {#header_close#}1277 {#header_close#}
1246 {#header_open|Arrays#}1278 {#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;
1248const mem = @import("std").mem;1281const mem = @import("std").mem;
12491282
1250// array literal1283// array literal
...@@ -1314,7 +1347,7 @@ comptime {...@@ -1314,7 +1347,7 @@ comptime {
1314}1347}
13151348
1316// use compile-time code to initialize an array1349// use compile-time code to initialize an array
1317var fancy_array = {1350var fancy_array = init: {
1318 var initial_value: [10]Point = undefined;1351 var initial_value: [10]Point = undefined;
1319 for (initial_value) |*pt, i| {1352 for (initial_value) |*pt, i| {
1320 *pt = Point {1353 *pt = Point {
...@@ -1322,7 +1355,7 @@ var fancy_array = {...@@ -1322,7 +1355,7 @@ var fancy_array = {
1322 .y = i32(i) * 2,1355 .y = i32(i) * 2,
1323 };1356 };
1324 }1357 }
1325 initial_value1358 break :init initial_value;
1326};1359};
1327const Point = struct {1360const Point = struct {
1328 x: i32,1361 x: i32,
...@@ -1336,26 +1369,23 @@ test "compile-time array initalization" {...@@ -1336,26 +1369,23 @@ test "compile-time array initalization" {
13361369
1337// call a function to initialize an array1370// call a function to initialize an array
1338var more_points = []Point{makePoint(3)} ** 10;1371var more_points = []Point{makePoint(3)} ** 10;
1339fn makePoint(x: i32) -&gt; Point {1372fn makePoint(x: i32) -> Point {
1340 Point {1373 return Point {
1341 .x = x,1374 .x = x,
1342 .y = x * 2,1375 .y = x * 2,
1343 }1376 };
1344}1377}
1345test "array initialization with function calls" {1378test "array initialization with function calls" {
1346 assert(more_points[4].x == 3);1379 assert(more_points[4].x == 3);
1347 assert(more_points[4].y == 6);1380 assert(more_points[4].y == 6);
1348 assert(more_points.len == 10);1381 assert(more_points.len == 10);
1349}</code></pre>1382}
1350 <pre><code class="sh">$ zig test arrays.zig1383 {#code_end#}
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>
1355 {#see_also|for|Slices#}1384 {#see_also|for|Slices#}
1356 {#header_close#}1385 {#header_close#}
1357 {#header_open|Pointers#}1386 {#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
1360test "address of syntax" {1390test "address of syntax" {
1361 // Get the address of a variable:1391 // Get the address of a variable:
...@@ -1366,12 +1396,12 @@ test "address of syntax" {...@@ -1366,12 +1396,12 @@ test "address of syntax" {
1366 assert(*x_ptr == 1234);1396 assert(*x_ptr == 1234);
13671397
1368 // When you get the address of a const variable, you get a const pointer.1398 // 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
1371 // If you want to mutate the value, you'd need an address of a mutable variable:1401 // If you want to mutate the value, you'd need an address of a mutable variable:
1372 var y: i32 = 5678;1402 var y: i32 = 5678;
1373 const y_ptr = &y;1403 const y_ptr = &y;
1374 assert(@typeOf(y_ptr) == &amp;i32);1404 assert(@typeOf(y_ptr) == &i32);
1375 *y_ptr += 1;1405 *y_ptr += 1;
1376 assert(*y_ptr == 5679);1406 assert(*y_ptr == 5679);
1377}1407}
...@@ -1381,7 +1411,7 @@ test "pointer array access" {...@@ -1381,7 +1411,7 @@ test "pointer array access" {
1381 // need such a thing, use array index syntax:1411 // need such a thing, use array index syntax:
13821412
1383 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};1413 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
1386 assert(array[2] == 3);1416 assert(array[2] == 3);
1387 ptr[1] += 1;1417 ptr[1] += 1;
...@@ -1392,10 +1422,10 @@ test "pointer slicing" {...@@ -1392,10 +1422,10 @@ test "pointer slicing" {
1392 // In Zig, we prefer using slices over null-terminated pointers.1422 // In Zig, we prefer using slices over null-terminated pointers.
1393 // You can turn a pointer into a slice using slice syntax:1423 // You can turn a pointer into a slice using slice syntax:
1394 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};1424 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1395 const ptr = &amp;array[1];1425 const ptr = &array[1];
1396 const slice = ptr[1..3];1426 const slice = ptr[1..3];
13971427
1398 assert(slice.ptr == &amp;ptr[1]);1428 assert(slice.ptr == &ptr[1]);
1399 assert(slice.len == 2);1429 assert(slice.len == 2);
14001430
1401 // Slices have bounds checking and are therefore protected1431 // Slices have bounds checking and are therefore protected
...@@ -1410,7 +1440,7 @@ comptime {...@@ -1410,7 +1440,7 @@ comptime {
1410 // Pointers work at compile-time too, as long as you don't use1440 // Pointers work at compile-time too, as long as you don't use
1411 // @ptrCast.1441 // @ptrCast.
1412 var x: i32 = 1;1442 var x: i32 = 1;
1413 const ptr = &amp;x;1443 const ptr = &x;
1414 *ptr += 1;1444 *ptr += 1;
1415 x += 1;1445 x += 1;
1416 assert(*ptr == 3);1446 assert(*ptr == 3);
...@@ -1418,7 +1448,7 @@ comptime {...@@ -1418,7 +1448,7 @@ comptime {
14181448
1419test "@ptrToInt and @intToPtr" {1449test "@ptrToInt and @intToPtr" {
1420 // To convert an integer address into a pointer, use @intToPtr:1450 // To convert an integer address into a pointer, use @intToPtr:
1421 const ptr = @intToPtr(&amp;i32, 0xdeadbeef);1451 const ptr = @intToPtr(&i32, 0xdeadbeef);
14221452
1423 // To convert a pointer to an integer, use @ptrToInt:1453 // To convert a pointer to an integer, use @ptrToInt:
1424 const addr = @ptrToInt(ptr);1454 const addr = @ptrToInt(ptr);
...@@ -1430,7 +1460,7 @@ test "@ptrToInt and @intToPtr" {...@@ -1430,7 +1460,7 @@ test "@ptrToInt and @intToPtr" {
1430comptime {1460comptime {
1431 // Zig is able to do this at compile-time, as long as1461 // Zig is able to do this at compile-time, as long as
1432 // ptr is never dereferenced.1462 // ptr is never dereferenced.
1433 const ptr = @intToPtr(&amp;i32, 0xdeadbeef);1463 const ptr = @intToPtr(&i32, 0xdeadbeef);
1434 const addr = @ptrToInt(ptr);1464 const addr = @ptrToInt(ptr);
1435 assert(@typeOf(addr) == usize);1465 assert(@typeOf(addr) == usize);
1436 assert(addr == 0xdeadbeef);1466 assert(addr == 0xdeadbeef);
...@@ -1440,34 +1470,34 @@ test "volatile" {...@@ -1440,34 +1470,34 @@ test "volatile" {
1440 // In Zig, loads and stores are assumed to not have side effects.1470 // In Zig, loads and stores are assumed to not have side effects.
1441 // If a given load or store should have side effects, such as1471 // If a given load or store should have side effects, such as
1442 // Memory Mapped Input/Output (MMIO), use `volatile`:1472 // 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
1445 // Now loads and stores with mmio_ptr are guaranteed to all happen1475 // Now loads and stores with mmio_ptr are guaranteed to all happen
1446 // and in the same order as in source code.1476 // and in the same order as in source code.
1447 assert(@typeOf(mmio_ptr) == &amp;volatile u8);1477 assert(@typeOf(mmio_ptr) == &volatile u8);
1448}1478}
14491479
1450test "nullable pointers" {1480test "nullable pointers" {
1451 // Pointers cannot be null. If you want a null pointer, use the nullable1481 // Pointers cannot be null. If you want a null pointer, use the nullable
1452 // prefix `?` to make the pointer type nullable.1482 // prefix `?` to make the pointer type nullable.
1453 var ptr: ?&amp;i32 = null;1483 var ptr: ?&i32 = null;
14541484
1455 var x: i32 = 1;1485 var x: i32 = 1;
1456 ptr = &amp;x;1486 ptr = &x;
14571487
1458 assert(*??ptr == 1);1488 assert(*??ptr == 1);
14591489
1460 // Nullable pointers are the same size as normal pointers, because pointer1490 // Nullable pointers are the same size as normal pointers, because pointer
1461 // value 0 is used as the null value.1491 // value 0 is used as the null value.
1462 assert(@sizeOf(?&amp;i32) == @sizeOf(&amp;i32));1492 assert(@sizeOf(?&i32) == @sizeOf(&i32));
1463}1493}
14641494
1465test "pointer casting" {1495test "pointer casting" {
1466 // To convert one pointer type to another, use @ptrCast. This is an unsafe1496 // To convert one pointer type to another, use @ptrCast. This is an unsafe
1467 // operation that Zig cannot protect you against. Use @ptrCast only when other1497 // operation that Zig cannot protect you against. Use @ptrCast only when other
1468 // conversions are not possible.1498 // conversions are not possible.
1469 const bytes = []u8{0x12, 0x12, 0x12, 0x12};1499 const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
1470 const u32_ptr = @ptrCast(&amp;const u32, &amp;bytes[0]);1500 const u32_ptr = @ptrCast(&const u32, &bytes[0]);
1471 assert(*u32_ptr == 0x12121212);1501 assert(*u32_ptr == 0x12121212);
14721502
1473 // Even this example is contrived - there are better ways to do the above than1503 // Even this example is contrived - there are better ways to do the above than
...@@ -1481,17 +1511,9 @@ test "pointer casting" {...@@ -1481,17 +1511,9 @@ test "pointer casting" {
14811511
1482test "pointer child type" {1512test "pointer child type" {
1483 // pointer types have a `child` field which tells you the type they point to.1513 // pointer types have a `child` field which tells you the type they point to.
1484 assert((&amp;u32).child == u32);1514 assert((&u32).Child == u32);
1485}</code></pre>1515}
1486 <pre><code class="sh">$ zig test test.zig1516 {#code_end#}
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>
1495 {#header_open|Alignment#}1517 {#header_open|Alignment#}
1496 <p>1518 <p>
1497 Each type has an <strong>alignment</strong> - a number of bytes such that,1519 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>...@@ -1507,18 +1529,20 @@ Test 8/8 pointer child type...OK</code></pre>
1507 In Zig, a pointer type has an alignment value. If the value is equal to the1529 In Zig, a pointer type has an alignment value. If the value is equal to the
1508 alignment of the underlying type, it can be omitted from the type:1530 alignment of the underlying type, it can be omitted from the type:
1509 </p>1531 </p>
1510 <pre><code class="zig">const assert = @import("std").debug.assert;1532 {#code_begin|test#}
1533const assert = @import("std").debug.assert;
1511const builtin = @import("builtin");1534const builtin = @import("builtin");
15121535
1513test "variable alignment" {1536test "variable alignment" {
1514 var x: i32 = 1234;1537 var x: i32 = 1234;
1515 const align_of_i32 = @alignOf(@typeOf(x));1538 const align_of_i32 = @alignOf(@typeOf(x));
1516 assert(@typeOf(&amp;x) == &amp;i32);1539 assert(@typeOf(&x) == &i32);
1517 assert(&amp;i32 == &amp;align(align_of_i32) i32);1540 assert(&i32 == &align(align_of_i32) i32);
1518 if (builtin.arch == builtin.Arch.x86_64) {1541 if (builtin.arch == builtin.Arch.x86_64) {
1519 assert((&amp;i32).alignment == 4);1542 assert((&i32).alignment == 4);
1520 }1543 }
1521}</code></pre>1544}
1545 {#code_end#}
1522 <p>In the same way that a <code>&amp;i32</code> can be implicitly cast to a1546 <p>In the same way that a <code>&amp;i32</code> can be implicitly cast to a
1523 <code>&amp;const i32</code>, a pointer with a larger alignment can be implicitly1547 <code>&amp;const i32</code>, a pointer with a larger alignment can be implicitly
1524 cast to a pointer with a smaller alignment, but not vice versa.1548 cast to a pointer with a smaller alignment, but not vice versa.
...@@ -1527,18 +1551,19 @@ test "variable alignment" {...@@ -1527,18 +1551,19 @@ test "variable alignment" {
1527 You can specify alignment on variables and functions. If you do this, then1551 You can specify alignment on variables and functions. If you do this, then
1528 pointers to them get the specified alignment:1552 pointers to them get the specified alignment:
1529 </p>1553 </p>
1530 <pre><code class="zig">const assert = @import("std").debug.assert;1554 {#code_begin|test#}
1555const assert = @import("std").debug.assert;
15311556
1532var foo: u8 align(4) = 100;1557var foo: u8 align(4) = 100;
15331558
1534test "global variable alignment" {1559test "global variable alignment" {
1535 assert(@typeOf(&amp;foo).alignment == 4);1560 assert(@typeOf(&foo).alignment == 4);
1536 assert(@typeOf(&amp;foo) == &amp;align(4) u8);1561 assert(@typeOf(&foo) == &align(4) u8);
1537 const slice = (&amp;foo)[0..1];1562 const slice = (&foo)[0..1];
1538 assert(@typeOf(slice) == []align(4) u8);1563 assert(@typeOf(slice) == []align(4) u8);
1539}1564}
15401565
1541fn derp() align(@sizeOf(usize) * 2) -&gt; i32 { 1234 }1566fn derp() align(@sizeOf(usize) * 2) -> i32 { return 1234; }
1542fn noop1() align(1) {}1567fn noop1() align(1) {}
1543fn noop4() align(4) {}1568fn noop4() align(4) {}
15441569
...@@ -1548,51 +1573,28 @@ test "function alignment" {...@@ -1548,51 +1573,28 @@ test "function alignment" {
1548 assert(@typeOf(noop4) == fn() align(4));1573 assert(@typeOf(noop4) == fn() align(4));
1549 noop1();1574 noop1();
1550 noop4();1575 noop4();
1551}</code></pre>1576}
1577 {#code_end#}
1552 <p>1578 <p>
1553 If you have a pointer or a slice that has a small alignment, but you know that it actually1579 If you have a pointer or a slice that has a small alignment, but you know that it actually
1554 has a bigger alignment, use <a href="#builtin-alignCast">@alignCast</a> to change the1580 has a bigger alignment, use <a href="#builtin-alignCast">@alignCast</a> to change the
1555 pointer into a more aligned pointer. This is a no-op at runtime, but inserts a1581 pointer into a more aligned pointer. This is a no-op at runtime, but inserts a
1556 <a href="#undef-incorrect-pointer-alignment">safety check</a>:1582 <a href="#undef-incorrect-pointer-alignment">safety check</a>:
1557 </p>1583 </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
1560test "pointer alignment safety" {1587test "pointer alignment safety" {
1561 var array align(4) = []u32{0x11111111, 0x11111111};1588 var array align(4) = []u32{0x11111111, 0x11111111};
1562 const bytes = ([]u8)(array[0..]);1589 const bytes = ([]u8)(array[0..]);
1563 assert(foo(bytes) == 0x11111111);1590 assert(foo(bytes) == 0x11111111);
1564}1591}
1565fn foo(bytes: []u8) -&gt; u32 {1592fn foo(bytes: []u8) -> u32 {
1566 const slice4 = bytes[1..5];1593 const slice4 = bytes[1..5];
1567 const int_slice = ([]u32)(@alignCast(4, slice4));1594 const int_slice = ([]u32)(@alignCast(4, slice4));
1568 return int_slice[0];1595 return int_slice[0];
1569}</code></pre>1596}
1570 <pre><code class="sh">$ zig test test.zig1597 {#code_end#}
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 {#header_close#}1598 {#header_close#}
1597 {#header_open|Type Based Alias Analysis#}1599 {#header_open|Type Based Alias Analysis#}
1598 <p>Zig uses Type Based Alias Analysis (also known as Strict Aliasing) to1600 <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:...@@ -1609,7 +1611,8 @@ Tests failed. Use the following command to reproduce the failure:
1609 {#header_close#}1611 {#header_close#}
1610 {#header_close#}1612 {#header_close#}
1611 {#header_open|Slices#}1613 {#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
1614test "basic slices" {1617test "basic slices" {
1615 var array = []i32{1, 2, 3, 4};1618 var array = []i32{1, 2, 3, 4};
...@@ -1618,38 +1621,17 @@ test "basic slices" {...@@ -1618,38 +1621,17 @@ test "basic slices" {
1618 // compile-time, whereas the slice's length is known at runtime.1621 // compile-time, whereas the slice's length is known at runtime.
1619 // Both can be accessed with the `len` field.1622 // Both can be accessed with the `len` field.
1620 const slice = array[0..array.len];1623 const slice = array[0..array.len];
1621 assert(slice.ptr == &amp;array[0]);1624 assert(slice.ptr == &array[0]);
1622 assert(slice.len == array.len);1625 assert(slice.len == array.len);
16231626
1624 // Slices have array bounds checking. If you try to access something out1627 // Slices have array bounds checking. If you try to access something out
1625 // of bounds, you'll get a safety check failure:1628 // of bounds, you'll get a safety check failure:
1626 slice[10] += 1;1629 slice[10] += 1;
1627}</code></pre>1630}
1628 <pre><code class="sh">$ zig test test.zig1631 {#code_end#}
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>
1651 <p>This is one reason we prefer slices to pointers.</p>1632 <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;
1653const mem = @import("std").mem;1635const mem = @import("std").mem;
1654const fmt = @import("std").fmt;1636const fmt = @import("std").fmt;
16551637
...@@ -1663,8 +1645,8 @@ test "using slices for strings" {...@@ -1663,8 +1645,8 @@ test "using slices for strings" {
1663 var all_together: [100]u8 = undefined;1645 var all_together: [100]u8 = undefined;
1664 // You can use slice syntax on an array to convert an array into a slice.1646 // You can use slice syntax on an array to convert an array into a slice.
1665 const all_together_slice = all_together[0..];1647 const all_together_slice = all_together[0..];
1666 // String concatenation example:1648 // String concatenation example.
1667 const hello_world = fmt.bufPrint(all_together_slice, "{} {}", hello, world);1649 const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", hello, world);
16681650
1669 // Generally, you can use UTF-8 and not worry about whether something is a1651 // Generally, you can use UTF-8 and not worry about whether something is a
1670 // string. If you don't need to deal with individual characters, no need1652 // string. If you don't need to deal with individual characters, no need
...@@ -1674,7 +1656,7 @@ test "using slices for strings" {...@@ -1674,7 +1656,7 @@ test "using slices for strings" {
16741656
1675test "slice pointer" {1657test "slice pointer" {
1676 var array: [10]u8 = undefined;1658 var array: [10]u8 = undefined;
1677 const ptr = &amp;array[0];1659 const ptr = &array[0];
16781660
1679 // You can use slicing syntax to convert a pointer into a slice:1661 // You can use slicing syntax to convert a pointer into a slice:
1680 const slice = ptr[0..5];1662 const slice = ptr[0..5];
...@@ -1692,20 +1674,18 @@ test "slice pointer" {...@@ -1692,20 +1674,18 @@ test "slice pointer" {
1692test "slice widening" {1674test "slice widening" {
1693 // Zig supports slice widening and slice narrowing. Cast a slice of u81675 // Zig supports slice widening and slice narrowing. Cast a slice of u8
1694 // to a slice of anything else, and Zig will perform the length conversion.1676 // 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};
1696 const slice = ([]const u32)(array[0..]);1678 const slice = ([]const u32)(array[0..]);
1697 assert(slice.len == 2);1679 assert(slice.len == 2);
1698 assert(slice[0] == 0x12121212);1680 assert(slice[0] == 0x12121212);
1699 assert(slice[1] == 0x13131313);1681 assert(slice[1] == 0x13131313);
1700}</code></pre>1682}
1701 <pre><code class="sh">$ zig test test.zig1683 {#code_end#}
1702Test 1/3 using slices for strings...OK
1703Test 2/3 slice pointer...OK
1704Test 3/3 slice widening...OK</code></pre>
1705 {#see_also|Pointers|for|Arrays#}1684 {#see_also|Pointers|for|Arrays#}
1706 {#header_close#}1685 {#header_close#}
1707 {#header_open|struct#}1686 {#header_open|struct#}
1708 <pre><code class="zig">// Declare a struct.1687 {#code_begin|test|structs#}
1688// Declare a struct.
1709// Zig gives no guarantees about the order of fields and whether or1689// Zig gives no guarantees about the order of fields and whether or
1710// not there will be padding.1690// not there will be padding.
1711const Point = struct {1691const Point = struct {
...@@ -1741,7 +1721,7 @@ const Vec3 = struct {...@@ -1741,7 +1721,7 @@ const Vec3 = struct {
1741 y: f32,1721 y: f32,
1742 z: f32,1722 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 {
1745 return Vec3 {1725 return Vec3 {
1746 .x = x,1726 .x = x,
1747 .y = y,1727 .y = y,
...@@ -1749,7 +1729,7 @@ const Vec3 = struct {...@@ -1749,7 +1729,7 @@ const Vec3 = struct {
1749 };1729 };
1750 }1730 }
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 {
1753 return self.x * other.x + self.y * other.y + self.z * other.z;1733 return self.x * other.x + self.y * other.y + self.z * other.z;
1754 }1734 }
1755};1735};
...@@ -1781,7 +1761,7 @@ test "struct namespaced variable" {...@@ -1781,7 +1761,7 @@ test "struct namespaced variable" {
17811761
1782// struct field order is determined by the compiler for optimal performance.1762// struct field order is determined by the compiler for optimal performance.
1783// however, you can still calculate a struct base pointer given a field pointer:1763// 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) {
1785 const point = @fieldParentPtr(Point, "x", x);1765 const point = @fieldParentPtr(Point, "x", x);
1786 point.y = y;1766 point.y = y;
1787}1767}
...@@ -1790,22 +1770,22 @@ test "field parent pointer" {...@@ -1790,22 +1770,22 @@ test "field parent pointer" {
1790 .x = 0.1234,1770 .x = 0.1234,
1791 .y = 0.5678,1771 .y = 0.5678,
1792 };1772 };
1793 setYBasedOnX(&amp;point.x, 0.9);1773 setYBasedOnX(&point.x, 0.9);
1794 assert(point.y == 0.9);1774 assert(point.y == 0.9);
1795}1775}
17961776
1797// You can return a struct from a function. This is how we do generics1777// You can return a struct from a function. This is how we do generics
1798// in Zig:1778// in Zig:
1799fn LinkedList(comptime T: type) -&gt; type {1779fn LinkedList(comptime T: type) -> type {
1800 return struct {1780 return struct {
1801 pub const Node = struct {1781 pub const Node = struct {
1802 prev: ?&amp;Node,1782 prev: ?&Node,
1803 next: ?&amp;Node,1783 next: ?&Node,
1804 data: T,1784 data: T,
1805 };1785 };
18061786
1807 first: ?&amp;Node,1787 first: ?&Node,
1808 last: ?&amp;Node,1788 last: ?&Node,
1809 len: usize,1789 len: usize,
1810 };1790 };
1811}1791}
...@@ -1833,21 +1813,18 @@ test "linked list" {...@@ -1833,21 +1813,18 @@ test "linked list" {
1833 .data = 1234,1813 .data = 1234,
1834 };1814 };
1835 var list2 = LinkedList(i32) {1815 var list2 = LinkedList(i32) {
1836 .first = &amp;node,1816 .first = &node,
1837 .last = &amp;node,1817 .last = &node,
1838 .len = 1,1818 .len = 1,
1839 };1819 };
1840 assert((??list2.first).data == 1234);1820 assert((??list2.first).data == 1234);
1841}</code></pre>1821}
1842 <pre><code class="sh">$ zig test structs.zig1822 {#code_end#}
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>
1847 {#see_also|comptime|@fieldParentPtr#}1823 {#see_also|comptime|@fieldParentPtr#}
1848 {#header_close#}1824 {#header_close#}
1849 {#header_open|enum#}1825 {#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;
1851const mem = @import("std").mem;1828const mem = @import("std").mem;
18521829
1853// Declare an enum.1830// Declare an enum.
...@@ -1896,7 +1873,7 @@ const Suit = enum {...@@ -1896,7 +1873,7 @@ const Suit = enum {
1896 Diamonds,1873 Diamonds,
1897 Hearts,1874 Hearts,
18981875
1899 pub fn isClubs(self: Suit) -&gt; bool {1876 pub fn isClubs(self: Suit) -> bool {
1900 return self == Suit.Clubs;1877 return self == Suit.Clubs;
1901 }1878 }
1902};1879};
...@@ -1914,9 +1891,9 @@ const Foo = enum {...@@ -1914,9 +1891,9 @@ const Foo = enum {
1914test "enum variant switch" {1891test "enum variant switch" {
1915 const p = Foo.Number;1892 const p = Foo.Number;
1916 const what_is_it = switch (p) {1893 const what_is_it = switch (p) {
1917 Foo.String =&gt; "this is a string",1894 Foo.String => "this is a string",
1918 Foo.Number =&gt; "this is a number",1895 Foo.Number => "this is a number",
1919 Foo.None =&gt; "this is a none",1896 Foo.None => "this is a none",
1920 };1897 };
1921 assert(mem.eql(u8, what_is_it, "this is a number"));1898 assert(mem.eql(u8, what_is_it, "this is a number"));
1922}1899}
...@@ -1945,22 +1922,15 @@ test "@memberName" {...@@ -1945,22 +1922,15 @@ test "@memberName" {
1945// @tagName gives a []const u8 representation of an enum value:1922// @tagName gives a []const u8 representation of an enum value:
1946test "@tagName" {1923test "@tagName" {
1947 assert(mem.eql(u8, @tagName(Small.Three), "Three"));1924 assert(mem.eql(u8, @tagName(Small.Three), "Three"));
1948}</code></pre>1925}
1926 {#code_end#}
1949 <p>TODO extern enum</p>1927 <p>TODO extern enum</p>
1950 <p>TODO packed enum</p>1928 <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>
1960 {#see_also|@memberName|@memberCount|@tagName#}1929 {#see_also|@memberName|@memberCount|@tagName#}
1961 {#header_close#}1930 {#header_close#}
1962 {#header_open|union#}1931 {#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;
1964const mem = @import("std").mem;1934const mem = @import("std").mem;
19651935
1966// A union has only 1 active field at a time.1936// A union has only 1 active field at a time.
...@@ -2008,19 +1978,19 @@ test "union variant switch" {...@@ -2008,19 +1978,19 @@ test "union variant switch" {
2008 const p = Foo { .Number = 54 };1978 const p = Foo { .Number = 54 };
2009 const what_is_it = switch (p) {1979 const what_is_it = switch (p) {
2010 // Capture by reference1980 // Capture by reference
2011 Foo.String =&gt; |*x| {1981 Foo.String => |*x| blk: {
2012 "this is a string"1982 break :blk "this is a string";
2013 },1983 },
20141984
2015 // Capture by value1985 // Capture by value
2016 Foo.Number =&gt; |x| {1986 Foo.Number => |x| blk: {
2017 assert(x == 54);1987 assert(x == 54);
2018 "this is a number"1988 break :blk "this is a number";
2019 },1989 },
20201990
2021 Foo.None =&gt; {1991 Foo.None => blk: {
2022 "this is a none"1992 break :blk "this is a none";
2023 }1993 },
2024 };1994 };
2025 assert(mem.eql(u8, what_is_it, "this is a number"));1995 assert(mem.eql(u8, what_is_it, "this is a number"));
2026}1996}
...@@ -2053,22 +2023,16 @@ const Small2 = union(enum) {...@@ -2053,22 +2023,16 @@ const Small2 = union(enum) {
2053};2023};
2054test "@tagName" {2024test "@tagName" {
2055 assert(mem.eql(u8, @tagName(Small2.C), "C"));2025 assert(mem.eql(u8, @tagName(Small2.C), "C"));
2056}</code></pre>2026}
2057 <pre><code class="sh">$ zig test union.zig2027 {#code_end#}
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>
2065 <p>2028 <p>
2066 Unions with an enum tag are generated as a struct with a tag field and union field. Zig2029 Unions with an enum tag are generated as a struct with a tag field and union field. Zig
2067 sorts the order of the tag and union field by the largest alignment.2030 sorts the order of the tag and union field by the largest alignment.
2068 </p>2031 </p>
2069 {#header_close#}2032 {#header_close#}
2070 {#header_open|switch#}2033 {#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;
2072const builtin = @import("builtin");2036const builtin = @import("builtin");
20732037
2074test "switch simple" {2038test "switch simple" {
...@@ -2082,59 +2046,59 @@ test "switch simple" {...@@ -2082,59 +2046,59 @@ test "switch simple" {
2082 // the cases and use an if.2046 // the cases and use an if.
2083 const b = switch (a) {2047 const b = switch (a) {
2084 // Multiple cases can be combined via a ','2048 // Multiple cases can be combined via a ','
2085 1, 2, 3 =&gt; 0,2049 1, 2, 3 => 0,
20862050
2087 // Ranges can be specified using the ... syntax. These are inclusive2051 // Ranges can be specified using the ... syntax. These are inclusive
2088 // both ends.2052 // both ends.
2089 5 ... 100 =&gt; 1,2053 5 ... 100 => 1,
20902054
2091 // Branches can be arbitrarily complex.2055 // Branches can be arbitrarily complex.
2092 101 =&gt; {2056 101 => blk: {
2093 const c: u64 = 5;2057 const c: u64 = 5;
2094 c * 2 + 12058 break :blk c * 2 + 1;
2095 },2059 },
20962060
2097 // Switching on arbitrary expressions is allowed as long as the2061 // Switching on arbitrary expressions is allowed as long as the
2098 // expression is known at compile-time.2062 // expression is known at compile-time.
2099 zz =&gt; zz,2063 zz => zz,
2100 comptime {2064 comptime blk: {
2101 const d: u32 = 5;2065 const d: u32 = 5;
2102 const e: u32 = 100;2066 const e: u32 = 100;
2103 d + e2067 break :blk d + e;
2104 } =&gt; 107,2068 } => 107,
21052069
2106 // The else branch catches everything not already captured.2070 // The else branch catches everything not already captured.
2107 // Else branches are mandatory unless the entire range of values2071 // Else branches are mandatory unless the entire range of values
2108 // is handled.2072 // is handled.
2109 else =&gt; 9,2073 else => 9,
2110 };2074 };
21112075
2112 assert(b == 1);2076 assert(b == 1);
2113}2077}
21142078
2115test "switch enum" {2079test "switch enum" {
2116 const Item = enum {2080 const Item = union(enum) {
2117 A: u32,2081 A: u32,
2118 C: struct { x: u8, y: u8 },2082 C: struct { x: u8, y: u8 },
2119 D,2083 D,
2120 };2084 };
21212085
2122 var a = Item.A { 3 };2086 var a = Item { .A = 3 };
21232087
2124 // Switching on more complex enums is allowed.2088 // Switching on more complex enums is allowed.
2125 const b = switch (a) {2089 const b = switch (a) {
2126 // A capture group is allowed on a match, and will return the enum2090 // A capture group is allowed on a match, and will return the enum
2127 // value matched.2091 // value matched.
2128 Item.A =&gt; |item| item,2092 Item.A => |item| item,
21292093
2130 // A reference to the matched value can be obtained using `*` syntax.2094 // A reference to the matched value can be obtained using `*` syntax.
2131 Item.C =&gt; |*item| {2095 Item.C => |*item| blk: {
2132 (*item).x += 1;2096 (*item).x += 1;
2133 62097 break :blk 6;
2134 },2098 },
21352099
2136 // No else is required if the types cases was exhaustively handled2100 // No else is required if the types cases was exhaustively handled
2137 Item.D =&gt; 8,2101 Item.D => 8,
2138 };2102 };
21392103
2140 assert(b == 3);2104 assert(b == 3);
...@@ -2142,37 +2106,35 @@ test "switch enum" {...@@ -2142,37 +2106,35 @@ test "switch enum" {
21422106
2143// Switch expressions can be used outside a function:2107// Switch expressions can be used outside a function:
2144const os_msg = switch (builtin.os) {2108const os_msg = switch (builtin.os) {
2145 builtin.Os.linux =&gt; "we found a linux user",2109 builtin.Os.linux => "we found a linux user",
2146 else =&gt; "not a linux user",2110 else => "not a linux user",
2147};2111};
21482112
2149// Inside a function, switch statements implicitly are compile-time2113// Inside a function, switch statements implicitly are compile-time
2150// evaluated if the target expression is compile-time known.2114// evaluated if the target expression is compile-time known.
2151test "switch inside function" {2115test "switch inside function" {
2152 switch (builtin.os) {2116 switch (builtin.os) {
2153 builtin.Os.windows =&gt; {2117 builtin.Os.windows => {
2154 // On an OS other than windows, block is not even analyzed,2118 // On an OS other than windows, block is not even analyzed,
2155 // so this compile error is not triggered.2119 // so this compile error is not triggered.
2156 // On windows this compile error would be triggered.2120 // On windows this compile error would be triggered.
2157 @compileError("windows not supported");2121 @compileError("windows not supported");
2158 },2122 },
2159 else =&gt; {},2123 else => {},
2160 };2124 }
2161}</code></pre>2125}
2162 <pre><code class="sh">$ zig test switch.zig2126 {#code_end#}
2163Test 1/2 switch simple...OK
2164Test 2/2 switch enum...OK
2165Test 3/3 switch inside function...OK</code></pre>
2166 {#see_also|comptime|enum|@compileError|Compile Variables#}2127 {#see_also|comptime|enum|@compileError|Compile Variables#}
2167 {#header_close#}2128 {#header_close#}
2168 {#header_open|while#}2129 {#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
2171test "while basic" {2133test "while basic" {
2172 // A while loop is used to repeatedly execute an expression until2134 // A while loop is used to repeatedly execute an expression until
2173 // some condition is no longer true.2135 // some condition is no longer true.
2174 var i: usize = 0;2136 var i: usize = 0;
2175 while (i &lt; 10) {2137 while (i < 10) {
2176 i += 1;2138 i += 1;
2177 }2139 }
2178 assert(i == 10);2140 assert(i == 10);
...@@ -2194,7 +2156,7 @@ test "while continue" {...@@ -2194,7 +2156,7 @@ test "while continue" {
2194 var i: usize = 0;2156 var i: usize = 0;
2195 while (true) {2157 while (true) {
2196 i += 1;2158 i += 1;
2197 if (i &lt; 10)2159 if (i < 10)
2198 continue;2160 continue;
2199 break;2161 break;
2200 }2162 }
...@@ -2205,7 +2167,7 @@ test "while loop continuation expression" {...@@ -2205,7 +2167,7 @@ test "while loop continuation expression" {
2205 // You can give an expression to the while loop to execute when2167 // You can give an expression to the while loop to execute when
2206 // the loop is continued. This is respected by the continue control flow.2168 // the loop is continued. This is respected by the continue control flow.
2207 var i: usize = 0;2169 var i: usize = 0;
2208 while (i &lt; 10) : (i += 1) {}2170 while (i < 10) : (i += 1) {}
2209 assert(i == 10);2171 assert(i == 10);
2210}2172}
22112173
...@@ -2214,9 +2176,9 @@ test "while loop continuation expression, more complicated" {...@@ -2214,9 +2176,9 @@ test "while loop continuation expression, more complicated" {
2214 // expression.2176 // expression.
2215 var i1: usize = 1;2177 var i1: usize = 1;
2216 var j1: usize = 1;2178 var j1: usize = 1;
2217 while (i1 * j1 &lt; 2000) : ({ i1 *= 2; j1 *= 3; }) {2179 while (i1 * j1 < 2000) : ({ i1 *= 2; j1 *= 3; }) {
2218 const my_ij1 = i1 * j1;2180 const my_ij1 = i1 * j1;
2219 assert(my_ij1 &lt; 2000);2181 assert(my_ij1 < 2000);
2220 }2182 }
2221}2183}
22222184
...@@ -2225,12 +2187,12 @@ test "while else" {...@@ -2225,12 +2187,12 @@ test "while else" {
2225 assert(!rangeHasNumber(0, 10, 15));2187 assert(!rangeHasNumber(0, 10, 15));
2226}2188}
22272189
2228fn rangeHasNumber(begin: usize, end: usize, number: usize) -&gt; bool {2190fn rangeHasNumber(begin: usize, end: usize, number: usize) -> bool {
2229 var i = begin;2191 var i = begin;
2230 // While loops are expressions. The result of the expression is the2192 // While loops are expressions. The result of the expression is the
2231 // result of the else clause of a while loop, which is executed when2193 // result of the else clause of a while loop, which is executed when
2232 // the condition of the while loop is tested as false.2194 // 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) {
2234 if (i == number) {2196 if (i == number) {
2235 // break expressions, like return expressions, accept a value2197 // break expressions, like return expressions, accept a value
2236 // parameter. This is the result of the while expression.2198 // parameter. This is the result of the while expression.
...@@ -2238,9 +2200,7 @@ fn rangeHasNumber(begin: usize, end: usize, number: usize) -&gt; bool {...@@ -2238,9 +2200,7 @@ fn rangeHasNumber(begin: usize, end: usize, number: usize) -&gt; bool {
2238 // evaluated.2200 // evaluated.
2239 break true;2201 break true;
2240 }2202 }
2241 } else {2203 } else false;
2242 false
2243 }
2244}2204}
22452205
2246test "while null capture" {2206test "while null capture" {
...@@ -2278,22 +2238,18 @@ test "while null capture" {...@@ -2278,22 +2238,18 @@ test "while null capture" {
2278}2238}
22792239
2280var numbers_left: u32 = undefined;2240var numbers_left: u32 = undefined;
2281fn eventuallyNullSequence() -&gt; ?u32 {2241fn eventuallyNullSequence() -> ?u32 {
2282 return if (numbers_left == 0) {2242 return if (numbers_left == 0) null else blk: {
2283 null
2284 } else {
2285 numbers_left -= 1;2243 numbers_left -= 1;
2286 numbers_left2244 break :blk numbers_left;
2287 }2245 };
2288}2246}
2289error ReachedZero;2247error ReachedZero;
2290fn eventuallyErrorSequence() -&gt; %u32 {2248fn eventuallyErrorSequence() -> %u32 {
2291 return if (numbers_left == 0) {2249 return if (numbers_left == 0) error.ReachedZero else blk: {
2292 error.ReachedZero
2293 } else {
2294 numbers_left -= 1;2250 numbers_left -= 1;
2295 numbers_left2251 break :blk numbers_left;
2296 }2252 };
2297}2253}
22982254
2299test "inline while loop" {2255test "inline while loop" {
...@@ -2302,34 +2258,27 @@ test "inline while loop" {...@@ -2302,34 +2258,27 @@ test "inline while loop" {
2302 // such as use types as first class values.2258 // such as use types as first class values.
2303 comptime var i = 0;2259 comptime var i = 0;
2304 var sum: usize = 0;2260 var sum: usize = 0;
2305 inline while (i &lt; 3) : (i += 1) {2261 inline while (i < 3) : (i += 1) {
2306 const T = switch (i) {2262 const T = switch (i) {
2307 0 =&gt; f32,2263 0 => f32,
2308 1 =&gt; i8,2264 1 => i8,
2309 2 =&gt; bool,2265 2 => bool,
2310 else =&gt; unreachable,2266 else => unreachable,
2311 };2267 };
2312 sum += typeNameLength(T);2268 sum += typeNameLength(T);
2313 }2269 }
2314 assert(sum == 9);2270 assert(sum == 9);
2315}2271}
23162272
2317fn typeNameLength(comptime T: type) -&gt; usize {2273fn typeNameLength(comptime T: type) -> usize {
2318 return @typeName(T).len;2274 return @typeName(T).len;
2319}</code></pre>2275}
2320 <pre><code class="sh">$ zig while.zig2276 {#code_end#}
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>
2329 {#see_also|if|Nullables|Errors|comptime|unreachable#}2277 {#see_also|if|Nullables|Errors|comptime|unreachable#}
2330 {#header_close#}2278 {#header_close#}
2331 {#header_open|for#}2279 {#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
2334test "for basics" {2283test "for basics" {
2335 const items = []i32 { 4, 5, 3, 4, 0 };2284 const items = []i32 { 4, 5, 3, 4, 0 };
...@@ -2387,9 +2336,9 @@ test "for else" {...@@ -2387,9 +2336,9 @@ test "for else" {
2387 } else {2336 } else {
2388 sum += ??value;2337 sum += ??value;
2389 }2338 }
2390 } else {2339 } else blk: {
2391 assert(sum == 7);2340 assert(sum == 7);
2392 sum2341 break :blk sum;
2393 };2342 };
2394}2343}
23952344
...@@ -2404,28 +2353,25 @@ test "inline for loop" {...@@ -2404,28 +2353,25 @@ test "inline for loop" {
2404 var sum: usize = 0;2353 var sum: usize = 0;
2405 inline for (nums) |i| {2354 inline for (nums) |i| {
2406 const T = switch (i) {2355 const T = switch (i) {
2407 2 =&gt; f32,2356 2 => f32,
2408 4 =&gt; i8,2357 4 => i8,
2409 6 =&gt; bool,2358 6 => bool,
2410 else =&gt; unreachable,2359 else => unreachable,
2411 };2360 };
2412 sum += typeNameLength(T);2361 sum += typeNameLength(T);
2413 }2362 }
2414 assert(sum == 9);2363 assert(sum == 9);
2415}2364}
24162365
2417fn typeNameLength(comptime T: type) -&gt; usize {2366fn typeNameLength(comptime T: type) -> usize {
2418 return @typeName(T).len;2367 return @typeName(T).len;
2419}</code></pre>2368}
2420 <pre><code class="sh">$ zig test for.zig2369 {#code_end#}
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>
2425 {#see_also|while|comptime|Arrays|Slices#}2370 {#see_also|while|comptime|Arrays|Slices#}
2426 {#header_close#}2371 {#header_close#}
2427 {#header_open|if#}2372 {#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:
2429// * bool2375// * bool
2430// * ?T2376// * ?T
2431// * %T2377// * %T
...@@ -2439,9 +2385,9 @@ test "if boolean" {...@@ -2439,9 +2385,9 @@ test "if boolean" {
2439 if (a != b) {2385 if (a != b) {
2440 assert(true);2386 assert(true);
2441 } else if (a == 9) {2387 } else if (a == 9) {
2442 unreachable2388 unreachable;
2443 } else {2389 } else {
2444 unreachable2390 unreachable;
2445 }2391 }
24462392
2447 // If expressions are used instead of a ternary expression.2393 // If expressions are used instead of a ternary expression.
...@@ -2499,12 +2445,12 @@ test "if error union" {...@@ -2499,12 +2445,12 @@ test "if error union" {
2499 if (a) |value| {2445 if (a) |value| {
2500 assert(value == 0);2446 assert(value == 0);
2501 } else |err| {2447 } else |err| {
2502 unreachable2448 unreachable;
2503 }2449 }
25042450
2505 const b: %u32 = error.BadValue;2451 const b: %u32 = error.BadValue;
2506 if (b) |value| {2452 if (b) |value| {
2507 unreachable2453 unreachable;
2508 } else |err| {2454 } else |err| {
2509 assert(err == error.BadValue);2455 assert(err == error.BadValue);
2510 }2456 }
...@@ -2524,27 +2470,26 @@ test "if error union" {...@@ -2524,27 +2470,26 @@ test "if error union" {
2524 if (c) |*value| {2470 if (c) |*value| {
2525 *value = 9;2471 *value = 9;
2526 } else |err| {2472 } else |err| {
2527 unreachable2473 unreachable;
2528 }2474 }
25292475
2530 if (c) |value| {2476 if (c) |value| {
2531 assert(value == 9);2477 assert(value == 9);
2532 } else |err| {2478 } else |err| {
2533 unreachable2479 unreachable;
2534 }2480 }
2535}</code></pre>2481}
2536 <pre><code class="sh">$ zig test if.zig2482 {#code_end#}
2537Test 1/3 if boolean...OK
2538Test 2/3 if nullable...OK
2539Test 3/3 if error union...OK</code></pre>
2540 {#see_also|Nullables|Errors#}2483 {#see_also|Nullables|Errors#}
2541 {#header_close#}2484 {#header_close#}
2542 {#header_open|defer#}2485 {#header_open|defer#}
2543 <pre><code class="zig">const assert = @import("std").debug.assert;2486 {#code_begin|test|defer#}
2544const printf = @import("std").io.stdout.printf;2487const std = @import("std");
2488const assert = std.debug.assert;
2489const warn = std.debug.warn;
25452490
2546// defer will execute an expression at the end of the current scope.2491// defer will execute an expression at the end of the current scope.
2547fn deferExample() -&gt; usize {2492fn deferExample() -> usize {
2548 var a: usize = 1;2493 var a: usize = 1;
25492494
2550 {2495 {
...@@ -2554,7 +2499,7 @@ fn deferExample() -&gt; usize {...@@ -2554,7 +2499,7 @@ fn deferExample() -&gt; usize {
2554 assert(a == 2);2499 assert(a == 2);
25552500
2556 a = 5;2501 a = 5;
2557 a2502 return a;
2558}2503}
25592504
2560test "defer basics" {2505test "defer basics" {
...@@ -2564,24 +2509,24 @@ test "defer basics" {...@@ -2564,24 +2509,24 @@ test "defer basics" {
2564// If multiple defer statements are specified, they will be executed in2509// If multiple defer statements are specified, they will be executed in
2565// the reverse order they were run.2510// the reverse order they were run.
2566fn deferUnwindExample() {2511fn deferUnwindExample() {
2567 %%printf("\n");2512 warn("\n");
25682513
2569 defer {2514 defer {
2570 %%printf("1 ");2515 warn("1 ");
2571 }2516 }
2572 defer {2517 defer {
2573 %%printf("2 ");2518 warn("2 ");
2574 }2519 }
2575 if (false) {2520 if (false) {
2576 // defers are not run if they are never executed.2521 // defers are not run if they are never executed.
2577 defer {2522 defer {
2578 %%printf("3 ");2523 warn("3 ");
2579 }2524 }
2580 }2525 }
2581}2526}
25822527
2583test "defer unwinding" {2528test "defer unwinding" {
2584 deferUnwindExample()2529 deferUnwindExample();
2585}2530}
25862531
2587// The %defer keyword is similar to defer, but will only execute if the2532// The %defer keyword is similar to defer, but will only execute if the
...@@ -2590,16 +2535,16 @@ test "defer unwinding" {...@@ -2590,16 +2535,16 @@ test "defer unwinding" {
2590// This is especially useful in allowing a function to clean up properly2535// This is especially useful in allowing a function to clean up properly
2591// on error, and replaces goto error handling tactics as seen in c.2536// on error, and replaces goto error handling tactics as seen in c.
2592error DeferError;2537error DeferError;
2593fn deferErrorExample(is_error: bool) -&gt; %void {2538fn deferErrorExample(is_error: bool) -> %void {
2594 %%printf("\nstart of function\n");2539 warn("\nstart of function\n");
25952540
2596 // This will always be executed on exit2541 // This will always be executed on exit
2597 defer {2542 defer {
2598 %%printf("end of function\n");2543 warn("end of function\n");
2599 }2544 }
26002545
2601 %defer {2546 %defer {
2602 %%printf("encountered an error!\n");2547 warn("encountered an error!\n");
2603 }2548 }
26042549
2605 if (is_error) {2550 if (is_error) {
...@@ -2611,20 +2556,7 @@ test "%defer unwinding" {...@@ -2611,20 +2556,7 @@ test "%defer unwinding" {
2611 _ = deferErrorExample(false);2556 _ = deferErrorExample(false);
2612 _ = deferErrorExample(true);2557 _ = deferErrorExample(true);
2613}2558}
2614</code></pre>2559 {#code_end#}
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>
2628 {#see_also|Errors#}2560 {#see_also|Errors#}
2629 {#header_close#}2561 {#header_close#}
2630 {#header_open|unreachable#}2562 {#header_open|unreachable#}
...@@ -2638,7 +2570,8 @@ OK...@@ -2638,7 +2570,8 @@ OK
2638 still emits <code>unreachable</code> as calls to <code>panic</code>.2570 still emits <code>unreachable</code> as calls to <code>panic</code>.
2639 </p>2571 </p>
2640 {#header_open|Basics#}2572 {#header_open|Basics#}
2641 <pre><code class="zig">// unreachable is used to assert that control flow will never happen upon a2573 {#code_begin|test#}
2574// unreachable is used to assert that control flow will never happen upon a
2642// particular location:2575// particular location:
2643test "basic math" {2576test "basic math" {
2644 const x = 1;2577 const x = 1;
...@@ -2647,8 +2580,9 @@ test "basic math" {...@@ -2647,8 +2580,9 @@ test "basic math" {
2647 unreachable;2580 unreachable;
2648 }2581 }
2649}2582}
26502583 {#code_end#}
2651// in fact, this is how assert is implemented:2584 <p>In fact, this is how assert is implemented:</p>
2585 {#code_begin|test_err#}
2652fn assert(ok: bool) {2586fn assert(ok: bool) {
2653 if (!ok) unreachable; // assertion failure2587 if (!ok) unreachable; // assertion failure
2654}2588}
...@@ -2656,47 +2590,24 @@ fn assert(ok: bool) {...@@ -2656,47 +2590,24 @@ fn assert(ok: bool) {
2656// This test will fail because we hit unreachable.2590// This test will fail because we hit unreachable.
2657test "this will fail" {2591test "this will fail" {
2658 assert(false);2592 assert(false);
2659}</code></pre>2593}
2660 <pre><code class="sh">$ zig test test.zig2594 {#code_end#}
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>
2684 {#header_close#}2595 {#header_close#}
2685 {#header_open|At Compile-Time#}2596 {#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 {2600test "type of unreachable" {
2689 // The type of unreachable is noreturn.2601 comptime {
2602 // The type of unreachable is noreturn.
26902603
2691 // However this assertion will still fail because2604 // However this assertion will still fail because
2692 // evaluating unreachable at compile-time is a compile error.2605 // evaluating unreachable at compile-time is a compile error.
26932606
2694 assert(@typeOf(unreachable) == noreturn);2607 assert(@typeOf(unreachable) == noreturn);
2695}</code></pre>2608 }
2696 <pre><code class="sh">$ zig build-obj test.zig2609}
2697test.zig:9:12: error: unreachable code2610 {#code_end#}
2698 assert(@typeOf(unreachable) == noreturn);
2699 ^</code></pre>
2700 {#see_also|Zig Test|Build Mode|comptime#}2611 {#see_also|Zig Test|Build Mode|comptime#}
2701 {#header_close#}2612 {#header_close#}
2702 {#header_close#}2613 {#header_close#}
...@@ -2715,31 +2626,38 @@ test.zig:9:12: error: unreachable code...@@ -2715,31 +2626,38 @@ test.zig:9:12: error: unreachable code
2715 <p>When resolving types together, such as <code>if</code> clauses or <code>switch</code> prongs,2626 <p>When resolving types together, such as <code>if</code> clauses or <code>switch</code> prongs,
2716 the <code>noreturn</code> type is compatible with every other type. Consider:2627 the <code>noreturn</code> type is compatible with every other type. Consider:
2717 </p>2628 </p>
2718 <pre><code class="zig">fn foo(condition: bool, b: u32) {2629 {#code_begin|test#}
2630fn foo(condition: bool, b: u32) {
2719 const a = if (condition) b else return;2631 const a = if (condition) b else return;
2720 bar(a);2632 @panic("do something with a");
2721}2633}
27222634test "noreturn" {
2723extern fn bar(value: u32);</code></pre>2635 foo(false, 1);
2636}
2637 {#code_end#}
2724 <p>Another use case for <code>noreturn</code> is the <code>exit</code> function:</p>2638 <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" {
2728 const value = bar() catch ExitProcess(1);2644 const value = bar() catch ExitProcess(1);
2729 assert(value == 1234);2645 assert(value == 1234);
2730}2646}
27312647
2732fn bar() -&gt; %u32 {2648fn bar() -> %u32 {
2733 return 1234;2649 return 1234;
2734}2650}
27352651
2736const assert = @import("std").debug.assert;</code></pre>2652const assert = @import("std").debug.assert;
2653 {#code_end#}
2737 {#header_close#}2654 {#header_close#}
2738 {#header_open|Functions#}2655 {#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
2741// Functions are declared like this2659// Functions are declared like this
2742fn add(a: i8, b: i8) -&gt; i8 {2660fn add(a: i8, b: i8) -> i8 {
2743 if (a == 0) {2661 if (a == 0) {
2744 // You can still return manually if needed.2662 // You can still return manually if needed.
2745 return b;2663 return b;
...@@ -2750,84 +2668,83 @@ fn add(a: i8, b: i8) -&gt; i8 {...@@ -2750,84 +2668,83 @@ fn add(a: i8, b: i8) -&gt; i8 {
27502668
2751// The export specifier makes a function externally visible in the generated2669// The export specifier makes a function externally visible in the generated
2752// object file, and makes it use the C ABI.2670// 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
2755// The extern specifier is used to declare a function that will be resolved2673// The extern specifier is used to declare a function that will be resolved
2756// at link time, when linking statically, or at runtime, when linking2674// at link time, when linking statically, or at runtime, when linking
2757// dynamically.2675// dynamically.
2758// The stdcallcc specifier changes the calling convention of the function.2676// The stdcallcc specifier changes the calling convention of the function.
2759extern "kernel32" stdcallcc fn ExitProcess(exit_code: u32) -&gt; noreturn;2677extern "kernel32" stdcallcc fn ExitProcess(exit_code: u32) -> noreturn;
2760extern "c" fn atan2(a: f64, b: f64) -&gt; f64;2678extern "c" fn atan2(a: f64, b: f64) -> f64;
27612679
2762// coldcc makes a function use the cold calling convention.2680// coldcc makes a function use the cold calling convention.
2763coldcc fn abort() -&gt; noreturn {2681coldcc fn abort() -> noreturn {
2764 while (true) {}2682 while (true) {}
2765}2683}
27662684
2767// nakedcc makes a function not have any function prologue or epilogue.2685// nakedcc makes a function not have any function prologue or epilogue.
2768// This can be useful when integrating with assembly.2686// This can be useful when integrating with assembly.
2769nakedcc fn _start() -&gt; noreturn {2687nakedcc fn _start() -> noreturn {
2770 abort();2688 abort();
2771}2689}
27722690
2773// The pub specifier allows the function to be visible when importing.2691// The pub specifier allows the function to be visible when importing.
2774// Another file can use @import and call sub22692// 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
2777// Functions can be used as values and are equivalent to pointers.2695// Functions can be used as values and are equivalent to pointers.
2778const call2_op = fn (a: i8, b: i8) -&gt; i8;2696const call2_op = fn (a: i8, b: i8) -> i8;
2779fn do_op(fn_call: call2_op, op1: i8, op2: i8) -&gt; i8 {2697fn do_op(fn_call: call2_op, op1: i8, op2: i8) -> i8 {
2780 fn_call(op1, op2)2698 return fn_call(op1, op2);
2781}2699}
27822700
2783test "function" {2701test "function" {
2784 assert(do_op(add, 5, 6) == 11);2702 assert(do_op(add, 5, 6) == 11);
2785 assert(do_op(sub2, 5, 6) == -1);2703 assert(do_op(sub2, 5, 6) == -1);
2786}</code></pre>2704}
2787 <pre><code class="sh">$ zig test function.zig2705 {#code_end#}
2788Test 1/1 function...OK
2789</code></pre>
2790 <p>Function values are like pointers:</p>2706 <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
2793comptime {2710comptime {
2794 assert(@typeOf(foo) == fn());2711 assert(@typeOf(foo) == fn());
2795 assert(@sizeOf(fn()) == @sizeOf(?fn()));2712 assert(@sizeOf(fn()) == @sizeOf(?fn()));
2796}2713}
27972714
2798fn foo() { }</code></pre>2715fn foo() { }
2799 <pre><code class="sh">$ zig build-obj test.zig</code></pre>2716 {#code_end#}
2800 {#header_open|Pass-by-value Parameters#}2717 {#header_open|Pass-by-value Parameters#}
2801 <p>2718 <p>
2802 In Zig, structs, unions, and enums with payloads cannot be passed by value2719 In Zig, structs, unions, and enums with payloads cannot be passed by value
2803 to a function.2720 to a function.
2804 </p>2721 </p>
2805 <pre><code class="zig">const Foo = struct {2722 {#code_begin|test_err|not copyable; cannot pass by value#}
2723const Foo = struct {
2806 x: i32,2724 x: i32,
2807};2725};
28082726
2809fn bar(foo: Foo) {}2727fn bar(foo: Foo) {}
28102728
2811export fn entry() {2729test "pass aggregate type by value to function" {
2812 bar(Foo {.x = 12,});2730 bar(Foo {.x = 12,});
2813}</code></pre>2731}
2814 <pre><code class="sh">$ ./zig build-obj test.zig 2732 {#code_end#}
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>
2818 <p>2733 <p>
2819 Instead, one must use <code>&amp;const</code>. Zig allows implicitly casting something2734 Instead, one must use <code>&amp;const</code>. Zig allows implicitly casting something
2820 to a const pointer to it:2735 to a const pointer to it:
2821 </p>2736 </p>
2822 <pre><code class="zig">const Foo = struct {2737 {#code_begin|test#}
2738const Foo = struct {
2823 x: i32,2739 x: i32,
2824};2740};
28252741
2826fn bar(foo: &amp;const Foo) {}2742fn bar(foo: &const Foo) {}
28272743
2828export fn entry() {2744test "implicitly cast to const pointer" {
2829 bar(Foo {.x = 12,});2745 bar(Foo {.x = 12,});
2830}</code></pre>2746}
2747 {#code_end#}
2831 <p>2748 <p>
2832 However,2749 However,
2833 the C ABI does allow passing structs and unions by value. So functions which2750 the C ABI does allow passing structs and unions by value. So functions which
...@@ -2842,9 +2759,11 @@ export fn entry() {...@@ -2842,9 +2759,11 @@ export fn entry() {
2842 <p>2759 <p>
2843 Among the top level declarations available is the error value declaration:2760 Among the top level declarations available is the error value declaration:
2844 </p>2761 </p>
2845 <pre><code class="zig">error FileNotFound;2762 {#code_begin|syntax#}
2763error FileNotFound;
2846error OutOfMemory;2764error OutOfMemory;
2847error UnexpectedToken;</code></pre>2765error UnexpectedToken;
2766 {#code_end#}
2848 <p>2767 <p>
2849 These error values are assigned an unsigned integer value greater than 0 at2768 These error values are assigned an unsigned integer value greater than 0 at
2850 compile time. You are allowed to declare the same error value more than once,2769 compile time. You are allowed to declare the same error value more than once,
...@@ -2862,7 +2781,7 @@ error UnexpectedToken;</code></pre>...@@ -2862,7 +2781,7 @@ error UnexpectedToken;</code></pre>
2862 The pure error type is one of the error values, and in the same way that pointers2781 The pure error type is one of the error values, and in the same way that pointers
2863 cannot be null, a pure error is always an error.2782 cannot be null, a pure error is always an error.
2864 </p>2783 </p>
2865 <pre><code class="zig">const pure_error = error.FileNotFound;</code></pre>2784 {#code_begin|syntax#}const pure_error = error.FileNotFound;{#code_end#}
2866 <p>2785 <p>
2867 Most of the time you will not find yourself using a pure error type. Instead,2786 Most of the time you will not find yourself using a pure error type. Instead,
2868 likely you will be using the error union type. This is when you take a normal type,2787 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>...@@ -2871,32 +2790,48 @@ error UnexpectedToken;</code></pre>
2871 <p>2790 <p>
2872 Here is a function to parse a string into a 64-bit integer:2791 Here is a function to parse a string into a 64-bit integer:
2873 </p>2792 </p>
2874 <pre><code class="zig">error InvalidChar;2793 {#code_begin|test#}
2794error InvalidChar;
2875error Overflow;2795error Overflow;
28762796
2877pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {2797pub fn parseU64(buf: []const u8, radix: u8) -> %u64 {
2878 var x: u64 = 0;2798 var x: u64 = 0;
28792799
2880 for (buf) |c| {2800 for (buf) |c| {
2881 const digit = charToDigit(c);2801 const digit = charToDigit(c);
28822802
2883 if (digit &gt;= radix) {2803 if (digit >= radix) {
2884 return error.InvalidChar;2804 return error.InvalidChar;
2885 }2805 }
28862806
2887 // x *= radix2807 // x *= radix
2888 if (@mulWithOverflow(u64, x, radix, &amp;x)) {2808 if (@mulWithOverflow(u64, x, radix, &x)) {
2889 return error.Overflow;2809 return error.Overflow;
2890 }2810 }
28912811
2892 // x += digit2812 // x += digit
2893 if (@addWithOverflow(u64, x, digit, &amp;x)) {2813 if (@addWithOverflow(u64, x, digit, &x)) {
2894 return error.Overflow;2814 return error.Overflow;
2895 }2815 }
2896 }2816 }
28972817
2898 return x;2818 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#}
2900 <p>2835 <p>
2901 Notice the return type is <code>%u64</code>. This means that the function2836 Notice the return type is <code>%u64</code>. This means that the function
2902 either returns an unsigned 64 bit integer, or an error.2837 either returns an unsigned 64 bit integer, or an error.
...@@ -2916,29 +2851,35 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {...@@ -2916,29 +2851,35 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
2916 <li>You know with complete certainty it will not return an error, so want to unconditionally unwrap it.</li>2851 <li>You know with complete certainty it will not return an error, so want to unconditionally unwrap it.</li>
2917 <li>You want to take a different action for each possible error.</li>2852 <li>You want to take a different action for each possible error.</li>
2918 </ul>2853 </ul>
2919 <p>If you want to provide a default value, you can use the <code>%%</code> binary operator:</p>2854 <p>If you want to provide a default value, you can use the <code>catch</code> binary operator:</p>
2920 <pre><code class="zig">fn doAThing(str: []u8) {2855 {#code_begin|syntax#}
2856fn doAThing(str: []u8) {
2921 const number = parseU64(str, 10) catch 13;2857 const number = parseU64(str, 10) catch 13;
2922 // ...2858 // ...
2923}</code></pre>2859}
2860 {#code_end#}
2924 <p>2861 <p>
2925 In this code, <code>number</code> will be equal to the successfully parsed string, or2862 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 must2863 a default value of 13. The type of the right hand side of the binary <code>catch</code> operator must
2927 match the unwrapped error union type, or be of type <code>noreturn</code>.2864 match the unwrapped error union type, or be of type <code>noreturn</code>.
2928 </p>2865 </p>
2929 <p>Let's say you wanted to return the error if you got one, otherwise continue with the2866 <p>Let's say you wanted to return the error if you got one, otherwise continue with the
2930 function logic:</p>2867 function logic:</p>
2931 <pre><code class="zig">fn doAThing(str: []u8) -&gt; %void {2868 {#code_begin|syntax#}
2869fn doAThing(str: []u8) -> %void {
2932 const number = parseU64(str, 10) catch |err| return err;2870 const number = parseU64(str, 10) catch |err| return err;
2933 // ...2871 // ...
2934}</code></pre>2872}
2873 {#code_end#}
2935 <p>2874 <p>
2936 There is a shortcut for this. The <code>try</code> expression:2875 There is a shortcut for this. The <code>try</code> expression:
2937 </p>2876 </p>
2938 <pre><code class="zig">fn doAThing(str: []u8) -&gt; %void {2877 {#code_begin|syntax#}
2878fn doAThing(str: []u8) -> %void {
2939 const number = try parseU64(str, 10);2879 const number = try parseU64(str, 10);
2940 // ...2880 // ...
2941}</code></pre>2881}
2882 {#code_end#}
2942 <p>2883 <p>
2943 <code>try</code> evaluates an error union expression. If it is an error, it returns2884 <code>try</code> evaluates an error union expression. If it is an error, it returns
2944 from the current function with the same error. Otherwise, the expression results in2885 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 {...@@ -2948,35 +2889,32 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
2948 Maybe you know with complete certainty that an expression will never be an error.2889 Maybe you know with complete certainty that an expression will never be an error.
2949 In this case you can do this:2890 In this case you can do this:
2950 </p>2891 </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#}
2952 <p>2893 <p>
2953 Here we know for sure that "1234" will parse successfully. So we put the2894 Here we know for sure that "1234" will parse successfully. So we put the
2954 <code>unreachable</code> value on the right hand side. <code>unreachable</code> generates2895 <code>unreachable</code> value on the right hand side. <code>unreachable</code> generates
2955 a panic in Debug and ReleaseSafe modes and undefined behavior in ReleaseFast mode. So, while we're debugging the2896 a panic in Debug and ReleaseSafe modes and undefined behavior in ReleaseFast mode. So, while we're debugging the
2956 application, if there <em>was</em> a surprise error here, the application would crash2897 application, if there <em>was</em> a surprise error here, the application would crash
2957 appropriately.2898 appropriately.
2958 </p>2899 TODO: mention error return traces
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.
2964 </p>2900 </p>
2965 <p>2901 <p>
2966 Finally, you may want to take a different action for every situation. For that, we combine2902 Finally, you may want to take a different action for every situation. For that, we combine
2967 the <code>if</code> and <code>switch</code> expression:2903 the <code>if</code> and <code>switch</code> expression:
2968 </p>2904 </p>
2969 <pre><code class="zig">fn doAThing(str: []u8) {2905 {#code_begin|syntax#}
2906fn doAThing(str: []u8) {
2970 if (parseU64(str, 10)) |number| {2907 if (parseU64(str, 10)) |number| {
2971 doSomethingWithNumber(number);2908 doSomethingWithNumber(number);
2972 } else |err| switch (err) {2909 } else |err| switch (err) {
2973 error.Overflow =&gt; {2910 error.Overflow => {
2974 // handle overflow...2911 // handle overflow...
2975 },2912 },
2976 // we promise that InvalidChar won't happen (or crash in debug mode if it does)2913 // we promise that InvalidChar won't happen (or crash in debug mode if it does)
2977 error.InvalidChar =&gt; unreachable,2914 error.InvalidChar => unreachable,
2978 }2915 }
2979}</code></pre>2916}
2917 {#code_end#}
2980 <p>2918 <p>
2981 The other component to error handling is defer statements.2919 The other component to error handling is defer statements.
2982 In addition to an unconditional <code>defer</code>, Zig has <code>%defer</code>,2920 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 {...@@ -2986,7 +2924,8 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
2986 <p>2924 <p>
2987 Example:2925 Example:
2988 </p>2926 </p>
2989 <pre><code class="zig">fn createFoo(param: i32) -&gt; %Foo {2927 {#code_begin|syntax#}
2928fn createFoo(param: i32) -> %Foo {
2990 const foo = try tryToAllocateFoo();2929 const foo = try tryToAllocateFoo();
2991 // now we have allocated foo. we need to free it if the function fails.2930 // now we have allocated foo. we need to free it if the function fails.
2992 // but we want to return it if the function succeeds.2931 // but we want to return it if the function succeeds.
...@@ -2997,12 +2936,13 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {...@@ -2997,12 +2936,13 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
2997 // before this block leaves scope2936 // before this block leaves scope
2998 defer deallocateTmpBuffer(tmp_buf);2937 defer deallocateTmpBuffer(tmp_buf);
29992938
3000 if (param &gt; 1337) return error.InvalidParam;2939 if (param > 1337) return error.InvalidParam;
30012940
3002 // here the %defer will not run since we're returning success from the function.2941 // here the %defer will not run since we're returning success from the function.
3003 // but the defer will run!2942 // but the defer will run!
3004 return foo;2943 return foo;
3005}</code></pre>2944}
2945 {#code_end#}
3006 <p>2946 <p>
3007 The neat thing about this is that you get robust error handling without2947 The neat thing about this is that you get robust error handling without
3008 the verbosity and cognitive overhead of trying to make sure every exit path2948 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 {...@@ -3014,7 +2954,7 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
3014 <ul>2954 <ul>
3015 <li>These primitives give enough expressiveness that it's completely practical2955 <li>These primitives give enough expressiveness that it's completely practical
3016 to have failing to check for an error be a compile error. If you really want2956 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 and2957 to ignore the error, you can add <code>catch unreachable</code> and
3018 get the added benefit of crashing in Debug and ReleaseSafe modes if your assumption was wrong.2958 get the added benefit of crashing in Debug and ReleaseSafe modes if your assumption was wrong.
3019 </li>2959 </li>
3020 <li>2960 <li>
...@@ -3034,11 +2974,13 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {...@@ -3034,11 +2974,13 @@ pub fn parseU64(buf: []const u8, radix: u8) -&gt; %u64 {
3034 The question mark symbolizes the nullable type. You can convert a type to a nullable2974 The question mark symbolizes the nullable type. You can convert a type to a nullable
3035 type by putting a question mark in front of it, like this:2975 type by putting a question mark in front of it, like this:
3036 </p>2976 </p>
3037 <pre><code class="zig">// normal integer2977 {#code_begin|syntax#}
2978// normal integer
3038const normal_int: i32 = 1234;2979const normal_int: i32 = 1234;
30392980
3040// nullable integer2981// nullable integer
3041const nullable_int: ?i32 = 5678;</code></pre>2982const nullable_int: ?i32 = 5678;
2983 {#code_end#}
3042 <p>2984 <p>
3043 Now the variable <code>nullable_int</code> could be an <code>i32</code>, or <code>null</code>.2985 Now the variable <code>nullable_int</code> could be an <code>i32</code>, or <code>null</code>.
3044 </p>2986 </p>
...@@ -3061,7 +3003,7 @@ const nullable_int: ?i32 = 5678;</code></pre>...@@ -3061,7 +3003,7 @@ const nullable_int: ?i32 = 5678;</code></pre>
3061 Task: call malloc, if the result is null, return null.3003 Task: call malloc, if the result is null, return null.
3062 </p>3004 </p>
3063 <p>C code</p>3005 <p>C code</p>
3064 <pre><code class="c">// malloc prototype included for reference3006 <pre><code class="cpp">// malloc prototype included for reference
3065void *malloc(size_t size);3007void *malloc(size_t size);
30663008
3067struct Foo *do_a_thing(void) {3009struct Foo *do_a_thing(void) {
...@@ -3070,23 +3012,25 @@ struct Foo *do_a_thing(void) {...@@ -3070,23 +3012,25 @@ struct Foo *do_a_thing(void) {
3070 // ...3012 // ...
3071}</code></pre>3013}</code></pre>
3072 <p>Zig code</p>3014 <p>Zig code</p>
3073 <pre><code class="zig">// malloc prototype included for reference3015 {#code_begin|syntax#}
3074extern fn malloc(size: size_t) -&gt; ?&amp;u8;3016// malloc prototype included for reference
3017extern fn malloc(size: size_t) -> ?&u8;
30753018
3076fn doAThing() -&gt; ?&amp;Foo {3019fn doAThing() -> ?&Foo {
3077 const ptr = malloc(1234) ?? return null;3020 const ptr = malloc(1234) ?? return null;
3078 // ...3021 // ...
3079}</code></pre>3022}
3023 {#code_end#}
3080 <p>3024 <p>
3081 Here, Zig is at least as convenient, if not more, than C. And, the type of "ptr"3025 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> operator3026 is <code>&u8</code> <em>not</em> <code>?&u8</code>. The <code>??</code> operator
3083 unwrapped the nullable type and therefore <code>ptr</code> is guaranteed to be non-null everywhere3027 unwrapped the nullable type and therefore <code>ptr</code> is guaranteed to be non-null everywhere
3084 it is used in the function.3028 it is used in the function.
3085 </p>3029 </p>
3086 <p>3030 <p>
3087 The other form of checking against NULL you might see looks like this:3031 The other form of checking against NULL you might see looks like this:
3088 </p>3032 </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) {
3090 // do some stuff3034 // do some stuff
30913035
3092 if (foo) {3036 if (foo) {
...@@ -3098,7 +3042,8 @@ fn doAThing() -&gt; ?&amp;Foo {...@@ -3098,7 +3042,8 @@ fn doAThing() -&gt; ?&amp;Foo {
3098 <p>3042 <p>
3099 In Zig you can accomplish the same thing:3043 In Zig you can accomplish the same thing:
3100 </p>3044 </p>
3101 <pre><code class="zig">fn doAThing(nullable_foo: ?&amp;Foo) {3045 {#code_begin|syntax#}
3046fn doAThing(nullable_foo: ?&Foo) {
3102 // do some stuff3047 // do some stuff
31033048
3104 if (nullable_foo) |foo| {3049 if (nullable_foo) |foo| {
...@@ -3106,7 +3051,8 @@ fn doAThing() -&gt; ?&amp;Foo {...@@ -3106,7 +3051,8 @@ fn doAThing() -&gt; ?&amp;Foo {
3106 }3051 }
31073052
3108 // do some stuff3053 // do some stuff
3109}</code></pre>3054}
3055 {#code_end#}
3110 <p>3056 <p>
3111 Once again, the notable thing here is that inside the if block,3057 Once again, the notable thing here is that inside the if block,
3112 <code>foo</code> is no longer a nullable pointer, it is a pointer, which3058 <code>foo</code> is no longer a nullable pointer, it is a pointer, which
...@@ -3153,15 +3099,17 @@ fn doAThing() -&gt; ?&amp;Foo {...@@ -3153,15 +3099,17 @@ fn doAThing() -&gt; ?&amp;Foo {
3153 <p>3099 <p>
3154 Compile-time parameters is how Zig implements generics. It is compile-time duck typing.3100 Compile-time parameters is how Zig implements generics. It is compile-time duck typing.
3155 </p>3101 </p>
3156 <pre><code class="zig">fn max(comptime T: type, a: T, b: T) -&gt; T {3102 {#code_begin|syntax#}
3157 if (a &gt; b) a else b3103fn max(comptime T: type, a: T, b: T) -> T {
3104 return if (a > b) a else b;
3158}3105}
3159fn gimmeTheBiggerFloat(a: f32, b: f32) -&gt; f32 {3106fn gimmeTheBiggerFloat(a: f32, b: f32) -> f32 {
3160 max(f32, a, b)3107 return max(f32, a, b);
3161}3108}
3162fn gimmeTheBiggerInteger(a: u64, b: u64) -&gt; u64 {3109fn gimmeTheBiggerInteger(a: u64, b: u64) -> u64 {
3163 max(u64, a, b)3110 return max(u64, a, b);
3164}</code></pre>3111}
3112 {#code_end#}
3165 <p>3113 <p>
3166 In Zig, types are first-class citizens. They can be assigned to variables, passed as parameters to functions,3114 In Zig, types are first-class citizens. They can be assigned to variables, passed as parameters to functions,
3167 and returned from functions. However, they can only be used in expressions which are known at <em>compile-time</em>,3115 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 {...@@ -3179,21 +3127,20 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) -&gt; u64 {
3179 <p>3127 <p>
3180 For example, if we were to introduce another function to the above snippet:3128 For example, if we were to introduce another function to the above snippet:
3181 </p>3129 </p>
3182 <pre><code class="zig">fn max(comptime T: type, a: T, b: T) -&gt; T {3130 {#code_begin|test_err|unable to evaluate constant expression#}
3183 if (a &gt; b) a else b3131fn max(comptime T: type, a: T, b: T) -> T {
3132 return if (a > b) a else b;
3184}3133}
3185fn letsTryToPassARuntimeType(condition: bool) {3134test "try to pass a runtime type" {
3135 foo(false);
3136}
3137fn foo(condition: bool) {
3186 const result = max(3138 const result = max(
3187 if (condition) f32 else u64,3139 if (condition) f32 else u64,
3188 1234,3140 1234,
3189 5678);3141 5678);
3190}</code></pre>3142}
3191 <p>3143 {#code_end#}
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>
3197 <p>3144 <p>
3198 This is an error because the programmer attempted to pass a value only known at run-time3145 This is an error because the programmer attempted to pass a value only known at run-time
3199 to a function which expects a value known at compile-time.3146 to a function which expects a value known at compile-time.
...@@ -3205,38 +3152,33 @@ fn letsTryToPassARuntimeType(condition: bool) {...@@ -3205,38 +3152,33 @@ fn letsTryToPassARuntimeType(condition: bool) {
3205 <p>3152 <p>
3206 For example:3153 For example:
3207 </p>3154 </p>
3208 <pre><code class="zig">fn max(comptime T: type, a: T, b: T) -&gt; T {3155 {#code_begin|test_err|operator not allowed for type 'bool'#}
3209 if (a &gt; b) a else b3156fn max(comptime T: type, a: T, b: T) -> T {
3157 return if (a > b) a else b;
3210}3158}
3211fn letsTryToCompareBools(a: bool, b: bool) -&gt; bool {3159test "try to compare bools" {
3212 max(bool, a, b)3160 _ = max(bool, true, false);
3213}</code></pre>3161}
3214 <p>3162 {#code_end#}
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>
3223 <p>3163 <p>
3224 On the flip side, inside the function definition with the <code>comptime</code> parameter, the3164 On the flip side, inside the function definition with the <code>comptime</code> parameter, the
3225 value is known at compile-time. This means that we actually could make this work for the bool type3165 value is known at compile-time. This means that we actually could make this work for the bool type
3226 if we wanted to:3166 if we wanted to:
3227 </p>3167 </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 {
3229 if (T == bool) {3170 if (T == bool) {
3230 return a or b;3171 return a or b;
3231 } else if (a &gt; b) {3172 } else if (a > b) {
3232 return a;3173 return a;
3233 } else {3174 } else {
3234 return b;3175 return b;
3235 }3176 }
3236}3177}
3237fn letsTryToCompareBools(a: bool, b: bool) -&gt; bool {3178test "try to compare bools" {
3238 max(bool, a, b)3179 @import("std").debug.assert(max(bool, false, true) == true);
3239}</code></pre>3180}
3181 {#code_end#}
3240 <p>3182 <p>
3241 This works because Zig implicitly inlines <code>if</code> expressions when the condition3183 This works because Zig implicitly inlines <code>if</code> expressions when the condition
3242 is known at compile-time, and the compiler guarantees that it will skip analysis of3184 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 {...@@ -3246,9 +3188,11 @@ fn letsTryToCompareBools(a: bool, b: bool) -&gt; bool {
3246 This means that the actual function generated for <code>max</code> in this situation looks like3188 This means that the actual function generated for <code>max</code> in this situation looks like
3247 this:3189 this:
3248 </p>3190 </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 {
3250 return a or b;3193 return a or b;
3251}</code></pre>3194}
3195 {#code_end#}
3252 <p>3196 <p>
3253 All the code that dealt with compile-time known values is eliminated and we are left with only3197 All the code that dealt with compile-time known values is eliminated and we are left with only
3254 the necessary run-time code to accomplish the task.3198 the necessary run-time code to accomplish the task.
...@@ -3271,11 +3215,12 @@ fn letsTryToCompareBools(a: bool, b: bool) -&gt; bool {...@@ -3271,11 +3215,12 @@ fn letsTryToCompareBools(a: bool, b: bool) -&gt; bool {
3271 <p>3215 <p>
3272 For example:3216 For example:
3273 </p>3217 </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
3276const CmdFn = struct {3221const CmdFn = struct {
3277 name: []const u8,3222 name: []const u8,
3278 func: fn(i32) -&gt; i32,3223 func: fn(i32) -> i32,
3279};3224};
32803225
3281const cmd_fns = []CmdFn{3226const cmd_fns = []CmdFn{
...@@ -3283,14 +3228,14 @@ const cmd_fns = []CmdFn{...@@ -3283,14 +3228,14 @@ const cmd_fns = []CmdFn{
3283 CmdFn {.name = "two", .func = two},3228 CmdFn {.name = "two", .func = two},
3284 CmdFn {.name = "three", .func = three},3229 CmdFn {.name = "three", .func = three},
3285};3230};
3286fn one(value: i32) -&gt; i32 { value + 1 }3231fn one(value: i32) -> i32 { return value + 1; }
3287fn two(value: i32) -&gt; i32 { value + 2 }3232fn two(value: i32) -> i32 { return value + 2; }
3288fn three(value: i32) -&gt; i32 { value + 3 }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 {
3291 var result: i32 = start_value;3236 var result: i32 = start_value;
3292 comptime var i = 0;3237 comptime var i = 0;
3293 inline while (i &lt; cmd_fns.len) : (i += 1) {3238 inline while (i < cmd_fns.len) : (i += 1) {
3294 if (cmd_fns[i].name[0] == prefix_char) {3239 if (cmd_fns[i].name[0] == prefix_char) {
3295 result = cmd_fns[i].func(result);3240 result = cmd_fns[i].func(result);
3296 }3241 }
...@@ -3302,37 +3247,42 @@ test "perform fn" {...@@ -3302,37 +3247,42 @@ test "perform fn" {
3302 assert(performFn('t', 1) == 6);3247 assert(performFn('t', 1) == 6);
3303 assert(performFn('o', 0) == 1);3248 assert(performFn('o', 0) == 1);
3304 assert(performFn('w', 99) == 99);3249 assert(performFn('w', 99) == 99);
3305}</code></pre>3250}
3251 {#code_end#}
3306 <p>3252 <p>
3307 This example is a bit contrived, because the compile-time evaluation component is unnecessary;3253 This example is a bit contrived, because the compile-time evaluation component is unnecessary;
3308 this code would work fine if it was all done at run-time. But it does end up generating3254 this code would work fine if it was all done at run-time. But it does end up generating
3309 different code. In this example, the function <code>performFn</code> is generated three different times,3255 different code. In this example, the function <code>performFn</code> is generated three different times,
3310 for the different values of <code>prefix_char</code> provided:3256 for the different values of <code>prefix_char</code> provided:
3311 </p>3257 </p>
3312 <pre><code class="zig">// From the line:3258 {#code_begin|syntax#}
3259// From the line:
3313// assert(performFn('t', 1) == 6);3260// assert(performFn('t', 1) == 6);
3314fn performFn(start_value: i32) -&gt; i32 {3261fn performFn(start_value: i32) -> i32 {
3315 var result: i32 = start_value;3262 var result: i32 = start_value;
3316 result = two(result);3263 result = two(result);
3317 result = three(result);3264 result = three(result);
3318 return result;3265 return result;
3319}3266}
33203267 {#code_end#}
3268 {#code_begin|syntax#}
3321// From the line:3269// From the line:
3322// assert(performFn('o', 0) == 1);3270// assert(performFn('o', 0) == 1);
3323fn performFn(start_value: i32) -&gt; i32 {3271fn performFn(start_value: i32) -> i32 {
3324 var result: i32 = start_value;3272 var result: i32 = start_value;
3325 result = one(result);3273 result = one(result);
3326 return result;3274 return result;
3327}3275}
33283276 {#code_end#}
3277 {#code_begin|syntax#}
3329// From the line:3278// From the line:
3330// assert(performFn('w', 99) == 99);3279// assert(performFn('w', 99) == 99);
3331fn performFn(start_value: i32) -&gt; i32 {3280fn performFn(start_value: i32) -> i32 {
3332 var result: i32 = start_value;3281 var result: i32 = start_value;
3333 return result;3282 return result;
3334}</code></pre>3283}
3335 <p>3284 {#code_end#}
3285 <p>
3336 Note that this happens even in a debug build; in a release build these generated functions still3286 Note that this happens even in a debug build; in a release build these generated functions still
3337 pass through rigorous LLVM optimizations. The important thing to note, however, is not that this3287 pass through rigorous LLVM optimizations. The important thing to note, however, is not that this
3338 is a way to write more optimized code, but that it is a way to make sure that what <em>should</em> happen3288 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 {...@@ -3347,16 +3297,15 @@ fn performFn(start_value: i32) -&gt; i32 {
3347 use a <code>comptime</code> expression to guarantee that the expression will be evaluated at compile-time.3297 use a <code>comptime</code> expression to guarantee that the expression will be evaluated at compile-time.
3348 If this cannot be accomplished, the compiler will emit an error. For example:3298 If this cannot be accomplished, the compiler will emit an error. For example:
3349 </p>3299 </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" {
3353 comptime {3304 comptime {
3354 exit();3305 exit();
3355 }3306 }
3356}</code></pre>3307}
3357 <pre><code>./test.zig:5:9: error: unable to evaluate constant expression3308 {#code_end#}
3358 exit();
3359 ^</code></pre>
3360 <p>3309 <p>
3361 It doesn't make sense that a program could call <code>exit()</code> (or any other external function)3310 It doesn't make sense that a program could call <code>exit()</code> (or any other external function)
3362 at compile-time, so this is a compile error. However, a <code>comptime</code> expression does much3311 at compile-time, so this is a compile error. However, a <code>comptime</code> expression does much
...@@ -3379,10 +3328,11 @@ fn foo() {...@@ -3379,10 +3328,11 @@ fn foo() {
3379 <p>3328 <p>
3380 Let's look at an example:3329 Let's look at an example:
3381 </p>3330 </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 {3334fn fibonacci(index: u32) -> u32 {
3385 if (index &lt; 2) return index;3335 if (index < 2) return index;
3386 return fibonacci(index - 1) + fibonacci(index - 2);3336 return fibonacci(index - 1) + fibonacci(index - 2);
3387}3337}
33883338
...@@ -3394,16 +3344,16 @@ test "fibonacci" {...@@ -3394,16 +3344,16 @@ test "fibonacci" {
3394 comptime {3344 comptime {
3395 assert(fibonacci(7) == 13);3345 assert(fibonacci(7) == 13);
3396 }3346 }
3397}</code></pre>3347}
3398 <pre><code>$ zig test test.zig3348 {#code_end#}
3399Test 1/1 testFibonacci...OK</code></pre>
3400 <p>3349 <p>
3401 Imagine if we had forgotten the base case of the recursive function and tried to run the tests:3350 Imagine if we had forgotten the base case of the recursive function and tried to run the tests:
3402 </p>3351 </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 {3355fn fibonacci(index: u32) -> u32 {
3406 //if (index &lt; 2) return index;3356 //if (index < 2) return index;
3407 return fibonacci(index - 1) + fibonacci(index - 2);3357 return fibonacci(index - 1) + fibonacci(index - 2);
3408}3358}
34093359
...@@ -3411,35 +3361,8 @@ test "fibonacci" {...@@ -3411,35 +3361,8 @@ test "fibonacci" {
3411 comptime {3361 comptime {
3412 assert(fibonacci(7) == 13);3362 assert(fibonacci(7) == 13);
3413 }3363 }
3414}</code></pre>3364}
3415 <pre><code>$ zig test test.zig3365 {#code_end#}
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>
3443 <p>3366 <p>
3444 The compiler produces an error which is a stack trace from trying to evaluate the3367 The compiler produces an error which is a stack trace from trying to evaluate the
3445 function at compile-time.3368 function at compile-time.
...@@ -3449,10 +3372,11 @@ test "fibonacci" {...@@ -3449,10 +3372,11 @@ test "fibonacci" {
3449 undefined behavior, which is always a compile error if the compiler knows it happened.3372 undefined behavior, which is always a compile error if the compiler knows it happened.
3450 But what would have happened if we used a signed integer?3373 But what would have happened if we used a signed integer?
3451 </p>3374 </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 {3378fn fibonacci(index: i32) -> i32 {
3455 //if (index &lt; 2) return index;3379 //if (index < 2) return index;
3456 return fibonacci(index - 1) + fibonacci(index - 2);3380 return fibonacci(index - 1) + fibonacci(index - 2);
3457}3381}
34583382
...@@ -3460,43 +3384,8 @@ test "fibonacci" {...@@ -3460,43 +3384,8 @@ test "fibonacci" {
3460 comptime {3384 comptime {
3461 assert(fibonacci(7) == 13);3385 assert(fibonacci(7) == 13);
3462 }3386 }
3463}</code></pre>3387}
3464 <pre><code>./test.zig:3:21: error: evaluation exceeded 1000 backwards branches3388 {#code_end#}
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>
3500 <p>3389 <p>
3501 The compiler noticed that evaluating this function at compile-time took a long time,3390 The compiler noticed that evaluating this function at compile-time took a long time,
3502 and thus emitted a compile error and gave up. If the programmer wants to increase3391 and thus emitted a compile error and gave up. If the programmer wants to increase
...@@ -3506,15 +3395,20 @@ test "fibonacci" {...@@ -3506,15 +3395,20 @@ test "fibonacci" {
3506 <p>3395 <p>
3507 What if we fix the base case, but put the wrong value in the <code>assert</code> line?3396 What if we fix the base case, but put the wrong value in the <code>assert</code> line?
3508 </p>3397 </p>
3509 <pre><code class="zig">comptime {3398 {#code_begin|test_err|encountered @panic at compile-time#}
3510 assert(fibonacci(7) == 99999);3399const assert = @import("std").debug.assert;
3511}</code></pre>3400
3512 <pre><code>./test.zig:15:14: error: unable to evaluate constant expression3401fn fibonacci(index: i32) -> i32 {
3513 if (!ok) unreachable;3402 if (index < 2) return index;
3514 ^3403 return fibonacci(index - 1) + fibonacci(index - 2);
3515./test.zig:10:15: note: called from here3404}
3405
3406test "fibonacci" {
3407 comptime {
3516 assert(fibonacci(7) == 99999);3408 assert(fibonacci(7) == 99999);
3517 ^</code></pre>3409 }
3410}
3411 {#code_end#}
3518 <p>3412 <p>
3519 What happened is Zig started interpreting the <code>assert</code> function with the3413 What happened is Zig started interpreting the <code>assert</code> function with the
3520 parameter <code>ok</code> set to <code>false</code>. When the interpreter hit3414 parameter <code>ok</code> set to <code>false</code>. When the interpreter hit
...@@ -3528,17 +3422,18 @@ test "fibonacci" {...@@ -3528,17 +3422,18 @@ test "fibonacci" {
3528 <code>comptime</code> expressions. This means that we can use functions to3422 <code>comptime</code> expressions. This means that we can use functions to
3529 initialize complex static data. For example:3423 initialize complex static data. For example:
3530 </p>3424 </p>
3531 <pre><code class="zig">const first_25_primes = firstNPrimes(25);3425 {#code_begin|test#}
3426const first_25_primes = firstNPrimes(25);
3532const sum_of_first_25_primes = sum(first_25_primes);3427const 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 {
3535 var prime_list: [n]i32 = undefined;3430 var prime_list: [n]i32 = undefined;
3536 var next_index: usize = 0;3431 var next_index: usize = 0;
3537 var test_number: i32 = 2;3432 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) {
3539 var test_prime_index: usize = 0;3434 var test_prime_index: usize = 0;
3540 var is_prime = true;3435 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) {
3542 if (test_number % prime_list[test_prime_index] == 0) {3437 if (test_number % prime_list[test_prime_index] == 0) {
3543 is_prime = false;3438 is_prime = false;
3544 break;3439 break;
...@@ -3552,19 +3447,24 @@ fn firstNPrimes(comptime n: usize) -&gt; [n]i32 {...@@ -3552,19 +3447,24 @@ fn firstNPrimes(comptime n: usize) -&gt; [n]i32 {
3552 return prime_list;3447 return prime_list;
3553}3448}
35543449
3555fn sum(numbers: []i32) -&gt; i32 {3450fn sum(numbers: []const i32) -> i32 {
3556 var result: i32 = 0;3451 var result: i32 = 0;
3557 for (numbers) |x| {3452 for (numbers) |x| {
3558 result += x;3453 result += x;
3559 }3454 }
3560 return result;3455 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#}
3562 <p>3462 <p>
3563 When we compile this program, Zig generates the constants3463 When we compile this program, Zig generates the constants
3564 with the answer pre-computed. Here are the lines from the generated LLVM IR:3464 with the answer pre-computed. Here are the lines from the generated LLVM IR:
3565 </p>3465 </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]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]
3567 @1 = internal unnamed_addr constant i32 1060</code></pre>3467@1 = internal unnamed_addr constant i32 1060</code></pre>
3568 <p>3468 <p>
3569 Note that we did not have to do anything special with the syntax of these functions. For example,3469 Note that we did not have to do anything special with the syntax of these functions. For example,
3570 we could call the <code>sum</code> function as is with a slice of numbers whose length and values were3470 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 {...@@ -3582,12 +3482,14 @@ fn sum(numbers: []i32) -&gt; i32 {
3582 Here is an example of a generic <code>List</code> data structure, that we will instantiate with3482 Here is an example of a generic <code>List</code> data structure, that we will instantiate with
3583 the type <code>i32</code>. In Zig we refer to the type as <code>List(i32)</code>.3483 the type <code>i32</code>. In Zig we refer to the type as <code>List(i32)</code>.
3584 </p>3484 </p>
3585 <pre><code class="zig">fn List(comptime T: type) -&gt; type {3485 {#code_begin|syntax#}
3586 struct {3486fn List(comptime T: type) -> type {
3487 return struct {
3587 items: []T,3488 items: []T,
3588 len: usize,3489 len: usize,
3589 }3490 };
3590}</code></pre>3491}
3492 {#code_end#}
3591 <p>3493 <p>
3592 That's it. It's a function that returns an anonymous <code>struct</code>. For the purposes of error messages3494 That's it. It's a function that returns an anonymous <code>struct</code>. For the purposes of error messages
3593 and debugging, Zig infers the name <code>"List(i32)"</code> from the function name and parameters invoked when creating3495 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 {...@@ -3597,10 +3499,12 @@ fn sum(numbers: []i32) -&gt; i32 {
3597 To keep the language small and uniform, all aggregate types in Zig are anonymous. To give a type3499 To keep the language small and uniform, all aggregate types in Zig are anonymous. To give a type
3598 a name, we assign it to a constant:3500 a name, we assign it to a constant:
3599 </p>3501 </p>
3600 <pre><code class="zig">const Node = struct {3502 {#code_begin|syntax#}
3601 next: &amp;Node,3503const Node = struct {
3504 next: &Node,
3602 name: []u8,3505 name: []u8,
3603};</code></pre>3506};
3507 {#code_end#}
3604 <p>3508 <p>
3605 This works because all top level declarations are order-independent, and as long as there isn't3509 This works because all top level declarations are order-independent, and as long as there isn't
3606 an actual infinite regression, values can refer to themselves, directly or indirectly. In this case,3510 an actual infinite regression, values can refer to themselves, directly or indirectly. In this case,
...@@ -3627,8 +3531,9 @@ pub fn main() {...@@ -3627,8 +3531,9 @@ pub fn main() {
3627 Let's crack open the implementation of this and see how it works:3531 Let's crack open the implementation of this and see how it works:
3628 </p>3532 </p>
36293533
3630 <pre><code class="zig">/// Calls print and then flushes the buffer.3534 {#code_begin|syntax#}
3631pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt; %void {3535/// Calls print and then flushes the buffer.
3536pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) -> %void {
3632 const State = enum {3537 const State = enum {
3633 Start,3538 Start,
3634 OpenBrace,3539 OpenBrace,
...@@ -3641,36 +3546,36 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt...@@ -3641,36 +3546,36 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt
36413546
3642 inline for (format) |c, i| {3547 inline for (format) |c, i| {
3643 switch (state) {3548 switch (state) {
3644 State.Start =&gt; switch (c) {3549 State.Start => switch (c) {
3645 '{' =&gt; {3550 '{' => {
3646 if (start_index &lt; i) try self.write(format[start_index...i]);3551 if (start_index < i) try self.write(format[start_index..i]);
3647 state = State.OpenBrace;3552 state = State.OpenBrace;
3648 },3553 },
3649 '}' =&gt; {3554 '}' => {
3650 if (start_index &lt; i) try self.write(format[start_index...i]);3555 if (start_index < i) try self.write(format[start_index..i]);
3651 state = State.CloseBrace;3556 state = State.CloseBrace;
3652 },3557 },
3653 else =&gt; {},3558 else => {},
3654 },3559 },
3655 State.OpenBrace =&gt; switch (c) {3560 State.OpenBrace => switch (c) {
3656 '{' =&gt; {3561 '{' => {
3657 state = State.Start;3562 state = State.Start;
3658 start_index = i;3563 start_index = i;
3659 },3564 },
3660 '}' =&gt; {3565 '}' => {
3661 try self.printValue(args[next_arg]);3566 try self.printValue(args[next_arg]);
3662 next_arg += 1;3567 next_arg += 1;
3663 state = State.Start;3568 state = State.Start;
3664 start_index = i + 1;3569 start_index = i + 1;
3665 },3570 },
3666 else =&gt; @compileError("Unknown format character: " ++ c),3571 else => @compileError("Unknown format character: " ++ c),
3667 },3572 },
3668 State.CloseBrace =&gt; switch (c) {3573 State.CloseBrace => switch (c) {
3669 '}' =&gt; {3574 '}' => {
3670 state = State.Start;3575 state = State.Start;
3671 start_index = i;3576 start_index = i;
3672 },3577 },
3673 else =&gt; @compileError("Single '}' encountered in format string"),3578 else => @compileError("Single '}' encountered in format string"),
3674 },3579 },
3675 }3580 }
3676 }3581 }
...@@ -3682,11 +3587,12 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt...@@ -3682,11 +3587,12 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt
3682 @compileError("Incomplete format string: " ++ format);3587 @compileError("Incomplete format string: " ++ format);
3683 }3588 }
3684 }3589 }
3685 if (start_index &lt; format.len) {3590 if (start_index < format.len) {
3686 try self.write(format[start_index...format.len]);3591 try self.write(format[start_index..format.len]);
3687 }3592 }
3688 try self.flush();3593 try self.flush();
3689}</code></pre>3594}
3595 {#code_end#}
3690 <p>3596 <p>
3691 This is a proof of concept implementation; the actual function in the standard library has more3597 This is a proof of concept implementation; the actual function in the standard library has more
3692 formatting capabilities.3598 formatting capabilities.
...@@ -3698,19 +3604,22 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt...@@ -3698,19 +3604,22 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt
3698 When this function is analyzed from our example code above, Zig partially evaluates the function3604 When this function is analyzed from our example code above, Zig partially evaluates the function
3699 and emits a function that actually looks like this:3605 and emits a function that actually looks like this:
3700 </p>3606 </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 {
3702 try self.write("here is a string: '");3609 try self.write("here is a string: '");
3703 try self.printValue(arg0);3610 try self.printValue(arg0);
3704 try self.write("' here is a number: ");3611 try self.write("' here is a number: ");
3705 try self.printValue(arg1);3612 try self.printValue(arg1);
3706 try self.write("\n");3613 try self.write("\n");
3707 try self.flush();3614 try self.flush();
3708}</code></pre>3615}
3616 {#code_end#}
3709 <p>3617 <p>
3710 <code>printValue</code> is a function that takes a parameter of any type, and does different things depending3618 <code>printValue</code> is a function that takes a parameter of any type, and does different things depending
3711 on the type:3619 on the type:
3712 </p>3620 </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 {
3714 const T = @typeOf(value);3623 const T = @typeOf(value);
3715 if (@isInteger(T)) {3624 if (@isInteger(T)) {
3716 return self.printInt(T, value);3625 return self.printInt(T, value);
...@@ -3722,18 +3631,22 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt...@@ -3722,18 +3631,22 @@ pub fn printf(self: &amp;OutStream, comptime format: []const u8, args: ...) -&gt
3722 } else {3631 } else {
3723 @compileError("Unable to print type '" ++ @typeName(T) ++ "'");3632 @compileError("Unable to print type '" ++ @typeName(T) ++ "'");
3724 }3633 }
3725}</code></pre>3634}
3635 {#code_end#}
3726 <p>3636 <p>
3727 And now, what happens if we give too many arguments to <code>printf</code>?3637 And now, what happens if we give too many arguments to <code>printf</code>?
3728 </p>3638 </p>
3729 <pre><code class="zig">warn("here is a string: '{}' here is a number: {}\n",3639 {#code_begin|test_err|Unused arguments#}
3730 a_string, a_number, a_number);</code></pre>3640const warn = @import("std").debug.warn;
3731 <pre><code>.../std/io.zig:147:17: error: Unused arguments3641
3732 @compileError("Unused arguments");3642const a_number: i32 = 1234;
3733 ^3643const a_string = "foobar";
3734./test.zig:7:23: note: called from here3644
3735 warn("here is a number: {} and here is a string: {}\n",3645test "printf too many arguments" {
3736 ^</code></pre>3646 warn("here is a string: '{}' here is a number: {}\n",
3647 a_string, a_number, a_number);
3648}
3649 {#code_end#}
3737 <p>3650 <p>
3738 Zig gives programmers the tools needed to protect themselves against their own mistakes.3651 Zig gives programmers the tools needed to protect themselves against their own mistakes.
3739 </p>3652 </p>
...@@ -3786,7 +3699,7 @@ pub fn main() {...@@ -3786,7 +3699,7 @@ pub fn main() {
3786 at compile time.3699 at compile time.
3787 </p>3700 </p>
3788 {#header_open|@addWithOverflow#}3701 {#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>
3790 <p>3703 <p>
3791 Performs <code>*result = a + b</code>. If overflow or underflow occurs,3704 Performs <code>*result = a + b</code>. If overflow or underflow occurs,
3792 stores the overflowed bits in <code>result</code> and returns <code>true</code>.3705 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
...@@ -3849,7 +3762,7 @@ pub fn main() {...@@ -3849,7 +3762,7 @@ pub fn main() {
3849 </p>3762 </p>
3850 <pre><code class="zig">const assert = @import("std").debug.assert;3763 <pre><code class="zig">const assert = @import("std").debug.assert;
3851comptime {3764comptime {
3852 assert(&amp;u32 == &amp;align(@alignOf(u32)) u32);3765 assert(&u32 == &align(@alignOf(u32)) u32);
3853}</code></pre>3766}</code></pre>
3854 <p>3767 <p>
3855 The result is a target-specific compile time constant. It is guaranteed to be3768 The result is a target-specific compile time constant. It is guaranteed to be
...@@ -3933,7 +3846,7 @@ comptime {...@@ -3933,7 +3846,7 @@ comptime {
39333846
3934 {#header_close#}3847 {#header_close#}
3935 {#header_open|@cmpxchg#}3848 {#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>
3937 <p>3850 <p>
3938 This function performs an atomic compare exchange operation.3851 This function performs an atomic compare exchange operation.
3939 </p>3852 </p>
...@@ -3970,42 +3883,46 @@ comptime {...@@ -3970,42 +3883,46 @@ comptime {
3970 This function can be used to do "printf debugging" on3883 This function can be used to do "printf debugging" on
3971 compile-time executing code.3884 compile-time executing code.
3972 </p>3885 </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: {
3976 var val1: i32 = 99;3890 var val1: i32 = 99;
3977 @compileLog("comptime val1 = ", val1); 3891 @compileLog("comptime val1 = ", val1);
3978 val1 = val1 + 1;3892 val1 = val1 + 1;
3979 val13893 break :blk val1;
3980};3894};
39813895
3982pub fn main() -&gt; %void {3896test "main" {
3983 @compileLog("comptime in main"); 3897 @compileLog("comptime in main");
39843898
3985 warn("Runtime in main, num1 = {}.\n", num1);3899 warn("Runtime in main, num1 = {}.\n", num1);
3986}</code></pre>3900}
39873901 {#code_end#}
3988 </p>3902 </p>
3989 <p>3903 <p>
3990 will ouput:3904 will ouput:
3991 </p>3905 </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>
4002 <p>3906 <p>
4003 If all <code>@compileLog</code> calls are removed or 3907 If all <code>@compileLog</code> calls are removed or
4004 not encountered by analysis, the3908 not encountered by analysis, the
4005 program compiles successfully and the generated executable prints:3909 program compiles successfully and the generated executable prints:
4006 </p> 3910 </p>
4007<pre><code class="sh">Runtime in main, num1 = 100.</code></pre>3911 {#code_begin|test#}
4008{{@ctheader_open:z}}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#}
4009 <pre><code class="zig">@ctz(x: T) -&gt; U</code></pre>3926 <pre><code class="zig">@ctz(x: T) -&gt; U</code></pre>
4010 <p>3927 <p>
4011 This function counts the number of trailing zeroes in <code>x</code> which is an integer3928 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...@@ -4110,7 +4027,7 @@ test.zig:6:2: error: found compile log statement
4110 </p>4027 </p>
4111 {#header_close#}4028 {#header_close#}
4112 {#header_open|@errorReturnTrace#}4029 {#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>
4114 <p>4031 <p>
4115 If the binary is built with error return tracing, and this function is invoked in a4032 If the binary is built with error return tracing, and this function is invoked in a
4116 function that calls a function with an error or error union return type, returns a4033 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...@@ -4129,7 +4046,7 @@ test.zig:6:2: error: found compile log statement
4129 {#header_close#}4046 {#header_close#}
4130 {#header_open|@fieldParentPtr#}4047 {#header_open|@fieldParentPtr#}
4131 <pre><code class="zig">@fieldParentPtr(comptime ParentType: type, comptime field_name: []const u8,4048 <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>
4133 <p>4050 <p>
4134 Given a pointer to a field, returns the base pointer of a struct.4051 Given a pointer to a field, returns the base pointer of a struct.
4135 </p>4052 </p>
...@@ -4173,12 +4090,15 @@ test.zig:6:2: error: found compile log statement...@@ -4173,12 +4090,15 @@ test.zig:6:2: error: found compile log statement
4173 <p>4090 <p>
4174 This calls a function, in the same way that invoking an expression with parentheses does:4091 This calls a function, in the same way that invoking an expression with parentheses does:
4175 </p>4092 </p>
4176 <pre><code class="zig">const assert = @import("std").debug.assert;4093 {#code_begin|test#}
4094const assert = @import("std").debug.assert;
4095
4177test "inline function call" {4096test "inline function call" {
4178 assert(@inlineCall(add, 3, 9) == 12);4097 assert(@inlineCall(add, 3, 9) == 12);
4179}4098}
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#}
4182 <p>4102 <p>
4183 Unlike a normal function call, however, <code>@inlineCall</code> guarantees that the call4103 Unlike a normal function call, however, <code>@inlineCall</code> guarantees that the call
4184 will be inlined. If the call cannot be inlined, a compile error is emitted.4104 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>...@@ -4222,7 +4142,7 @@ fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
4222 <p>TODO</p>4142 <p>TODO</p>
4223 {#header_close#}4143 {#header_close#}
4224 {#header_open|@memcpy#}4144 {#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>
4226 <p>4146 <p>
4227 This function copies bytes from one region of memory to another. <code>dest</code> and4147 This function copies bytes from one region of memory to another. <code>dest</code> and
4228 <code>source</code> are both pointers and must not overlap.4148 <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>...@@ -4240,7 +4160,7 @@ fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
4240mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre>4160mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre>
4241 {#header_close#}4161 {#header_close#}
4242 {#header_open|@memset#}4162 {#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>
4244 <p>4164 <p>
4245 This function sets a region of memory to <code>c</code>. <code>dest</code> is a pointer.4165 This function sets a region of memory to <code>c</code>. <code>dest</code> is a pointer.
4246 </p>4166 </p>
...@@ -4279,7 +4199,7 @@ mem.set(u8, dest, c);</code></pre>...@@ -4279,7 +4199,7 @@ mem.set(u8, dest, c);</code></pre>
4279 {#see_also|@rem#}4199 {#see_also|@rem#}
4280 {#header_close#}4200 {#header_close#}
4281 {#header_open|@mulWithOverflow#}4201 {#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>
4283 <p>4203 <p>
4284 Performs <code>*result = a * b</code>. If overflow or underflow occurs,4204 Performs <code>*result = a * b</code>. If overflow or underflow occurs,
4285 stores the overflowed bits in <code>result</code> and returns <code>true</code>.4205 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>...@@ -4318,17 +4238,19 @@ fn add(a: i32, b: i32) -&gt; i32 { a + b }</code></pre>
4318 This is typically used for type safety when interacting with C code that does not expose struct details.4238 This is typically used for type safety when interacting with C code that does not expose struct details.
4319 Example:4239 Example:
4320 </p>4240 </p>
4321 <pre><code class="zig">const Derp = @OpaqueType();4241 {#code_begin|test_err|expected type '&Derp', found '&Wat'#}
4242const Derp = @OpaqueType();
4322const Wat = @OpaqueType();4243const Wat = @OpaqueType();
43234244
4324extern fn bar(d: &amp;Derp);4245extern fn bar(d: &Derp);
4325export fn foo(w: &amp;Wat) {4246export fn foo(w: &Wat) {
4326 bar(w);4247 bar(w);
4327}</code></pre>4248}
4328 <pre><code class="sh">$ ./zig build-obj test.zig4249
4329test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'4250test "call foo" {
4330 bar(w);4251 foo(undefined);
4331 ^</code></pre>4252}
4253 {#code_end#}
4332 {#header_close#}4254 {#header_close#}
4333 {#header_open|@panic#}4255 {#header_open|@panic#}
4334 <pre><code class="zig">@panic(message: []const u8) -&gt; noreturn</code></pre>4256 <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'...@@ -4413,22 +4335,24 @@ test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'
4413 <p>4335 <p>
4414 Example:4336 Example:
4415 </p>4337 </p>
4416 <pre><code class="zig">comptime {4338 {#code_begin|test_err|evaluation exceeded 1000 backwards branches#}
4417 var i = 0;4339test "foo" {
4418 while (i &lt; 1001) : (i += 1) {}4340 comptime {
4419}</code></pre>4341 var i = 0;
4420 <pre><code class="sh">$ ./zig build-obj test.zig4342 while (i < 1001) : (i += 1) {}
4421/home/andy/dev/zig/build/test.zig:3:5: error: evaluation exceeded 1000 backwards branches4343 }
4422 while (i &lt; 1001) : (i += 1) {}4344}
4423 ^</code></pre>4345 {#code_end#}
4424 <p>Now we use <code>@setEvalBranchQuota</code>:</p>4346 <p>Now we use <code class="zig">@setEvalBranchQuota</code>:</p>
4425 <pre><code class="zig">comptime {4347 {#code_begin|test#}
4426 @setEvalBranchQuota(1001);4348test "foo" {
4427 var i = 0;4349 comptime {
4428 while (i &lt; 1001) : (i += 1) {}4350 @setEvalBranchQuota(1001);
4429}</code></pre>4351 var i = 0;
4430 <pre><code class="sh">$ ./zig build-obj test.zig</code></pre>4352 while (i < 1001) : (i += 1) {}
4431 <p>(no output because it worked fine)</p>4353 }
4354}
4355 {#code_end#}
44324356
4433 {#see_also|comptime#}4357 {#see_also|comptime#}
4434 {#header_close#}4358 {#header_close#}
...@@ -4437,10 +4361,12 @@ test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'...@@ -4437,10 +4361,12 @@ test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'
4437 <p>4361 <p>
4438 Sets the floating point mode for a given scope. Possible values are:4362 Sets the floating point mode for a given scope. Possible values are:
4439 </p>4363 </p>
4440 <pre><code class="zig">pub const FloatMode = enum {4364 {#code_begin|syntax#}
4365pub const FloatMode = enum {
4441 Optimized,4366 Optimized,
4442 Strict,4367 Strict,
4443};</code></pre>4368};
4369 {#code_end#}
4444 <ul>4370 <ul>
4445 <li>4371 <li>
4446 <code>Optimized</code> (default) - Floating point operations may do all of the following:4372 <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'...@@ -4486,7 +4412,7 @@ test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'
4486 {#see_also|@shrExact|@shlWithOverflow#}4412 {#see_also|@shrExact|@shlWithOverflow#}
4487 {#header_close#}4413 {#header_close#}
4488 {#header_open|@shlWithOverflow#}4414 {#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>
4490 <p>4416 <p>
4491 Performs <code>*result = a &lt;&lt; b</code>. If overflow or underflow occurs,4417 Performs <code>*result = a &lt;&lt; b</code>. If overflow or underflow occurs,
4492 stores the overflowed bits in <code>result</code> and returns <code>true</code>.4418 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'...@@ -4520,7 +4446,7 @@ test.zig:5:9: error: expected type '&amp;Derp', found '&amp;Wat'
4520 </p>4446 </p>
4521 {#header_close#}4447 {#header_close#}
4522 {#header_open|@subWithOverflow#}4448 {#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>
4524 <p>4450 <p>
4525 Performs <code>*result = a - b</code>. If overflow or underflow occurs,4451 Performs <code>*result = a - b</code>. If overflow or underflow occurs,
4526 stores the overflowed bits in <code>result</code> and returns <code>true</code>.4452 stores the overflowed bits in <code>result</code> and returns <code>true</code>.
...@@ -4556,7 +4482,8 @@ const b: u8 = @truncate(u8, a);...@@ -4556,7 +4482,8 @@ const b: u8 = @truncate(u8, a);
4556 <p>4482 <p>
4557 Returns which kind of type something is. Possible values:4483 Returns which kind of type something is. Possible values:
4558 </p>4484 </p>
4559 <pre><code class="zig">pub const TypeId = enum {4485 {#code_begin|syntax#}
4486pub const TypeId = enum {
4560 Type,4487 Type,
4561 Void,4488 Void,
4562 Bool,4489 Bool,
...@@ -4574,7 +4501,6 @@ const b: u8 = @truncate(u8, a);...@@ -4574,7 +4501,6 @@ const b: u8 = @truncate(u8, a);
4574 ErrorUnion,4501 ErrorUnion,
4575 Error,4502 Error,
4576 Enum,4503 Enum,
4577 EnumTag,
4578 Union,4504 Union,
4579 Fn,4505 Fn,
4580 Namespace,4506 Namespace,
...@@ -4582,8 +4508,8 @@ const b: u8 = @truncate(u8, a);...@@ -4582,8 +4508,8 @@ const b: u8 = @truncate(u8, a);
4582 BoundFn,4508 BoundFn,
4583 ArgTuple,4509 ArgTuple,
4584 Opaque,4510 Opaque,
4585};</code></pre>4511};
45864512 {#code_end#}
4587 {#header_close#}4513 {#header_close#}
4588 {#header_open|@typeName#}4514 {#header_open|@typeName#}
4589 <pre><code class="zig">@typeName(T: type) -&gt; []u8</code></pre>4515 <pre><code class="zig">@typeName(T: type) -&gt; []u8</code></pre>
...@@ -4613,20 +4539,22 @@ const b: u8 = @truncate(u8, a);...@@ -4613,20 +4539,22 @@ const b: u8 = @truncate(u8, a);
4613 <p>4539 <p>
4614 To add standard build options to a <code>build.zig</code> file:4540 To add standard build options to a <code>build.zig</code> file:
4615 </p>4541 </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 {
4619 const exe = b.addExecutable("example", "example.zig");4546 const exe = b.addExecutable("example", "example.zig");
4620 exe.setBuildMode(b.standardReleaseOptions());4547 exe.setBuildMode(b.standardReleaseOptions());
4621 b.default_step.dependOn(&amp;exe.step);4548 b.default_step.dependOn(&exe.step);
4622}</code></pre>4549}
4550 {#code_end#}
4623 <p>4551 <p>
4624 This causes these options to be available:4552 This causes these options to be available:
4625 </p>4553 </p>
4626 <pre><code class="sh"> -Drelease-safe=(bool) optimizations on and safety on4554 <pre><code class="shell"> -Drelease-safe=(bool) optimizations on and safety on
4627 -Drelease-fast=(bool) optimizations on and safety off</code></pre>4555 -Drelease-fast=(bool) optimizations on and safety off</code></pre>
4628 {#header_open|Debug#}4556 {#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>
4630 <ul>4558 <ul>
4631 <li>Fast compilation speed</li>4559 <li>Fast compilation speed</li>
4632 <li>Safety checks enabled</li>4560 <li>Safety checks enabled</li>
...@@ -4634,7 +4562,7 @@ pub fn build(b: &amp;Builder) {...@@ -4634,7 +4562,7 @@ pub fn build(b: &amp;Builder) {
4634 </ul>4562 </ul>
4635 {#header_close#}4563 {#header_close#}
4636 {#header_open|ReleaseFast#}4564 {#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>
4638 <ul>4566 <ul>
4639 <li>Fast runtime performance</li>4567 <li>Fast runtime performance</li>
4640 <li>Safety checks disabled</li>4568 <li>Safety checks disabled</li>
...@@ -4642,7 +4570,7 @@ pub fn build(b: &amp;Builder) {...@@ -4642,7 +4570,7 @@ pub fn build(b: &amp;Builder) {
4642 </ul>4570 </ul>
4643 {#header_close#}4571 {#header_close#}
4644 {#header_open|ReleaseSafe#}4572 {#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>
4646 <ul>4574 <ul>
4647 <li>Medium runtime performance</li>4575 <li>Medium runtime performance</li>
4648 <li>Safety checks enabled</li>4576 <li>Safety checks enabled</li>
...@@ -4663,73 +4591,41 @@ pub fn build(b: &amp;Builder) {...@@ -4663,73 +4591,41 @@ pub fn build(b: &amp;Builder) {
4663 <p>4591 <p>
4664 When a safety check fails, Zig crashes with a stack trace, like this:4592 When a safety check fails, Zig crashes with a stack trace, like this:
4665 </p>4593 </p>
4666 <pre><code class="zig">test "safety check" {4594 {#code_begin|test_err|reached unreachable code#}
4667 unreachable;4595test "safety check" {
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)
4675 unreachable;4596 unreachable;
4676 ^4597}
4677/home/andy/dev/zig/build/lib/zig/std/special/test_runner.zig:9:21: 0x0000000000214b0a in ??? (test)4598 {#code_end#}
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>
4692 {#header_open|Reaching Unreachable Code#}4599 {#header_open|Reaching Unreachable Code#}
4693 <p>At compile-time:</p>4600 <p>At compile-time:</p>
4694 <pre><code class="zig">comptime {4601 {#code_begin|test_err|unable to evaluate constant expression#}
4602comptime {
4695 assert(false);4603 assert(false);
4696}4604}
4697fn assert(ok: bool) {4605fn assert(ok: bool) {
4698 if (!ok) unreachable; // assertion failure4606 if (!ok) unreachable; // assertion failure
4699}</code></pre>4607}
4700 <pre><code class="sh">$ zig build-obj test.zig4608 {#code_end#}
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>
4710 <p>At runtime crashes with the message <code>reached unreachable code</code> and a stack trace.</p>4609 <p>At runtime crashes with the message <code>reached unreachable code</code> and a stack trace.</p>
4711 {#header_close#}4610 {#header_close#}
4712 {#header_open|Index out of Bounds#}4611 {#header_open|Index out of Bounds#}
4713 <p>At compile-time:</p>4612 <p>At compile-time:</p>
4714 <pre><code class="zig">comptime {4613 {#code_begin|test_err|index 5 outside array of size 5#}
4614comptime {
4715 const array = "hello";4615 const array = "hello";
4716 const garbage = array[5];4616 const garbage = array[5];
4717}</code></pre>4617}
4718 <pre><code class="sh">$ zig build-obj test.zig4618 {#code_end#}
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>
4722 <p>At runtime crashes with the message <code>index out of bounds</code> and a stack trace.</p>4619 <p>At runtime crashes with the message <code>index out of bounds</code> and a stack trace.</p>
4723 {#header_close#}4620 {#header_close#}
4724 {#header_open|Cast Negative Number to Unsigned Integer#}4621 {#header_open|Cast Negative Number to Unsigned Integer#}
4725 <p>At compile-time:</p>4622 <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 {
4727 const value: i32 = -1;4625 const value: i32 = -1;
4728 const unsigned = u32(value);4626 const unsigned = u32(value);
4729}</code></pre>4627}
4730 <pre><code class="sh">$ zig build-obj test.zig test.zig:3:25: error: attempt to cast negative value to unsigned integer4628 {#code_end#}
4731 const unsigned = u32(value);
4732 ^</code></pre>
4733 <p>At runtime crashes with the message <code>attempt to cast negative value to unsigned integer</code> and a stack trace.</p>4629 <p>At runtime crashes with the message <code>attempt to cast negative value to unsigned integer</code> and a stack trace.</p>
4734 <p>4630 <p>
4735 If you are trying to obtain the maximum value of an unsigned integer, use <code>@maxValue(T)</code>,4631 If you are trying to obtain the maximum value of an unsigned integer, use <code>@maxValue(T)</code>,
...@@ -4738,14 +4634,12 @@ comptime {...@@ -4738,14 +4634,12 @@ comptime {
4738 {#header_close#}4634 {#header_close#}
4739 {#header_open|Cast Truncates Data#}4635 {#header_open|Cast Truncates Data#}
4740 <p>At compile-time:</p>4636 <p>At compile-time:</p>
4741 <pre><code class="zig">comptime {4637 {#code_begin|test_err|cast from 'u16' to 'u8' truncates bits#}
4638comptime {
4742 const spartan_count: u16 = 300;4639 const spartan_count: u16 = 300;
4743 const byte = u8(spartan_count);4640 const byte = u8(spartan_count);
4744}</code></pre>4641}
4745 <pre><code class="sh">$ zig build-obj test.zig4642 {#code_end#}
4746test.zig:3:20: error: cast from 'u16' to 'u8' truncates bits
4747 const byte = u8(spartan_count);
4748 ^</code></pre>
4749 <p>At runtime crashes with the message <code>integer cast truncated bits</code> and a stack trace.</p>4643 <p>At runtime crashes with the message <code>integer cast truncated bits</code> and a stack trace.</p>
4750 <p>4644 <p>
4751 If you are trying to truncate bits, use <code>@truncate(T, value)</code>,4645 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...@@ -4767,14 +4661,12 @@ test.zig:3:20: error: cast from 'u16' to 'u8' truncates bits
4767 <li><code>@divExact</code> (division)</li>4661 <li><code>@divExact</code> (division)</li>
4768 </ul>4662 </ul>
4769 <p>Example with addition at compile-time:</p>4663 <p>Example with addition at compile-time:</p>
4770 <pre><code class="zig">comptime {4664 {#code_begin|test_err|operation caused overflow#}
4665comptime {
4771 var byte: u8 = 255;4666 var byte: u8 = 255;
4772 byte += 1;4667 byte += 1;
4773}</code></pre>4668}
4774 <pre><code class="sh">$ zig build-obj test.zig4669 {#code_end#}
4775/home/andy/dev/zig/build/test.zig:3:10: error: operation caused overflow
4776 byte += 1;
4777 ^</code></pre>
4778 <p>At runtime crashes with the message <code>integer overflow</code> and a stack trace.</p>4670 <p>At runtime crashes with the message <code>integer overflow</code> and a stack trace.</p>
4779 {#header_close#}4671 {#header_close#}
4780 {#header_open|Standard Library Math Functions#}4672 {#header_open|Standard Library Math Functions#}
...@@ -4789,23 +4681,20 @@ test.zig:3:20: error: cast from 'u16' to 'u8' truncates bits...@@ -4789,23 +4681,20 @@ test.zig:3:20: error: cast from 'u16' to 'u8' truncates bits
4789 <li><code>@import("std").math.shl</code></li>4681 <li><code>@import("std").math.shl</code></li>
4790 </ul>4682 </ul>
4791 <p>Example of catching an overflow for addition:</p>4683 <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;
4793const warn = @import("std").debug.warn;4686const warn = @import("std").debug.warn;
4794pub fn main() -&gt; %void {4687pub fn main() -> %void {
4795 var byte: u8 = 255;4688 var byte: u8 = 255;
47964689
4797 byte = if (math.add(u8, byte, 1)) |result| {4690 byte = if (math.add(u8, byte, 1)) |result| result else |err| {
4798 result
4799 } else |err| {
4800 warn("unable to add one: {}\n", @errorName(err));4691 warn("unable to add one: {}\n", @errorName(err));
4801 return err;4692 return err;
4802 };4693 };
48034694
4804 warn("result: {}\n", byte);4695 warn("result: {}\n", byte);
4805}</code></pre>4696}
4806 <pre><code class="sh">$ zig build-exe test.zig4697 {#code_end#}
4807$ ./test
4808unable to add one: Overflow</code></pre>
4809 {#header_close#}4698 {#header_close#}
4810 {#header_open|Builtin Overflow Functions#}4699 {#header_open|Builtin Overflow Functions#}
4811 <p>4700 <p>
...@@ -4821,20 +4710,19 @@ unable to add one: Overflow</code></pre>...@@ -4821,20 +4710,19 @@ unable to add one: Overflow</code></pre>
4821 <p>4710 <p>
4822 Example of <code>@addWithOverflow</code>:4711 Example of <code>@addWithOverflow</code>:
4823 </p>4712 </p>
4824 <pre><code class="zig">const warn = @import("std").debug.warn;4713 {#code_begin|exe#}
4825pub fn main() -&gt; %void {4714const warn = @import("std").debug.warn;
4715pub fn main() -> %void {
4826 var byte: u8 = 255;4716 var byte: u8 = 255;
48274717
4828 var result: u8 = undefined;4718 var result: u8 = undefined;
4829 if (@addWithOverflow(u8, byte, 10, &amp;result)) {4719 if (@addWithOverflow(u8, byte, 10, &result)) {
4830 warn("overflowed result: {}\n", result);4720 warn("overflowed result: {}\n", result);
4831 } else {4721 } else {
4832 warn("result: {}\n", result);4722 warn("result: {}\n", result);
4833 }4723 }
4834}</code></pre>4724}
4835 <pre><code class="sh">$ zig build-exe test.zig4725 {#code_end#}
4836$ ./test
4837overflowed result: 9</code></pre>
4838 {#header_close#}4726 {#header_close#}
4839 {#header_open|Wrapping Operations#}4727 {#header_open|Wrapping Operations#}
4840 <p>4728 <p>
...@@ -4846,7 +4734,8 @@ overflowed result: 9</code></pre>...@@ -4846,7 +4734,8 @@ overflowed result: 9</code></pre>
4846 <li><code>-%</code> (wraparound negation)</li>4734 <li><code>-%</code> (wraparound negation)</li>
4847 <li><code>*%</code> (wraparound multiplication)</li>4735 <li><code>*%</code> (wraparound multiplication)</li>
4848 </ul>4736 </ul>
4849 <pre><code class="zig">const assert = @import("std").debug.assert;4737 {#code_begin|test#}
4738const assert = @import("std").debug.assert;
48504739
4851test "wraparound addition and subtraction" {4740test "wraparound addition and subtraction" {
4852 const x: i32 = @maxValue(i32);4741 const x: i32 = @maxValue(i32);
...@@ -4854,56 +4743,49 @@ test "wraparound addition and subtraction" {...@@ -4854,56 +4743,49 @@ test "wraparound addition and subtraction" {
4854 assert(min_val == @minValue(i32));4743 assert(min_val == @minValue(i32));
4855 const max_val = min_val -% 1;4744 const max_val = min_val -% 1;
4856 assert(max_val == @maxValue(i32));4745 assert(max_val == @maxValue(i32));
4857}</code></pre>4746}
4747 {#code_end#}
4858 {#header_close#}4748 {#header_close#}
4859 {#header_close#}4749 {#header_close#}
4860 {#header_open|Exact Left Shift Overflow#}4750 {#header_open|Exact Left Shift Overflow#}
4861 <p>At compile-time:</p>4751 <p>At compile-time:</p>
4862 <pre><code class="zig">comptime {4752 {#code_begin|test_err|operation caused overflow#}
4863 const x = @shlExact(u8(0b01010101), 2);4753comptime {
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
4867 const x = @shlExact(u8(0b01010101), 2);4754 const x = @shlExact(u8(0b01010101), 2);
4868 ^</code></pre>4755}
4756 {#code_end#}
4869 <p>At runtime crashes with the message <code>left shift overflowed bits</code> and a stack trace.</p>4757 <p>At runtime crashes with the message <code>left shift overflowed bits</code> and a stack trace.</p>
4870 {#header_close#}4758 {#header_close#}
4871 {#header_open|Exact Right Shift Overflow#}4759 {#header_open|Exact Right Shift Overflow#}
4872 <p>At compile-time:</p>4760 <p>At compile-time:</p>
4873 <pre><code class="zig">comptime {4761 {#code_begin|test_err|exact shift shifted out 1 bits#}
4874 const x = @shrExact(u8(0b10101010), 2);4762comptime {
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
4878 const x = @shrExact(u8(0b10101010), 2);4763 const x = @shrExact(u8(0b10101010), 2);
4879 ^</code></pre>4764}
4765 {#code_end#}
4880 <p>At runtime crashes with the message <code>right shift overflowed bits</code> and a stack trace.</p>4766 <p>At runtime crashes with the message <code>right shift overflowed bits</code> and a stack trace.</p>
4881 {#header_close#}4767 {#header_close#}
4882 {#header_open|Division by Zero#}4768 {#header_open|Division by Zero#}
4883 <p>At compile-time:</p>4769 <p>At compile-time:</p>
4884 <pre><code class="zig">comptime {4770 {#code_begin|test_err|division by zero#}
4771comptime {
4885 const a: i32 = 1;4772 const a: i32 = 1;
4886 const b: i32 = 0;4773 const b: i32 = 0;
4887 const c = a / b;4774 const c = a / b;
4888}</code></pre>4775}
4889 <pre><code class="sh">$ zig build-obj test.zig4776 {#code_end#}
4890/home/andy/dev/zig/build/test.zig:4:17: error: division by zero is undefined
4891 const c = a / b;
4892 ^</code></pre>
4893 <p>At runtime crashes with the message <code>division by zero</code> and a stack trace.</p>4777 <p>At runtime crashes with the message <code>division by zero</code> and a stack trace.</p>
48944778
4895 {#header_close#}4779 {#header_close#}
4896 {#header_open|Remainder Division by Zero#}4780 {#header_open|Remainder Division by Zero#}
4897 <p>At compile-time:</p>4781 <p>At compile-time:</p>
4898 <pre><code class="zig">comptime {4782 {#code_begin|test_err|division by zero#}
4783comptime {
4899 const a: i32 = 10;4784 const a: i32 = 10;
4900 const b: i32 = 0;4785 const b: i32 = 0;
4901 const c = a % b;4786 const c = a % b;
4902}</code></pre>4787}
4903 <pre><code class="sh">$ zig build-obj test.zig4788 {#code_end#}
4904/home/andy/dev/zig/build/test.zig:4:17: error: division by zero is undefined
4905 const c = a % b;
4906 ^</code></pre>
4907 <p>At runtime crashes with the message <code>remainder division by zero</code> and a stack trace.</p>4789 <p>At runtime crashes with the message <code>remainder division by zero</code> and a stack trace.</p>
49084790
4909 {#header_close#}4791 {#header_close#}
...@@ -4915,14 +4797,12 @@ test "wraparound addition and subtraction" {...@@ -4915,14 +4797,12 @@ test "wraparound addition and subtraction" {
4915 {#header_close#}4797 {#header_close#}
4916 {#header_open|Attempt to Unwrap Null#}4798 {#header_open|Attempt to Unwrap Null#}
4917 <p>At compile-time:</p>4799 <p>At compile-time:</p>
4918 <pre><code class="zig">comptime {4800 {#code_begin|test_err|unable to unwrap null#}
4801comptime {
4919 const nullable_number: ?i32 = null;4802 const nullable_number: ?i32 = null;
4920 const number = ??nullable_number;4803 const number = ??nullable_number;
4921}</code></pre>4804}
4922 <pre><code class="sh">$ zig build-obj test.zig4805 {#code_end#}
4923/home/andy/dev/zig/build/test.zig:3:20: error: unable to unwrap null
4924 const number = ??nullable_number;
4925 ^</code></pre>
4926 <p>At runtime crashes with the message <code>attempt to unwrap null</code> and a stack trace.</p>4806 <p>At runtime crashes with the message <code>attempt to unwrap null</code> and a stack trace.</p>
4927 <p>One way to avoid this crash is to test for null instead of assuming non-null, with4807 <p>One way to avoid this crash is to test for null instead of assuming non-null, with
4928 the <code>if</code> expression:</p>4808 the <code>if</code> expression:</p>
...@@ -4941,23 +4821,21 @@ pub fn main() {...@@ -4941,23 +4821,21 @@ pub fn main() {
4941 {#header_close#}4821 {#header_close#}
4942 {#header_open|Attempt to Unwrap Error#}4822 {#header_open|Attempt to Unwrap Error#}
4943 <p>At compile-time:</p>4823 <p>At compile-time:</p>
4944 <pre><code class="zig">comptime {4824 {#code_begin|test_err|unable to unwrap error 'UnableToReturnNumber'#}
4945 const number = %%getNumberOrFail();4825comptime {
4826 const number = getNumberOrFail() catch unreachable;
4946}4827}
49474828
4948error UnableToReturnNumber;4829error UnableToReturnNumber;
49494830
4950fn getNumberOrFail() -&gt; %i32 {4831fn getNumberOrFail() -> %i32 {
4951 return error.UnableToReturnNumber;4832 return error.UnableToReturnNumber;
4952}</code></pre>4833}
4953 <pre><code class="sh">$ zig build-obj test.zig4834 {#code_end#}
4954/home/andy/dev/zig/build/test.zig:2:20: error: unable to unwrap error 'UnableToReturnNumber'
4955 const number = %%getNumberOrFail();
4956 ^</code></pre>
4957 <p>At runtime crashes with the message <code>attempt to unwrap error: ErrorCode</code> and a stack trace.</p>4835 <p>At runtime crashes with the message <code>attempt to unwrap error: ErrorCode</code> and a stack trace.</p>
4958 <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with4836 <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with
4959 the <code>if</code> expression:</p>4837 the <code>if</code> expression:</p>
4960 {#code_begin|exe|test#}4838 {#code_begin|exe#}
4961const warn = @import("std").debug.warn;4839const warn = @import("std").debug.warn;
49624840
4963pub fn main() {4841pub fn main() {
...@@ -4979,16 +4857,14 @@ fn getNumberOrFail() -> %i32 {...@@ -4979,16 +4857,14 @@ fn getNumberOrFail() -> %i32 {
4979 {#header_close#}4857 {#header_close#}
4980 {#header_open|Invalid Error Code#}4858 {#header_open|Invalid Error Code#}
4981 <p>At compile-time:</p>4859 <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;
4983comptime {4862comptime {
4984 const err = error.AnError;4863 const err = error.AnError;
4985 const number = u32(err) + 10;4864 const number = u32(err) + 10;
4986 const invalid_err = error(number);4865 const invalid_err = error(number);
4987}</code></pre>4866}
4988 <pre><code class="sh">$ zig build-obj test.zig4867 {#code_end#}
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>
4992 <p>At runtime crashes with the message <code>invalid error code</code> and a stack trace.</p>4868 <p>At runtime crashes with the message <code>invalid error code</code> and a stack trace.</p>
4993 {#header_close#}4869 {#header_close#}
4994 {#header_open|Invalid Enum Cast#}4870 {#header_open|Invalid Enum Cast#}
...@@ -5020,17 +4896,26 @@ comptime {...@@ -5020,17 +4896,26 @@ comptime {
5020 which the compiler makes available to every Zig source file. It contains4896 which the compiler makes available to every Zig source file. It contains
5021 compile-time constants such as the current target, endianness, and release mode.4897 compile-time constants such as the current target, endianness, and release mode.
5022 </p>4898 </p>
5023 <pre><code class="zig">const builtin = @import("builtin");4899 {#code_begin|syntax#}
5024const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';</code></pre>4900const builtin = @import("builtin");
4901const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';
4902 {#code_end#}
5025 <p>4903 <p>
5026 Example of what is imported with <code>@import("builtin")</code>:4904 Example of what is imported with <code>@import("builtin")</code>:
5027 </p>4905 </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 {
5029 freestanding,4913 freestanding,
4914 ananas,
5030 cloudabi,4915 cloudabi,
5031 darwin,
5032 dragonfly,4916 dragonfly,
5033 freebsd,4917 freebsd,
4918 fuchsia,
5034 ios,4919 ios,
5035 kfreebsd,4920 kfreebsd,
5036 linux,4921 linux,
...@@ -5055,12 +4940,15 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';</code></p...@@ -5055,12 +4940,15 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';</code></p
5055 tvos,4940 tvos,
5056 watchos,4941 watchos,
5057 mesa3d,4942 mesa3d,
4943 contiki,
4944 zen,
5058};4945};
50594946
5060pub const Arch = enum {4947pub const Arch = enum {
5061 armv8_2a,4948 armv8_2a,
5062 armv8_1a,4949 armv8_1a,
5063 armv8,4950 armv8,
4951 armv8r,
5064 armv8m_baseline,4952 armv8m_baseline,
5065 armv8m_mainline,4953 armv8m_mainline,
5066 armv7,4954 armv7,
...@@ -5068,6 +4956,7 @@ pub const Arch = enum {...@@ -5068,6 +4956,7 @@ pub const Arch = enum {
5068 armv7m,4956 armv7m,
5069 armv7s,4957 armv7s,
5070 armv7k,4958 armv7k,
4959 armv7ve,
5071 armv6,4960 armv6,
5072 armv6m,4961 armv6m,
5073 armv6k,4962 armv6k,
...@@ -5087,16 +4976,20 @@ pub const Arch = enum {...@@ -5087,16 +4976,20 @@ pub const Arch = enum {
5087 mips64,4976 mips64,
5088 mips64el,4977 mips64el,
5089 msp430,4978 msp430,
4979 nios2,
5090 powerpc,4980 powerpc,
5091 powerpc64,4981 powerpc64,
5092 powerpc64le,4982 powerpc64le,
5093 r600,4983 r600,
5094 amdgcn,4984 amdgcn,
4985 riscv32,
4986 riscv64,
5095 sparc,4987 sparc,
5096 sparcv9,4988 sparcv9,
5097 sparcel,4989 sparcel,
5098 s390x,4990 s390x,
5099 tce,4991 tce,
4992 tcele,
5100 thumb,4993 thumb,
5101 thumbeb,4994 thumbeb,
5102 i386,4995 i386,
...@@ -5122,7 +5015,9 @@ pub const Arch = enum {...@@ -5122,7 +5015,9 @@ pub const Arch = enum {
5122 renderscript32,5015 renderscript32,
5123 renderscript64,5016 renderscript64,
5124};5017};
5018
5125pub const Environ = enum {5019pub const Environ = enum {
5020 unknown,
5126 gnu,5021 gnu,
5127 gnuabi64,5022 gnuabi64,
5128 gnueabi,5023 gnueabi,
...@@ -5140,6 +5035,7 @@ pub const Environ = enum {...@@ -5140,6 +5035,7 @@ pub const Environ = enum {
5140 cygnus,5035 cygnus,
5141 amdopencl,5036 amdopencl,
5142 coreclr,5037 coreclr,
5038 opencl,
5143};5039};
51445040
5145pub const ObjectFormat = enum {5041pub const ObjectFormat = enum {
...@@ -5147,6 +5043,7 @@ pub const ObjectFormat = enum {...@@ -5147,6 +5043,7 @@ pub const ObjectFormat = enum {
5147 coff,5043 coff,
5148 elf,5044 elf,
5149 macho,5045 macho,
5046 wasm,
5150};5047};
51515048
5152pub const GlobalLinkage = enum {5049pub const GlobalLinkage = enum {
...@@ -5171,15 +5068,53 @@ pub const Mode = enum {...@@ -5171,15 +5068,53 @@ pub const Mode = enum {
5171 ReleaseFast,5068 ReleaseFast,
5172};5069};
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;
5175pub const is_test = false;5109pub const is_test = false;
5176pub const os = Os.linux;5110pub const os = Os.linux;
5177pub const arch = Arch.x86_64;5111pub const arch = Arch.x86_64;
5178pub const environ = Environ.gnu;5112pub const environ = Environ.gnu;
5179pub const object_format = ObjectFormat.elf;5113pub const object_format = ObjectFormat.elf;
5180pub const mode = Mode.ReleaseFast;5114pub const mode = Mode.Debug;
5181pub const link_libs = [][]const u8 {5115pub const link_libc = false;
5182};</code></pre>5116pub const have_error_return_tracing = true;
5117 {#code_end#}
5183 {#see_also|Build Mode#}5118 {#see_also|Build Mode#}
5184 {#header_close#}5119 {#header_close#}
5185 {#header_open|Root Source File#}5120 {#header_open|Root Source File#}
...@@ -5230,16 +5165,19 @@ pub const link_libs = [][]const u8 {...@@ -5230,16 +5165,19 @@ pub const link_libs = [][]const u8 {
5230 {#see_also|Primitive Types#}5165 {#see_also|Primitive Types#}
5231 {#header_close#}5166 {#header_close#}
5232 {#header_open|C String Literals#}5167 {#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() {
5236 puts(c"this has a null terminator");5173 puts(c"this has a null terminator");
5237 puts(5174 puts(
5238 c\\and so5175 c\\and so
5239 c\\does this5176 c\\does this
5240 c\\multiline C string literal5177 c\\multiline C string literal
5241 );5178 );
5242}</code></pre>5179}
5180 {#code_end#}
5243 {#see_also|String Literals#}5181 {#see_also|String Literals#}
5244 {#header_close#}5182 {#header_close#}
5245 {#header_open|Import from C Header File#}5183 {#header_open|Import from C Header File#}
...@@ -5247,28 +5185,33 @@ pub fn main() -&gt; %void {...@@ -5247,28 +5185,33 @@ pub fn main() -&gt; %void {
5247 The <code>@cImport</code> builtin function can be used5185 The <code>@cImport</code> builtin function can be used
5248 to directly import symbols from .h files:5186 to directly import symbols from .h files:
5249 </p>5187 </p>
5250 <pre><code class="zig">const c = @cImport(@cInclude("stdio.h"));5188 {#code_begin|exe#}
5251pub fn main() -&gt; %void {5189 {#link_libc#}
5252 c.printf("hello\n");5190const c = @cImport(@cInclude("stdio.h"));
5253}</code></pre>5191pub fn main() {
5192 _ = c.printf(c"hello\n");
5193}
5194 {#code_end#}
5254 <p>5195 <p>
5255 The <code>@cImport</code> function takes an expression as a parameter.5196 The <code>@cImport</code> function takes an expression as a parameter.
5256 This expression is evaluated at compile-time and is used to control5197 This expression is evaluated at compile-time and is used to control
5257 preprocessor directives and include multiple .h files:5198 preprocessor directives and include multiple .h files:
5258 </p>5199 </p>
5259 <pre><code class="zig">const builtin = @import("builtin");5200 {#code_begin|syntax#}
5201const builtin = @import("builtin");
52605202
5261const c = @cImport({5203const c = @cImport({
5262 @cDefine("NDEBUG", builtin.mode == builtin.Mode.ReleaseFast);5204 @cDefine("NDEBUG", builtin.mode == builtin.Mode.ReleaseFast);
5263 if (something) {5205 if (something) {
5264 @cDefine("_GNU_SOURCE", {});5206 @cDefine("_GNU_SOURCE", {});
5265 }5207 }
5266 @cInclude("stdlib.h")5208 @cInclude("stdlib.h");
5267 if (something) {5209 if (something) {
5268 @cUndef("_GNU_SOURCE");5210 @cUndef("_GNU_SOURCE");
5269 }5211 }
5270 @cInclude("soundio.h");5212 @cInclude("soundio.h");
5271});</code></pre>5213});
5214 {#code_end#}
5272 {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}5215 {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
5273 {#header_close#}5216 {#header_close#}
5274 {#header_open|Mixing Object Files#}5217 {#header_open|Mixing Object Files#}
...@@ -5277,10 +5220,11 @@ const c = @cImport({...@@ -5277,10 +5220,11 @@ const c = @cImport({
5277 </p>5220 </p>
5278 {#header_close#}5221 {#header_close#}
5279 {#header_open|base64.zig#}5222 {#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,5226export fn decode_base_64(dest_ptr: &u8, dest_len: usize,
5283 source_ptr: &amp;const u8, source_len: usize) -&gt; usize5227 source_ptr: &const u8, source_len: usize) -> usize
5284{5228{
5285 const src = source_ptr[0..source_len];5229 const src = source_ptr[0..source_len];
5286 const dest = dest_ptr[0..dest_len];5230 const dest = dest_ptr[0..dest_len];
...@@ -5289,9 +5233,10 @@ export fn decode_base_64(dest_ptr: &amp;u8, dest_len: usize,...@@ -5289,9 +5233,10 @@ export fn decode_base_64(dest_ptr: &amp;u8, dest_len: usize,
5289 base64_decoder.decode(dest[0..decoded_size], src);5233 base64_decoder.decode(dest[0..decoded_size], src);
5290 return decoded_size;5234 return decoded_size;
5291}5235}
5292</code></pre>5236 {#code_end#}
5293{{teheader_open:st.c}}5237 {#header_close#}
5294 <pre><code class="c">// This header is generated by zig from base64.zig5238 {#header_open|test.c#}
5239 <pre><code class="cpp">// This header is generated by zig from base64.zig
5295#include "base64.h"5240#include "base64.h"
52965241
5297#include &lt;string.h&gt;5242#include &lt;string.h&gt;
...@@ -5309,9 +5254,10 @@ int main(int argc, char **argv) {...@@ -5309,9 +5254,10 @@ int main(int argc, char **argv) {
5309}</code></pre>5254}</code></pre>
5310 {#header_close#}5255 {#header_close#}
5311 {#header_open|build.zig#}5256 {#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 {
5315 const obj = b.addObject("base64", "base64.zig");5261 const obj = b.addObject("base64", "base64.zig");
53165262
5317 const exe = b.addCExecutable("test");5263 const exe = b.addCExecutable("test");
...@@ -5322,11 +5268,12 @@ pub fn build(b: &amp;Builder) {...@@ -5322,11 +5268,12 @@ pub fn build(b: &amp;Builder) {
5322 exe.addObject(obj);5268 exe.addObject(obj);
5323 exe.setOutputPath(".");5269 exe.setOutputPath(".");
53245270
5325 b.default_step.dependOn(&amp;exe.step);5271 b.default_step.dependOn(&exe.step);
5326}</code></pre>5272}
5273 {#code_end#}
5327 {#header_close#}5274 {#header_close#}
5328 {#header_open|Terminal#}5275 {#header_open|Terminal#}
5329 <pre><code class="sh">$ zig build5276 <pre><code class="shell">$ zig build
5330$ ./test5277$ ./test
5331all your base are belong to us</code></pre>5278all your base are belong to us</code></pre>
5332 {#see_also|Targets|Zig Build System#}5279 {#see_also|Targets|Zig Build System#}
...@@ -5338,11 +5285,12 @@ all your base are belong to us</code></pre>...@@ -5338,11 +5285,12 @@ all your base are belong to us</code></pre>
5338 what it looks like to execute <code>zig targets</code> on a Linux x86_645285 what it looks like to execute <code>zig targets</code> on a Linux x86_64
5339 computer:5286 computer:
5340 </p>5287 </p>
5341 <pre><code class="sh">$ zig targets5288 <pre><code class="shell">$ zig targets
5342Architectures:5289Architectures:
5343 armv8_2a5290 armv8_2a
5344 armv8_1a5291 armv8_1a
5345 armv85292 armv8
5293 armv8r
5346 armv8m_baseline5294 armv8m_baseline
5347 armv8m_mainline5295 armv8m_mainline
5348 armv75296 armv7
...@@ -5350,6 +5298,7 @@ Architectures:...@@ -5350,6 +5298,7 @@ Architectures:
5350 armv7m5298 armv7m
5351 armv7s5299 armv7s
5352 armv7k5300 armv7k
5301 armv7ve
5353 armv65302 armv6
5354 armv6m5303 armv6m
5355 armv6k5304 armv6k
...@@ -5369,16 +5318,20 @@ Architectures:...@@ -5369,16 +5318,20 @@ Architectures:
5369 mips645318 mips64
5370 mips64el5319 mips64el
5371 msp4305320 msp430
5321 nios2
5372 powerpc5322 powerpc
5373 powerpc645323 powerpc64
5374 powerpc64le5324 powerpc64le
5375 r6005325 r600
5376 amdgcn5326 amdgcn
5327 riscv32
5328 riscv64
5377 sparc5329 sparc
5378 sparcv95330 sparcv9
5379 sparcel5331 sparcel
5380 s390x5332 s390x
5381 tce5333 tce
5334 tcele
5382 thumb5335 thumb
5383 thumbeb5336 thumbeb
5384 i3865337 i386
...@@ -5392,6 +5345,7 @@ Architectures:...@@ -5392,6 +5345,7 @@ Architectures:
5392 amdil645345 amdil64
5393 hsail5346 hsail
5394 hsail645347 hsail64
5348 spir
5395 spir645349 spir64
5396 kalimbav35350 kalimbav3
5397 kalimbav45351 kalimbav4
...@@ -5405,10 +5359,11 @@ Architectures:...@@ -5405,10 +5359,11 @@ Architectures:
54055359
5406Operating Systems:5360Operating Systems:
5407 freestanding5361 freestanding
5362 ananas
5408 cloudabi5363 cloudabi
5409 darwin
5410 dragonfly5364 dragonfly
5411 freebsd5365 freebsd
5366 fuchsia
5412 ios5367 ios
5413 kfreebsd5368 kfreebsd
5414 linux (native)5369 linux (native)
...@@ -5433,8 +5388,11 @@ Operating Systems:...@@ -5433,8 +5388,11 @@ Operating Systems:
5433 tvos5388 tvos
5434 watchos5389 watchos
5435 mesa3d5390 mesa3d
5391 contiki
5392 zen
54365393
5437Environments:5394Environments:
5395 unknown
5438 gnu (native)5396 gnu (native)
5439 gnuabi645397 gnuabi64
5440 gnueabi5398 gnueabi
...@@ -5451,7 +5409,8 @@ Environments:...@@ -5451,7 +5409,8 @@ Environments:
5451 itanium5409 itanium
5452 cygnus5410 cygnus
5453 amdopencl5411 amdopencl
5454 coreclr</code></pre>5412 coreclr
5413 opencl</code></pre>
5455 <p>5414 <p>
5456 The Zig Standard Library (<code>@import("std")</code>) has architecture, environment, and operating sytsem5415 The Zig Standard Library (<code>@import("std")</code>) has architecture, environment, and operating sytsem
5457 abstractions, and thus takes additional work to support more platforms. It currently supports5416 abstractions, and thus takes additional work to support more platforms. It currently supports
...@@ -5518,7 +5477,8 @@ coding style....@@ -5518,7 +5477,8 @@ coding style.
5518 </p>5477 </p>
5519 {#header_close#}5478 {#header_close#}
5520 {#header_open|Examples#}5479 {#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");
5522var global_var: i32 = undefined;5482var global_var: i32 = undefined;
5523const const_name = 42;5483const const_name = 42;
5524const primitive_type_alias = f32;5484const primitive_type_alias = f32;
...@@ -5535,34 +5495,35 @@ fn functionName(param_name: TypeName) {...@@ -5535,34 +5495,35 @@ fn functionName(param_name: TypeName) {
5535}5495}
5536const functionAlias = functionName;5496const functionAlias = functionName;
55375497
5538fn ListTemplateFunction(comptime ChildType: type, comptime fixed_size: usize) -&gt; type {5498fn ListTemplateFunction(comptime ChildType: type, comptime fixed_size: usize) -> type {
5539 return List(ChildType, fixed_size);5499 return List(ChildType, fixed_size);
5540}5500}
55415501
5542fn ShortList(comptime T: type, comptime n: usize) -&gt; type {5502fn ShortList(comptime T: type, comptime n: usize) -> type {
5543 struct {5503 return struct {
5544 field_name: [n]T,5504 field_name: [n]T,
5545 fn methodName() {}5505 fn methodName() {}
5546 }5506 };
5547}5507}
55485508
5549// The word XML loses its casing when used in Zig identifiers.5509// The word XML loses its casing when used in Zig identifiers.
5550const xml_document =5510const xml_document =
5551 \\&lt;?xml version="1.0" encoding="UTF-8"?&gt;5511 \\<?xml version="1.0" encoding="UTF-8"?>
5552 \\&lt;document&gt;5512 \\<document>
5553 \\&lt;/document&gt;5513 \\</document>
5554;5514;
5555const XmlParser = struct {};5515const XmlParser = struct {};
55565516
5557// The initials BE (Big Endian) are just another word in Zig identifier names.5517// 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#}
5559 <p>5520 <p>
5560 See the Zig Standard Library for more examples.5521 See the Zig Standard Library for more examples.
5561 </p>5522 </p>
5562 {#header_close#}5523 {#header_close#}
5563 {#header_close#}5524 {#header_close#}
5564 {#header_open|Grammar#}5525 {#header_open|Grammar#}
5565 <pre><code>Root = many(TopLevelItem) EOF5526 <pre><code class="nohighlight">Root = many(TopLevelItem) EOF
55665527
5567TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl5528TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl
55685529
...@@ -5733,8 +5694,142 @@ ContainerDecl = option("extern" | "packed")...@@ -5733,8 +5694,142 @@ ContainerDecl = option("extern" | "packed")
5733 <p>TODO: document changes from a31b23c46ba2a8c28df01adc1aa0b4d878b9a5cf (compile time reflection additions)</p>5694 <p>TODO: document changes from a31b23c46ba2a8c28df01adc1aa0b4d878b9a5cf (compile time reflection additions)</p>
5734 {#header_close#}5695 {#header_close#}
5735 </div>5696 </div>
5736 <script src="highlight/highlight.pack.js"></script>5697 <script>
5737 <script>hljs.initHighlightingOnLoad();</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>
5738 </body>5833 </body>
5739</html>5834</html>
57405835
src/ir.cpp+1-1
...@@ -9009,7 +9009,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -9009,7 +9009,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
9009 int err;9009 int err;
9010 if ((err = ir_eval_math_op(resolved_type, op1_val, op_id, op2_val, out_val))) {9010 if ((err = ir_eval_math_op(resolved_type, op1_val, op_id, op2_val, out_val))) {
9011 if (err == ErrorDivByZero) {9011 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"));
9013 return ira->codegen->builtin_types.entry_invalid;9013 return ira->codegen->builtin_types.entry_invalid;
9014 } else if (err == ErrorOverflow) {9014 } else if (err == ErrorOverflow) {
9015 ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("operation caused overflow"));9015 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) {...@@ -462,7 +462,7 @@ int main(int argc, char **argv) {
462 Termination term;462 Termination term;
463 os_spawn_process(buf_ptr(path_to_build_exe), args, &term);463 os_spawn_process(buf_ptr(path_to_build_exe), args, &term);
464 if (term.how != TerminationIdClean || term.code != 0) {464 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");
466 fprintf(stderr, "%s", buf_ptr(path_to_build_exe));466 fprintf(stderr, "%s", buf_ptr(path_to_build_exe));
467 for (size_t i = 0; i < args.length; i += 1) {467 for (size_t i = 0; i < args.length; i += 1) {
468 fprintf(stderr, " %s", args.at(i));468 fprintf(stderr, " %s", args.at(i));
test/compile_errors.zig+7-7
...@@ -861,10 +861,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -861,10 +861,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
861 \\export fn entry3() -> usize { return @sizeOf(@typeOf(int_x)); }861 \\export fn entry3() -> usize { return @sizeOf(@typeOf(int_x)); }
862 \\export fn entry4() -> usize { return @sizeOf(@typeOf(float_x)); }862 \\export fn entry4() -> usize { return @sizeOf(@typeOf(float_x)); }
863 ,863 ,
864 ".tmp_source.zig:1:21: 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 is undefined",865 ".tmp_source.zig:2:25: error: division by zero",
866 ".tmp_source.zig:3:22: error: division by zero is undefined",866 ".tmp_source.zig:3:22: error: division by zero",
867 ".tmp_source.zig:4:26: error: division by zero is undefined");867 ".tmp_source.zig:4:26: error: division by zero");
868868
869869
870 cases.add("normal string with newline",870 cases.add("normal string with newline",
...@@ -911,7 +911,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -911,7 +911,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
911 \\911 \\
912 \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }912 \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
913 ,913 ,
914 ".tmp_source.zig:3:14: error: division by zero is undefined",914 ".tmp_source.zig:3:14: error: division by zero",
915 ".tmp_source.zig:1:14: note: called from here");915 ".tmp_source.zig:1:14: note: called from here");
916916
917 cases.add("branch on undefined value",917 cases.add("branch on undefined value",
...@@ -1816,7 +1816,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1816,7 +1816,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1816 \\ const c = a / b;1816 \\ const c = a / b;
1817 \\}1817 \\}
1818 ,1818 ,
1819 ".tmp_source.zig:4:17: error: division by zero is undefined");1819 ".tmp_source.zig:4:17: error: division by zero");
18201820
1821 cases.add("compile-time remainder division by zero",1821 cases.add("compile-time remainder division by zero",
1822 \\comptime {1822 \\comptime {
...@@ -1825,7 +1825,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1825,7 +1825,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1825 \\ const c = a % b;1825 \\ const c = a % b;
1826 \\}1826 \\}
1827 ,1827 ,
1828 ".tmp_source.zig:4:17: error: division by zero is undefined");1828 ".tmp_source.zig:4:17: error: division by zero");
18291829
1830 cases.add("compile-time integer cast truncates bits",1830 cases.add("compile-time integer cast truncates bits",
1831 \\comptime {1831 \\comptime {