diff --git a/doc/docgen.zig b/doc/docgen.zig index 4b4606d255..79fd1519cf 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -280,7 +280,7 @@ const Code = struct { id: Id, name: []const u8, source_token: Token, - is_inline: bool, + just_check_syntax: bool, mode: std.builtin.Mode, link_objects: []const []const u8, target_str: ?[]const u8, @@ -305,6 +305,18 @@ const Link = struct { token: Token, }; +const SyntaxBlock = struct { + source_type: SourceType, + name: []const u8, + source_token: Token, + + const SourceType = enum { + zig, + c, + javascript, + }; +}; + const Node = union(enum) { Content: []const u8, Nav, @@ -313,7 +325,9 @@ const Node = union(enum) { SeeAlso: []const SeeAlsoItem, Code: Code, Link: Link, - Syntax: Token, + InlineSyntax: Token, + Shell: Token, + SyntaxBlock: SyntaxBlock, }; const Toc = struct { @@ -403,7 +417,7 @@ fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc { .HeaderOpen = HeaderOpen{ .name = content, .url = urlized, - .n = header_stack_size, + .n = header_stack_size + 1, // highest-level section headers start at h2 }, }); if (try urls.fetchPut(urlized, tag_token)) |kv| { @@ -502,7 +516,7 @@ fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc { } const code_kind_str = tokenizer.buffer[code_kind_tok.start..code_kind_tok.end]; var code_kind_id: Code.Id = undefined; - var is_inline = false; + var just_check_syntax = false; if (mem.eql(u8, code_kind_str, "exe")) { code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Succeed }; } else if (mem.eql(u8, code_kind_str, "exe_err")) { @@ -526,7 +540,7 @@ fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc { code_kind_id = Code.Id.Lib; } else if (mem.eql(u8, code_kind_str, "syntax")) { code_kind_id = Code.Id{ .Obj = null }; - is_inline = true; + just_check_syntax = true; } else { return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {s}", .{code_kind_str}); } @@ -589,7 +603,7 @@ fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc { .id = code_kind_id, .name = name, .source_token = source_token, - .is_inline = is_inline, + .just_check_syntax = just_check_syntax, .mode = mode, .link_objects = link_objects.toOwnedSlice(), .target_str = target_str, @@ -615,7 +629,67 @@ fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc { ); } _ = try eatToken(tokenizer, Token.Id.BracketClose); - try nodes.append(Node{ .Syntax = content_tok }); + try nodes.append(Node{ .InlineSyntax = content_tok }); + } else if (mem.eql(u8, tag_name, "shell_samp")) { + _ = try eatToken(tokenizer, Token.Id.BracketClose); + const content_tok = try eatToken(tokenizer, Token.Id.Content); + _ = try eatToken(tokenizer, Token.Id.BracketOpen); + const end_syntax_tag = try eatToken(tokenizer, Token.Id.TagContent); + const end_tag_name = tokenizer.buffer[end_syntax_tag.start..end_syntax_tag.end]; + if (!mem.eql(u8, end_tag_name, "end_shell_samp")) { + return parseError( + tokenizer, + end_syntax_tag, + "invalid token inside syntax: {s}", + .{end_tag_name}, + ); + } + _ = try eatToken(tokenizer, Token.Id.BracketClose); + try nodes.append(Node{ .Shell = content_tok }); + } else if (mem.eql(u8, tag_name, "syntax_block")) { + _ = try eatToken(tokenizer, Token.Id.Separator); + const source_type_tok = try eatToken(tokenizer, Token.Id.TagContent); + var name: []const u8 = "sample_code"; + const maybe_sep = tokenizer.next(); + switch (maybe_sep.id) { + Token.Id.Separator => { + const name_tok = try eatToken(tokenizer, Token.Id.TagContent); + name = tokenizer.buffer[name_tok.start..name_tok.end]; + _ = try eatToken(tokenizer, Token.Id.BracketClose); + }, + Token.Id.BracketClose => {}, + else => return parseError(tokenizer, token, "invalid token", .{}), + } + const source_type_str = tokenizer.buffer[source_type_tok.start..source_type_tok.end]; + var source_type: SyntaxBlock.SourceType = undefined; + if (mem.eql(u8, source_type_str, "zig")) { + source_type = SyntaxBlock.SourceType.zig; + } else if (mem.eql(u8, source_type_str, "c")) { + source_type = SyntaxBlock.SourceType.c; + } else if (mem.eql(u8, source_type_str, "javascript")) { + source_type = SyntaxBlock.SourceType.javascript; + } else { + return parseError(tokenizer, source_type_tok, "unrecognized code kind: {s}", .{source_type_str}); + } + const source_token = while (true) { + const content_tok = try eatToken(tokenizer, Token.Id.Content); + _ = try eatToken(tokenizer, Token.Id.BracketOpen); + const end_code_tag = try eatToken(tokenizer, Token.Id.TagContent); + const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end]; + if (mem.eql(u8, end_tag_name, "end_syntax_block")) { + _ = try eatToken(tokenizer, Token.Id.BracketClose); + break content_tok; + } else { + return parseError( + tokenizer, + end_code_tag, + "invalid token inside code_begin: {s}", + .{end_tag_name}, + ); + } + _ = try eatToken(tokenizer, Token.Id.BracketClose); + } else unreachable; // TODO issue #707 + try nodes.append(Node{ .SyntaxBlock = SyntaxBlock{ .source_type = source_type, .name = name, .source_token = source_token } }); } else { return parseError(tokenizer, tag_token, "unrecognized tag name: {s}", .{tag_name}); } @@ -693,7 +767,7 @@ test "term color" { const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; const result = try termColor(std.testing.allocator, input_bytes); defer std.testing.allocator.free(result); - testing.expectEqualSlices(u8, "AgreenB", result); + try testing.expectEqualSlices(u8, "AgreenB", result); } fn termColor(allocator: *Allocator, input: []const u8) ![]u8 { @@ -799,7 +873,7 @@ fn tokenizeAndPrintRaw( ) !void { const src_non_terminated = mem.trim(u8, raw_src, " \n"); const src = try allocator.dupeZ(u8, src_non_terminated); - try out.writeAll(""); + try out.writeAll(""); var tokenizer = std.zig.Tokenizer.init(src); var index: usize = 0; var next_tok_is_fn = false; @@ -1033,6 +1107,47 @@ fn tokenizeAndPrint( return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src); } +fn printSourceBlock(allocator: *Allocator, docgen_tokenizer: *Tokenizer, out: anytype, syntax_block: SyntaxBlock) !void { + const source_type = @tagName(syntax_block.source_type); + + try out.print("
{s}
", .{ source_type, syntax_block.name });
+    switch (syntax_block.source_type) {
+        .zig => try tokenizeAndPrint(allocator, docgen_tokenizer, out, syntax_block.source_token),
+        else => {
+            const raw_source = docgen_tokenizer.buffer[syntax_block.source_token.start..syntax_block.source_token.end];
+            const trimmed_raw_source = mem.trim(u8, raw_source, " \n");
+
+            try out.writeAll("");
+            try writeEscaped(out, trimmed_raw_source);
+            try out.writeAll("");
+        },
+    }
+    try out.writeAll("
"); +} + +fn printShell(out: anytype, shell_content: []const u8) !void { + const trimmed_shell_content = mem.trim(u8, shell_content, " \n"); + try out.writeAll("
Shell
");
+    var cmd_cont: bool = false;
+    var iter = std.mem.split(u8, trimmed_shell_content, "\n");
+    while (iter.next()) |orig_line| {
+        const line = mem.trimRight(u8, orig_line, " ");
+        if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] != '\\') {
+            try out.print("$ {s}\n", .{std.mem.trimLeft(u8, line[1..], " ")});
+        } else if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] == '\\') {
+            try out.print("$ {s}\n", .{std.mem.trimLeft(u8, line[1..], " ")});
+            cmd_cont = true;
+        } else if (line.len > 0 and line[line.len - 1] != '\\' and cmd_cont) {
+            try out.print("{s}\n", .{line});
+            cmd_cont = false;
+        } else {
+            try out.print("{s}\n", .{line});
+        }
+    }
+
+    try out.writeAll("
"); +} + fn genHtml( allocator: *Allocator, tokenizer: *Tokenizer, @@ -1066,9 +1181,9 @@ fn genHtml( try out.writeAll(toc.toc); }, .Builtin => |tok| { - try out.writeAll("
");
+                try out.writeAll("
@import(\"builtin\")
");
                 try tokenizeAndPrintRaw(allocator, tokenizer, out, tok, builtin_code);
-                try out.writeAll("
"); + try out.writeAll("
"); }, .HeaderOpen => |info| { try out.print( @@ -1087,30 +1202,44 @@ fn genHtml( } try out.writeAll("\n"); }, - .Syntax => |content_tok| { + .InlineSyntax => |content_tok| { try tokenizeAndPrint(allocator, tokenizer, out, content_tok); }, + .Shell => |content_tok| { + const raw_shell_content = tokenizer.buffer[content_tok.start..content_tok.end]; + try printShell(out, raw_shell_content); + }, + .SyntaxBlock => |syntax_block| { + try printSourceBlock(allocator, tokenizer, out, syntax_block); + }, .Code => |code| { - const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end]; - const trimmed_raw_source = mem.trim(u8, raw_source, " \n"); - if (!code.is_inline) { - try out.print("

{s}.zig

", .{code.name}); - } - try out.writeAll("
");
-                try tokenizeAndPrint(allocator, tokenizer, out, code.source_token);
-                try out.writeAll("
"); + const name_plus_ext = try std.fmt.allocPrint(allocator, "{s}.zig", .{code.name}); + const syntax_block = SyntaxBlock{ + .source_type = .zig, + .name = name_plus_ext, + .source_token = code.source_token, + }; - if (!do_code_tests or code.is_inline) { + try printSourceBlock(allocator, tokenizer, out, syntax_block); + + // TODO: remove code.just_check_syntax after updating code samples + // that have stopped working due to a change in the compiler. + if (!do_code_tests or code.just_check_syntax) { continue; } - const name_plus_ext = try std.fmt.allocPrint(allocator, "{s}.zig", .{code.name}); + const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end]; + const trimmed_raw_source = mem.trim(u8, raw_source, " \n"); const tmp_source_file_name = try fs.path.join( allocator, &[_][]const u8{ tmp_dir_name, name_plus_ext }, ); try fs.cwd().writeFile(tmp_source_file_name, trimmed_raw_source); + var shell_buffer = std.ArrayList(u8).init(allocator); + defer shell_buffer.deinit(); + var shell_out = shell_buffer.writer(); + switch (code.id) { Code.Id.Exe => |expected_outcome| code_block: { var build_args = std.ArrayList([]const u8).init(allocator); @@ -1121,12 +1250,14 @@ fn genHtml( "--color", "on", "--enable-cache", tmp_source_file_name, }); - try out.print("
$ zig build-exe {s}.zig", .{code.name});
+
+                        try shell_out.print("$ zig build-exe {s} ", .{name_plus_ext});
+
                         switch (code.mode) {
                             .Debug => {},
                             else => {
                                 try build_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
-                                try out.print(" -O {s}", .{@tagName(code.mode)});
+                                try shell_out.print("-O {s} ", .{@tagName(code.mode)});
                             },
                         }
                         for (code.link_objects) |link_object| {
@@ -1136,25 +1267,26 @@ fn genHtml(
                                 &[_][]const u8{ tmp_dir_name, name_with_ext },
                             );
                             try build_args.append(full_path_object);
-                            try out.print(" {s}", .{name_with_ext});
+                            try shell_out.print("{s} ", .{name_with_ext});
                         }
                         if (code.link_libc) {
                             try build_args.append("-lc");
-                            try out.print(" -lc", .{});
+                            try shell_out.print("-lc ", .{});
                         }
                         const target = try std.zig.CrossTarget.parse(.{
                             .arch_os_abi = code.target_str orelse "native",
                         });
                         if (code.target_str) |triple| {
                             try build_args.appendSlice(&[_][]const u8{ "-target", triple });
-                            if (!code.is_inline) {
-                                try out.print(" -target {s}", .{triple});
-                            }
+                            try shell_out.print("-target {s} ", .{triple});
                         }
                         if (code.verbose_cimport) {
                             try build_args.append("--verbose-cimport");
-                            try out.print(" --verbose-cimport", .{});
+                            try shell_out.print("--verbose-cimport ", .{});
                         }
+
+                        try shell_out.print("\n", .{});
+
                         if (expected_outcome == .BuildFail) {
                             const result = try ChildProcess.exec(.{
                                 .allocator = allocator,
@@ -1180,12 +1312,17 @@ fn genHtml(
                             }
                             const escaped_stderr = try escapeHtml(allocator, result.stderr);
                             const colored_stderr = try termColor(allocator, escaped_stderr);
-                            try out.print("\n{s}
\n", .{colored_stderr}); + try shell_out.writeAll(colored_stderr); break :code_block; } const exec_result = exec(allocator, &env_map, build_args.items) catch return parseError(tokenizer, code.source_token, "example failed to compile", .{}); + if (code.verbose_cimport) { + const escaped_build_stderr = try escapeHtml(allocator, exec_result.stderr); + try shell_out.writeAll(escaped_build_stderr); + } + if (code.target_str) |triple| { if (mem.startsWith(u8, triple, "wasm32") or mem.startsWith(u8, triple, "riscv64-linux") or @@ -1193,7 +1330,6 @@ fn genHtml( std.Target.current.os.tag != .linux or std.Target.current.cpu.arch != .x86_64)) { // skip execution - try out.print("
\n", .{}); break :code_block; } } @@ -1241,41 +1377,38 @@ fn genHtml( const colored_stderr = try termColor(allocator, escaped_stderr); const colored_stdout = try termColor(allocator, escaped_stdout); - if (code.verbose_cimport) { - const escaped_build_stderr = try escapeHtml(allocator, exec_result.stderr); - try out.print("\n{s}", .{escaped_build_stderr}); - } - try out.print("\n$ ./{s}\n{s}{s}", .{ code.name, colored_stdout, colored_stderr }); + try shell_out.print("\n$ ./{s}\n{s}{s}", .{ code.name, colored_stdout, colored_stderr }); if (exited_with_signal) { - try out.print("(process terminated by signal)", .{}); + try shell_out.print("(process terminated by signal)", .{}); } - try out.print("
\n", .{}); + try shell_out.writeAll("\n"); }, Code.Id.Test => { var test_args = std.ArrayList([]const u8).init(allocator); defer test_args.deinit(); try test_args.appendSlice(&[_][]const u8{ zig_exe, "test", tmp_source_file_name }); - try out.print("
$ zig test {s}.zig", .{code.name});
+                        try shell_out.print("$ zig test {s}.zig ", .{code.name});
+
                         switch (code.mode) {
                             .Debug => {},
                             else => {
                                 try test_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
-                                try out.print(" -O {s}", .{@tagName(code.mode)});
+                                try shell_out.print("-O {s} ", .{@tagName(code.mode)});
                             },
                         }
                         if (code.link_libc) {
                             try test_args.append("-lc");
-                            try out.print(" -lc", .{});
+                            try shell_out.print("-lc ", .{});
                         }
                         if (code.target_str) |triple| {
                             try test_args.appendSlice(&[_][]const u8{ "-target", triple });
-                            try out.print(" -target {s}", .{triple});
+                            try shell_out.print("-target {s} ", .{triple});
                         }
                         const result = exec(allocator, &env_map, test_args.items) catch return parseError(tokenizer, code.source_token, "test failed", .{});
                         const escaped_stderr = try escapeHtml(allocator, result.stderr);
                         const escaped_stdout = try escapeHtml(allocator, result.stdout);
-                        try out.print("\n{s}{s}
\n", .{ escaped_stderr, escaped_stdout }); + try shell_out.print("\n{s}{s}\n", .{ escaped_stderr, escaped_stdout }); }, Code.Id.TestError => |error_match| { var test_args = std.ArrayList([]const u8).init(allocator); @@ -1288,12 +1421,13 @@ fn genHtml( "on", tmp_source_file_name, }); - try out.print("
$ zig test {s}.zig", .{code.name});
+                        try shell_out.print("$ zig test {s}.zig ", .{code.name});
+
                         switch (code.mode) {
                             .Debug => {},
                             else => {
                                 try test_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
-                                try out.print(" -O {s}", .{@tagName(code.mode)});
+                                try shell_out.print("-O {s} ", .{@tagName(code.mode)});
                             },
                         }
                         const result = try ChildProcess.exec(.{
@@ -1325,7 +1459,7 @@ fn genHtml(
                         }
                         const escaped_stderr = try escapeHtml(allocator, result.stderr);
                         const colored_stderr = try termColor(allocator, escaped_stderr);
-                        try out.print("\n{s}
\n", .{colored_stderr}); + try shell_out.print("\n{s}\n", .{colored_stderr}); }, Code.Id.TestSafety => |error_match| { @@ -1383,7 +1517,7 @@ fn genHtml( } const escaped_stderr = try escapeHtml(allocator, result.stderr); const colored_stderr = try termColor(allocator, escaped_stderr); - try out.print("
$ zig test {s}.zig {s}\n{s}
\n", .{ + try shell_out.print("$ zig test {s}.zig {s}\n{s}\n", .{ code.name, mode_arg, colored_stderr, @@ -1406,23 +1540,20 @@ fn genHtml( tmp_dir_name, fs.path.sep, name_plus_obj_ext, }), }); - if (!code.is_inline) { - try out.print("
$ zig build-obj {s}.zig", .{code.name});
-                        }
+
+                        try shell_out.print("$ zig build-obj {s}.zig ", .{code.name});
 
                         switch (code.mode) {
                             .Debug => {},
                             else => {
                                 try build_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
-                                if (!code.is_inline) {
-                                    try out.print(" -O {s}", .{@tagName(code.mode)});
-                                }
+                                try shell_out.print("-O {s} ", .{@tagName(code.mode)});
                             },
                         }
 
                         if (code.target_str) |triple| {
                             try build_args.appendSlice(&[_][]const u8{ "-target", triple });
-                            try out.print(" -target {s}", .{triple});
+                            try shell_out.print("-target {s} ", .{triple});
                         }
 
                         if (maybe_error_match) |error_match| {
@@ -1455,13 +1586,11 @@ fn genHtml(
                             }
                             const escaped_stderr = try escapeHtml(allocator, result.stderr);
                             const colored_stderr = try termColor(allocator, escaped_stderr);
-                            try out.print("\n{s}", .{colored_stderr});
+                            try shell_out.print("\n{s} ", .{colored_stderr});
                         } else {
                             _ = exec(allocator, &env_map, build_args.items) catch return parseError(tokenizer, code.source_token, "example failed to compile", .{});
                         }
-                        if (!code.is_inline) {
-                            try out.print("
\n", .{}); - } + try shell_out.writeAll("\n"); }, Code.Id.Lib => { const bin_basename = try std.zig.binNameAlloc(allocator, .{ @@ -1481,36 +1610,41 @@ fn genHtml( tmp_dir_name, fs.path.sep_str, bin_basename, }), }); - try out.print("
$ zig build-lib {s}.zig", .{code.name});
+                        try shell_out.print("$ zig build-lib {s}.zig ", .{code.name});
+
                         switch (code.mode) {
                             .Debug => {},
                             else => {
                                 try test_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
-                                try out.print(" -O {s}", .{@tagName(code.mode)});
+                                try shell_out.print("-O {s} ", .{@tagName(code.mode)});
                             },
                         }
                         if (code.target_str) |triple| {
                             try test_args.appendSlice(&[_][]const u8{ "-target", triple });
-                            try out.print(" -target {s}", .{triple});
+                            try shell_out.print("-target {s} ", .{triple});
                         }
                         if (code.link_mode) |link_mode| {
                             switch (link_mode) {
                                 .Static => {
                                     try test_args.append("-static");
-                                    try out.print(" -static", .{});
+                                    try shell_out.print("-static ", .{});
                                 },
                                 .Dynamic => {
                                     try test_args.append("-dynamic");
-                                    try out.print(" -dynamic", .{});
+                                    try shell_out.print("-dynamic ", .{});
                                 },
                             }
                         }
                         const result = exec(allocator, &env_map, test_args.items) catch return parseError(tokenizer, code.source_token, "test failed", .{});
                         const escaped_stderr = try escapeHtml(allocator, result.stderr);
                         const escaped_stdout = try escapeHtml(allocator, result.stdout);
-                        try out.print("\n{s}{s}
\n", .{ escaped_stderr, escaped_stdout }); + try shell_out.print("\n{s}{s}\n", .{ escaped_stderr, escaped_stdout }); }, } + + if (!code.just_check_syntax) { + try printShell(out, shell_buffer.items); + } }, } } @@ -1551,3 +1685,195 @@ fn dumpArgs(args: []const []const u8) void { else print("\n", .{}); } + +test "shell parsed" { + const test_allocator = std.testing.allocator; + + { + const shell_out = + \\$ zig build test.zig + ; + const expected = + \\
Shell
$ zig build test.zig
+            \\
+ ; + + var buffer = std.ArrayList(u8).init(test_allocator); + defer buffer.deinit(); + + try printShell(buffer.writer(), shell_out); + try testing.expectEqualSlices(u8, expected, buffer.items); + } + { + const shell_out = + \\$ zig build test.zig + \\build output + ; + const expected = + \\
Shell
$ zig build test.zig
+            \\build output
+            \\
+ ; + + var buffer = std.ArrayList(u8).init(test_allocator); + defer buffer.deinit(); + + try printShell(buffer.writer(), shell_out); + try testing.expectEqualSlices(u8, expected, buffer.items); + } + { + const shell_out = + \\$ zig build test.zig + \\build output + \\$ ./test + ; + const expected = + \\
Shell
$ zig build test.zig
+            \\build output
+            \\$ ./test
+            \\
+ ; + + var buffer = std.ArrayList(u8).init(test_allocator); + defer buffer.deinit(); + + try printShell(buffer.writer(), shell_out); + try testing.expectEqualSlices(u8, expected, buffer.items); + } + { + const shell_out = + \\$ zig build test.zig + \\ + \\$ ./test + \\output + ; + const expected = + \\
Shell
$ zig build test.zig
+            \\
+            \\$ ./test
+            \\output
+            \\
+ ; + + var buffer = std.ArrayList(u8).init(test_allocator); + defer buffer.deinit(); + + try printShell(buffer.writer(), shell_out); + try testing.expectEqualSlices(u8, expected, buffer.items); + } + { + const shell_out = + \\$ zig build test.zig + \\$ ./test + \\output + ; + const expected = + \\
Shell
$ zig build test.zig
+            \\$ ./test
+            \\output
+            \\
+ ; + + var buffer = std.ArrayList(u8).init(test_allocator); + defer buffer.deinit(); + + try printShell(buffer.writer(), shell_out); + try testing.expectEqualSlices(u8, expected, buffer.items); + } + { + const shell_out = + \\$ zig build test.zig \ + \\ --build-option + \\build output + \\$ ./test + \\output + ; + const expected = + \\
Shell
$ zig build test.zig \
+            \\ --build-option
+            \\build output
+            \\$ ./test
+            \\output
+            \\
+ ; + + var buffer = std.ArrayList(u8).init(test_allocator); + defer buffer.deinit(); + + try printShell(buffer.writer(), shell_out); + try testing.expectEqualSlices(u8, expected, buffer.items); + } + { + // intentional space after "--build-option1 \" + const shell_out = + \\$ zig build test.zig \ + \\ --build-option1 \ + \\ --build-option2 + \\$ ./test + ; + const expected = + \\
Shell
$ zig build test.zig \
+            \\ --build-option1 \
+            \\ --build-option2
+            \\$ ./test
+            \\
+ ; + + var buffer = std.ArrayList(u8).init(test_allocator); + defer buffer.deinit(); + + try printShell(buffer.writer(), shell_out); + try testing.expectEqualSlices(u8, expected, buffer.items); + } + { + const shell_out = + \\$ zig build test.zig \ + \\$ ./test + ; + const expected = + \\
Shell
$ zig build test.zig \
+            \\$ ./test
+            \\
+ ; + + var buffer = std.ArrayList(u8).init(test_allocator); + defer buffer.deinit(); + + try printShell(buffer.writer(), shell_out); + try testing.expectEqualSlices(u8, expected, buffer.items); + } + { + const shell_out = + \\$ zig build test.zig + \\$ ./test + \\$1 + ; + const expected = + \\
Shell
$ zig build test.zig
+            \\$ ./test
+            \\$1
+            \\
+ ; + + var buffer = std.ArrayList(u8).init(test_allocator); + defer buffer.deinit(); + + try printShell(buffer.writer(), shell_out); + try testing.expectEqualSlices(u8, expected, buffer.items); + } + { + const shell_out = + \\$zig build test.zig + ; + const expected = + \\
Shell
$zig build test.zig
+            \\
+ ; + + var buffer = std.ArrayList(u8).init(test_allocator); + defer buffer.deinit(); + + try printShell(buffer.writer(), shell_out); + try testing.expectEqualSlices(u8, expected, buffer.items); + } +} diff --git a/doc/langref.html.in b/doc/langref.html.in index 4bd831672a..9a3eef2390 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6,225 +6,312 @@ Documentation - The Zig Programming Language - - -
-
- 0.1.1 | - 0.2.0 | - 0.3.0 | - 0.4.0 | - 0.5.0 | - 0.6.0 | - 0.7.1 | - 0.8.1 | - master -

Contents

- {#nav#} + a { + color: #88f; + } + a:hover,a:focus { + color: #000; + } + table, th, td { + border-color: grey; + } + .t2_0 { + color: grey; + } + .t31_1 { + color: red; + } + .t32_1 { + color: #00B800; + } + .t36_1 { + color: #0086b3; + } + code { + background: #222; + border-color: #444; + } + pre > code { + color: #ccc; + background: #222; + border: unset; + } + samp { + background: #000; + color: #ccc; + } + pre > samp { + border: unset; + } + .tok-kw { + color: #eee; + } + .tok-str { + color: #2e5; + } + .tok-builtin { + color: #ff894c; + } + .tok-comment { + color: #aa7; + } + .tok-fn { + color: #B1A0F8; + } + .tok-null { + color: #ff8080; + } + .tok-number { + color: #ff8080; + } + .tok-type { + color: #68f; + } + h1 a, h2 a, h3 a, h4 a, h5 a { + color: #aaa; + } + figcaption.zig-cap { + background-color: #b27306; + color: #000; + } + figcaption.shell-cap { + background: #2a2a2a; + color: #fff; + } + } + + + +

Zig Language Reference

+
+ -
+
{#header_open|Introduction#}

- Zig is a general-purpose programming language and toolchain for maintaining + Zig is a general-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.

-
    -
  • Robust - behavior is correct even for edge cases such as out of memory.
  • -
  • Optimal - write programs the best way they can behave and perform.
  • -
  • Reusable - the same code works in many environments which have different - constraints.
  • -
  • Maintainable - precisely communicate intent to the compiler and +
    +
    Robust
    Behavior is correct even for edge cases such as out of memory.
    +
    Optimal
    Write programs the best way they can behave and perform.
    +
    Reusable
    The same code works in many environments which have different + constraints.
    +
    Maintainable
    Precisely communicate intent to the compiler and other programmers. The language imposes a low overhead to reading code and is - resilient to changing requirements and environments.
  • -
+ resilient to changing requirements and environments. +

Often the most efficient way to learn something new is to see examples, so this documentation shows how to use each of Zig's features. It is @@ -236,8 +323,16 @@

This HTML document depends on no external files, so you can use it offline.

+ {#header_close#} + + {#header_open|Zig Standard Library#}

- Where is the documentation for the Zig standard library? + The Zig Standard Library has its own documentation. +

+

+ Zig's Standard Library contains commonly used algorithms, data structures, and definitions to help you build programs or libraries. + You will see many examples of Zig's Standard Library used in this documentation. To learn more about the Zig Standard Library, + visit the link above.

{#header_close#} @@ -252,96 +347,102 @@ pub fn main() !void { } {#code_end#}

- The Zig code sample above demonstrates one way to create a program that will output Hello, world!. + The Zig code sample above demonstrates one way to create a program that will output: Hello, world!.

- The code sample shows the contents of a file named hello.zig. Files storing Zig + The code sample shows the contents of a file named hello.zig. Files storing Zig source code are {#link|UTF-8 encoded|Source Encoding#} text files. The files storing - Zig source code are usually named with the .zig extension. + Zig source code are usually named with the .zig extension.

- Following the hello.zig Zig code sample, the {#link|Zig Build System#} is used - to build an executable program from the hello.zig source code. Then, the - hello program is executed showing its output Hello, world!. The - lines beginning with $ represent command line prompts and a command. + Following the hello.zig Zig code sample, the {#link|Zig Build System#} is used + to build an executable program from the hello.zig source code. Then, the + hello program is executed showing its output Hello, world!. The + lines beginning with $ represent command line prompts and a command. Everything else is program output.

- The code sample begins by adding Zig's Standard Library to the build using the {#link|@import#} builtin function. - The {#syntax#}@import("std"){#endsyntax#} function call creates a structure to represent the Standard Library. + The code sample begins by adding the {#link|Zig Standard Library#} to the build using the {#link|@import#} builtin function. + The {#syntax#}@import("std"){#endsyntax#} function call creates a structure that represents the Zig Standard Library. The code then {#link|declares|Container Level Variables#} a - {#link|constant identifier|Assignment#}, named std, for easy access to - Zig's standard library. + {#link|constant identifier|Assignment#}, named {#syntax#}std{#endsyntax#}, that gives access the features of the Zig Standard Library.

- Next, a {#link|public function|Functions#}, {#syntax#}pub fn{#endsyntax#}, named main - is declared. The main function is necessary because it tells the Zig compiler where the start of + Next, a {#link|public function|Functions#}, {#syntax#}pub fn{#endsyntax#}, named {#syntax#}main{#endsyntax#} + is declared. The {#syntax#}main{#endsyntax#} function is necessary because it tells the Zig compiler where the start of the program exists. Programs designed to be executed will need a {#syntax#}pub fn main{#endsyntax#} function. - For more advanced use cases, Zig offers other features to inform the compiler where the start of - the program exists. Libraries, on the other hand, do not need a main function because - library code is usually called by other programs.

+

A function is a block of any number of statements and expressions that, as a whole, perform a task. Functions may or may not return data after they are done performing their task. If a function cannot perform its task, it might return an error. Zig makes all of this explicit.

- In the hello.zig code sample, the main function is declared + In the hello.zig code sample, the main function is declared with the {#syntax#}!void{#endsyntax#} return type. This return type is known as an {#link|Error Union Type#}. This syntax tells the Zig compiler that the function will either return an - error or a value. An error union type combines an {#link|Error Set Type#} and a {#link|Primitive Type|Primitive Types#}. + error or a value. An error union type combines an {#link|Error Set Type#} and any other data type + (e.g. a {#link|Primitive Type|Primitive Types#} or a user-defined type such as a {#link|struct#}, {#link|enum#}, or {#link|union#}). The full form of an error union type is - <error set type>{#syntax#}!{#endsyntax#}<primitive type>. In the code + <error set type>{#syntax#}!{#endsyntax#}<any data type>. In the code sample, the error set type is not explicitly written on the left side of the {#syntax#}!{#endsyntax#} operator. - When written this way, the error set type is a special kind of error union type that has an - {#link|inferred error set type|Inferred Error Sets#}. The {#syntax#}void{#endsyntax#} after the {#syntax#}!{#endsyntax#} operator - tells the compiler that the function will not return a value under normal circumstances (i.e. no errors occur). + When written this way, the error set type is an {#link|inferred error set type|Inferred Error Sets#}. The + {#syntax#}void{#endsyntax#} after the {#syntax#}!{#endsyntax#} operator + tells the compiler that the function will not return a value under normal circumstances (i.e. when no errors occur). +

+ +

+ In Zig, a function's block of statements and expressions are surrounded by an open curly-brace { and + close curly-brace }. Inside of the {#syntax#}main{#endsyntax#} function are expressions that perform + the task of outputting Hello, world! to standard output.

- Note to experienced programmers: Zig also has the boolean {#link|operator|Operators#} {#syntax#}!a{#endsyntax#} - where {#syntax#}a{#endsyntax#} is a value of type {#syntax#}bool{#endsyntax#}. Error union types contain the - name of the type in the syntax: {#syntax#}!{#endsyntax#}<primitive type>. -

-

- In Zig, a function's block of statements and expressions are surrounded by { and - } curly-braces. Inside of the main function are expressions that perform - the task of outputting Hello, world! to standard output. -

-

- First, a constant identifier, stdout, is initialized to represent standard output's - writer. Then, the program tries to print the Hello, world! + First, a constant identifier, {#syntax#}stdout{#endsyntax#}, is initialized to represent standard output's + writer. Then, the program tries to print the Hello, world! message to standard output.

Functions sometimes need information to perform their task. In Zig, information is passed - to functions between open ( and close ) parenthesis placed after + to functions between an open parenthesis {#syntax#}({#endsyntax#} and a close parenthesis {#syntax#}){#endsyntax#} placed after the function's name. This information is also known as arguments. When there are - multiple arguments passed to a function, they are separated by commas ,. + multiple arguments passed to a function, they are separated by commas {#syntax#},{#endsyntax#}.

- The two arguments passed to the stdout.print() function, "Hello, {s}!\n" - and .{"world"}, are evaluated at {#link|compile-time|comptime#}. The code sample is + The two arguments passed to the {#syntax#}stdout.print(){#endsyntax#} function, {#syntax#}"Hello, {s}!\n"{#endsyntax#} + and {#syntax#}.{"world"}{#endsyntax#}, are evaluated at {#link|compile-time|comptime#}. The code sample is purposely written to show how to perform {#link|string|String Literals and Unicode Code Point Literals#} - substitution in the print function. The curly-braces inside of the first argument + substitution in the {#syntax#}print{#endsyntax#} function. The curly-braces inside of the first argument are substituted with the compile-time known value inside of the second argument (known as an {#link|anonymous struct literal|Anonymous Struct Literals#}). The \n inside of the double-quotes of the first argument is the {#link|escape sequence|Escape Sequences#} for the - newline character. The {#link|try#} expression evaluates the result of stdout.print. + newline character. The {#link|try#} expression evaluates the result of {#syntax#}stdout.print{#endsyntax#}. If the result is an error, then the {#syntax#}try{#endsyntax#} expression will return from - main with the error. Otherwise, the program will continue. In this case, there are no - more statements or expressions left to execute in the main function, so the program exits. + {#syntax#}main{#endsyntax#} with the error. Otherwise, the program will continue. In this case, there are no + more statements or expressions left to execute in the {#syntax#}main{#endsyntax#} function, so the program exits.

- In Zig, the standard output writer's print function is allowed to fail because + In Zig, the standard output writer's {#syntax#}print{#endsyntax#} function is allowed to fail because it is actually a function defined as part of a generic Writer. Consider a generic Writer that represents writing data to a file. When the disk is full, a write to the file will fail. However, we typically do not expect writing text to the standard output to fail. To avoid having to handle the failure case of printing to standard output, you can use alternate functions: the - functions in std.log for proper logging or the std.debug.print function. + functions in {#syntax#}std.log{#endsyntax#} for proper logging or the {#syntax#}std.debug.print{#endsyntax#} function. This documentation will use the latter option to print to standard error (stderr) and silently return - on failure. The next code sample, hello_again.zig demonstrates the use of - std.debug.print. + on failure. The next code sample, hello_again.zig demonstrates the use of + {#syntax#}std.debug.print{#endsyntax#}.

{#code_begin|exe|hello_again#} const print = @import("std").debug.print; @@ -351,13 +452,13 @@ pub fn main() void { } {#code_end#}

- Note that you can leave off the {#syntax#}!{#endsyntax#} from the return type because std.debug.print cannot fail. + Note that you can leave off the {#syntax#}!{#endsyntax#} from the return type because {#syntax#}std.debug.print{#endsyntax#} cannot fail.

{#see_also|Values|@import|Errors|Root Source File|Source Encoding#} {#header_close#} {#header_open|Zig Test#}

- zig test is a tool that can be used to quickly build and run Zig code + zig test is a tool that can be used to quickly build and run Zig code to make sure behavior meets expectations. {#syntax#}@import("builtin").is_test{#endsyntax#} is available for code to detect whether the current build is a test build.

@@ -387,7 +488,7 @@ test "unused function" { } undefined behavior. The implementation of {#syntax#}std.debug.assert{#endsyntax#} is as simple as:

- {#code_begin|syntax#} + {#code_begin|syntax|assert#} pub fn assert(ok: bool) void { if (!ok) unreachable; } @@ -396,7 +497,7 @@ pub fn assert(ok: bool) void { This means that when testing in ReleaseFast or ReleaseSmall mode, {#syntax#}assert{#endsyntax#} is not sufficient to check the result of a computation:

- {#code_begin|syntax#} + {#code_begin|syntax|assert_release_fast_mode#} const std = @import("std"); const assert = std.debug.assert; @@ -423,14 +524,13 @@ test "expect in release fast mode" { {#code_end#}

See the rest of the {#syntax#}std.testing{#endsyntax#} namespace for more available functions.

- zig test has a few command line parameters which affect the compilation. See - zig --help for a full list. The most interesting one is --test-filter [text]. + zig test has a few command line parameters which affect the compilation. See + zig --help for a full list. The most interesting one is --test-filter [text]. This makes the test build only include tests whose name contains the supplied filter text. Again, thanks to lazy analysis, this can allow you to narrow a build to only a few functions in isolation.

{#header_close#} - {#header_open|Comments#} {#code_begin|test|comments#} const expect = @import("std").testing.expect; @@ -555,184 +655,183 @@ pub fn main() void { {#header_open|Primitive Types#}
- - - - + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + +
- Name - - C Equivalent - - Description -
Primitive Types
TypeC EquivalentDescription
{#syntax#}i8{#endsyntax#}{#syntax#}i8{#endsyntax#} int8_t signed 8-bit integer
{#syntax#}u8{#endsyntax#}{#syntax#}u8{#endsyntax#} uint8_t unsigned 8-bit integer
{#syntax#}i16{#endsyntax#}{#syntax#}i16{#endsyntax#} int16_t signed 16-bit integer
{#syntax#}u16{#endsyntax#}{#syntax#}u16{#endsyntax#} uint16_t unsigned 16-bit integer
{#syntax#}i32{#endsyntax#}{#syntax#}i32{#endsyntax#} int32_t signed 32-bit integer
{#syntax#}u32{#endsyntax#}{#syntax#}u32{#endsyntax#} uint32_t unsigned 32-bit integer
{#syntax#}i64{#endsyntax#}{#syntax#}i64{#endsyntax#} int64_t signed 64-bit integer
{#syntax#}u64{#endsyntax#}{#syntax#}u64{#endsyntax#} uint64_t unsigned 64-bit integer
{#syntax#}i128{#endsyntax#}{#syntax#}i128{#endsyntax#} __int128 signed 128-bit integer
{#syntax#}u128{#endsyntax#}{#syntax#}u128{#endsyntax#} unsigned __int128 unsigned 128-bit integer
{#syntax#}isize{#endsyntax#}{#syntax#}isize{#endsyntax#} intptr_t signed pointer sized integer
{#syntax#}usize{#endsyntax#}{#syntax#}usize{#endsyntax#} uintptr_t unsigned pointer sized integer
{#syntax#}c_short{#endsyntax#}{#syntax#}c_short{#endsyntax#} short for ABI compatibility with C
{#syntax#}c_ushort{#endsyntax#}{#syntax#}c_ushort{#endsyntax#} unsigned short for ABI compatibility with C
{#syntax#}c_int{#endsyntax#}{#syntax#}c_int{#endsyntax#} int for ABI compatibility with C
{#syntax#}c_uint{#endsyntax#}{#syntax#}c_uint{#endsyntax#} unsigned int for ABI compatibility with C
{#syntax#}c_long{#endsyntax#}{#syntax#}c_long{#endsyntax#} long for ABI compatibility with C
{#syntax#}c_ulong{#endsyntax#}{#syntax#}c_ulong{#endsyntax#} unsigned long for ABI compatibility with C
{#syntax#}c_longlong{#endsyntax#}{#syntax#}c_longlong{#endsyntax#} long long for ABI compatibility with C
{#syntax#}c_ulonglong{#endsyntax#}{#syntax#}c_ulonglong{#endsyntax#} unsigned long long for ABI compatibility with C
{#syntax#}c_longdouble{#endsyntax#}{#syntax#}c_longdouble{#endsyntax#} long double for ABI compatibility with C
{#syntax#}c_void{#endsyntax#}{#syntax#}c_void{#endsyntax#} void for ABI compatibility with C
{#syntax#}f16{#endsyntax#}{#syntax#}f16{#endsyntax#} _Float16 16-bit floating point (10-bit mantissa) IEEE-754-2008 binary16
{#syntax#}f32{#endsyntax#}{#syntax#}f32{#endsyntax#} float 32-bit floating point (23-bit mantissa) IEEE-754-2008 binary32
{#syntax#}f64{#endsyntax#}{#syntax#}f64{#endsyntax#} double 64-bit floating point (52-bit mantissa) IEEE-754-2008 binary64
{#syntax#}f128{#endsyntax#}{#syntax#}f128{#endsyntax#} _Float128 128-bit floating point (112-bit mantissa) IEEE-754-2008 binary128
{#syntax#}bool{#endsyntax#}{#syntax#}bool{#endsyntax#} bool {#syntax#}true{#endsyntax#} or {#syntax#}false{#endsyntax#}
{#syntax#}void{#endsyntax#}{#syntax#}void{#endsyntax#} (none) 0 bit type
{#syntax#}noreturn{#endsyntax#}{#syntax#}noreturn{#endsyntax#} (none) the type of {#syntax#}break{#endsyntax#}, {#syntax#}continue{#endsyntax#}, {#syntax#}return{#endsyntax#}, {#syntax#}unreachable{#endsyntax#}, and {#syntax#}while (true) {}{#endsyntax#}
{#syntax#}type{#endsyntax#}{#syntax#}type{#endsyntax#} (none) the type of types
{#syntax#}anyerror{#endsyntax#}{#syntax#}anyerror{#endsyntax#} (none) an error code
{#syntax#}comptime_int{#endsyntax#}{#syntax#}comptime_int{#endsyntax#} (none) Only allowed for {#link|comptime#}-known values. The type of integer literals.
{#syntax#}comptime_float{#endsyntax#}{#syntax#}comptime_float{#endsyntax#} (none) Only allowed for {#link|comptime#}-known values. The type of float literals.

@@ -746,26 +845,27 @@ pub fn main() void { {#header_open|Primitive Values#}

+ + - - + + + + - + - + - + +
Primitive Values
- Name - - Description - NameDescription
{#syntax#}true{#endsyntax#} and {#syntax#}false{#endsyntax#}{#syntax#}true{#endsyntax#} and {#syntax#}false{#endsyntax#} {#syntax#}bool{#endsyntax#} values
{#syntax#}null{#endsyntax#}{#syntax#}null{#endsyntax#} used to set an optional type to {#syntax#}null{#endsyntax#}
{#syntax#}undefined{#endsyntax#}{#syntax#}undefined{#endsyntax#} used to leave a value unspecified
{#see_also|Optionals|undefined#} @@ -796,7 +896,7 @@ pub fn main() void { in recent versions of the Unicode specification (as of Unicode 13.0). In Zig, a Unicode code point literal corresponds to the Unicode definition of a code point.

- {#code_begin|test#} + {#code_begin|test|string_literals_test#} const expect = @import("std").testing.expect; const mem = @import("std").mem; @@ -817,46 +917,47 @@ test "string literals" { {#header_open|Escape Sequences#}
+ + - - + + + + - + - + - + - + - + - + - + - + +
Escape Sequences
- Escape Sequence - - Name - Escape SequenceName
\n\n Newline
\r\r Carriage Return
\t\t Tab
\\\\ Backslash
\'\' Single Quote
\"\" Double Quote
\xNN\xNN hexadecimal 8-bit byte value (2 digits)
\u{NNNNNN}\u{NNNNNN} hexadecimal Unicode code point UTF-8 encoded (1 or more digits)

Note that the maximum valid Unicode point is {#syntax#}0x10ffff{#endsyntax#}.

@@ -870,7 +971,7 @@ test "string literals" { However, if the next line begins with {#syntax#}\\{#endsyntax#} then a newline is appended and the string literal continues.

- {#code_begin|syntax#} + {#code_begin|syntax|multiline_string_literals#} const hello_world_in_c = \\#include \\ @@ -902,7 +1003,7 @@ test "assignment" { {#code_end#}

{#syntax#}const{#endsyntax#} applies to all of the bytes that the identifier immediately addresses. {#link|Pointers#} have their own const-ness.

If you need a variable that you can modify, use the {#syntax#}var{#endsyntax#} keyword:

- {#code_begin|test#} + {#code_begin|test|var_test#} const expect = @import("std").testing.expect; test "var" { @@ -923,7 +1024,7 @@ test "initialization" { {#code_end#} {#header_open|undefined#}

Use {#syntax#}undefined{#endsyntax#} to leave variables uninitialized:

- {#code_begin|test#} + {#code_begin|test|undefined_test#} const expect = @import("std").testing.expect; test "init with undefined" { @@ -1108,7 +1209,7 @@ test "comptime vars" { {#header_open|Integers#} {#header_open|Integer Literals#} - {#code_begin|syntax#} + {#code_begin|syntax|integer_literals#} const decimal_int = 98222; const hex_int = 0xff; const another_hex_int = 0xFF; @@ -1131,7 +1232,7 @@ const big_address = 0xFF80_0000_0000_0000; However, once an integer value is no longer known at compile-time, it must have a known size, and is vulnerable to undefined behavior.

- {#code_begin|syntax#} + {#code_begin|syntax|runtime_vs_comptime#} fn divide(a: i32, b: i32) i32 { return a / b; } @@ -1174,7 +1275,7 @@ fn divide(a: i32, b: i32) i32 { Float literals {#link|coerce|Type Coercion#} to any floating point type, and to any {#link|integer|Integers#} type when there is no fractional component.

- {#code_begin|syntax#} + {#code_begin|syntax|float_literals#} const floating_point = 123.0E+77; const another_float = 123.0; const yet_another = 123.0e+77; @@ -1192,7 +1293,7 @@ const more_hex = 0x1234_5678.9ABC_CDEFp-10; There is no syntax for NaN, infinity, or negative infinity. For these special values, one must use the standard library:

- {#code_begin|syntax#} + {#code_begin|syntax|float_special_values#} const std = @import("std"); const inf = std.math.inf(f32); @@ -1245,23 +1346,19 @@ pub fn main() void { {#header_open|Table of Operators#}
+ + - - - - + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1847,7 +1944,7 @@ ptr.* == 1234{#endsyntax#} - + +
Table of Operators
- Syntax - - Relevant Types - - Description - - Example - SyntaxRelevant TypesDescriptionExample
{#syntax#}a + b
-a += b{#endsyntax#}
{#syntax#}a + b
+a += b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1280,8 +1377,8 @@ a += b{#endsyntax#}
{#syntax#}a +% b
-a +%= b{#endsyntax#}
{#syntax#}a +% b
+a +%= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1299,8 +1396,8 @@ a +%= b{#endsyntax#}
{#syntax#}a - b
-a -= b{#endsyntax#}
{#syntax#}a - b
+a -= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1319,8 +1416,8 @@ a -= b{#endsyntax#}
{#syntax#}a -% b
-a -%= b{#endsyntax#}
{#syntax#}a -% b
+a -%= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1338,7 +1435,7 @@ a -%= b{#endsyntax#}
{#syntax#}-a{#endsyntax#}
{#syntax#}-a{#endsyntax#}
  • {#link|Integers#}
  • @@ -1356,7 +1453,7 @@ a -%= b{#endsyntax#}
{#syntax#}-%a{#endsyntax#}
{#syntax#}-%a{#endsyntax#}
  • {#link|Integers#}
  • @@ -1373,8 +1470,8 @@ a -%= b{#endsyntax#}
{#syntax#}a * b
-a *= b{#endsyntax#}
{#syntax#}a * b
+a *= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1393,8 +1490,8 @@ a *= b{#endsyntax#}
{#syntax#}a *% b
-a *%= b{#endsyntax#}
{#syntax#}a *% b
+a *%= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1412,8 +1509,8 @@ a *%= b{#endsyntax#}
{#syntax#}a / b
-a /= b{#endsyntax#}
{#syntax#}a / b
+a /= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1438,8 +1535,8 @@ a /= b{#endsyntax#}
{#syntax#}a % b
-a %= b{#endsyntax#}
{#syntax#}a % b
+a %= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1462,8 +1559,8 @@ a %= b{#endsyntax#}
{#syntax#}a << b
-a <<= b{#endsyntax#}
{#syntax#}a << b
+a <<= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1481,8 +1578,8 @@ a <<= b{#endsyntax#}
{#syntax#}a >> b
-a >>= b{#endsyntax#}
{#syntax#}a >> b
+a >>= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1499,8 +1596,8 @@ a >>= b{#endsyntax#}
{#syntax#}a & b
-a &= b{#endsyntax#}
{#syntax#}a & b
+a &= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1516,8 +1613,8 @@ a &= b{#endsyntax#}
{#syntax#}a | b
-a |= b{#endsyntax#}
{#syntax#}a | b
+a |= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1533,8 +1630,8 @@ a |= b{#endsyntax#}
{#syntax#}a ^ b
-a ^= b{#endsyntax#}
{#syntax#}a ^ b
+a ^= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1550,7 +1647,7 @@ a ^= b{#endsyntax#}
{#syntax#}~a{#endsyntax#}
{#syntax#}~a{#endsyntax#}
  • {#link|Integers#}
  • @@ -1564,7 +1661,7 @@ a ^= b{#endsyntax#}
{#syntax#}a orelse b{#endsyntax#}
{#syntax#}a orelse b{#endsyntax#}
  • {#link|Optionals#}
  • @@ -1582,7 +1679,7 @@ unwrapped == 1234{#endsyntax#}
{#syntax#}a.?{#endsyntax#}
{#syntax#}a.?{#endsyntax#}
  • {#link|Optionals#}
  • @@ -1598,8 +1695,8 @@ value.? == 5678{#endsyntax#}
{#syntax#}a catch b
-a catch |err| b{#endsyntax#}
{#syntax#}a catch b
+a catch |err| b{#endsyntax#}
  • {#link|Error Unions|Errors#}
  • @@ -1618,7 +1715,7 @@ unwrapped == 1234{#endsyntax#}
{#syntax#}a and b{#endsyntax#}
{#syntax#}a and b{#endsyntax#}
  • {#link|bool|Primitive Types#}
  • @@ -1633,7 +1730,7 @@ unwrapped == 1234{#endsyntax#}
{#syntax#}a or b{#endsyntax#}
{#syntax#}a or b{#endsyntax#}
  • {#link|bool|Primitive Types#}
  • @@ -1648,7 +1745,7 @@ unwrapped == 1234{#endsyntax#}
{#syntax#}!a{#endsyntax#}
{#syntax#}!a{#endsyntax#}
  • {#link|bool|Primitive Types#}
  • @@ -1662,7 +1759,7 @@ unwrapped == 1234{#endsyntax#}
{#syntax#}a == b{#endsyntax#}
{#syntax#}a == b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1680,7 +1777,7 @@ unwrapped == 1234{#endsyntax#}
{#syntax#}a == null{#endsyntax#}
{#syntax#}a == null{#endsyntax#}
  • {#link|Optionals#}
  • @@ -1695,7 +1792,7 @@ value == null{#endsyntax#}
{#syntax#}a != b{#endsyntax#}
{#syntax#}a != b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1713,7 +1810,7 @@ value == null{#endsyntax#}
{#syntax#}a > b{#endsyntax#}
{#syntax#}a > b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1729,7 +1826,7 @@ value == null{#endsyntax#}
{#syntax#}a >= b{#endsyntax#}
{#syntax#}a >= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1745,7 +1842,7 @@ value == null{#endsyntax#}
{#syntax#}a < b{#endsyntax#}
{#syntax#}a < b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1761,7 +1858,7 @@ value == null{#endsyntax#}
{#syntax#}a <= b{#endsyntax#}
{#syntax#}a <= b{#endsyntax#}
  • {#link|Integers#}
  • @@ -1777,7 +1874,7 @@ value == null{#endsyntax#}
{#syntax#}a ++ b{#endsyntax#}
{#syntax#}a ++ b{#endsyntax#}
  • {#link|Arrays#}
  • @@ -1786,7 +1883,7 @@ value == null{#endsyntax#}
Array concatenation.
    -
  • Only available when {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} are {#link|compile-time known|comptime#}. +
  • Only available when {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} are {#link|compile-time known|comptime#}.
@@ -1798,7 +1895,7 @@ mem.eql(u32, &together, &[_]u32{1,2,3,4}){#endsyntax#}
{#syntax#}a ** b{#endsyntax#}
{#syntax#}a ** b{#endsyntax#}
  • {#link|Arrays#}
  • @@ -1807,7 +1904,7 @@ mem.eql(u32, &together, &[_]u32{1,2,3,4}){#endsyntax#}
Array multiplication.
    -
  • Only available when {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} are {#link|compile-time known|comptime#}. +
  • Only available when {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} are {#link|compile-time known|comptime#}.
@@ -1817,7 +1914,7 @@ mem.eql(u8, pattern, "ababab"){#endsyntax#}
{#syntax#}a.*{#endsyntax#}
{#syntax#}a.*{#endsyntax#}
  • {#link|Pointers#}
  • @@ -1833,7 +1930,7 @@ ptr.* == 1234{#endsyntax#}
{#syntax#}&a{#endsyntax#}
{#syntax#}&a{#endsyntax#}
All types
{#syntax#}a || b{#endsyntax#}
{#syntax#}a || b{#endsyntax#}
  • {#link|Error Set Type#}
  • @@ -1862,6 +1959,7 @@ const B = error{Two}; (A || B) == error{One, Two}{#endsyntax#}
{#header_close#} @@ -2138,7 +2236,7 @@ test "null terminated array" {

Use {#syntax#}&x{#endsyntax#} to obtain a single-item pointer:

- {#code_begin|test#} + {#code_begin|test|single_item_pointer_test#} const expect = @import("std").testing.expect; test "address of syntax" { @@ -2182,7 +2280,7 @@ test "pointer array access" { against this kind of undefined behavior. This is one reason we prefer slices to pointers.

- {#code_begin|test#} + {#code_begin|test|slice_bounds#} const expect = @import("std").testing.expect; test "pointer slicing" { @@ -2197,7 +2295,7 @@ test "pointer slicing" { {#code_end#}

Pointers work at compile-time too, as long as the code does not depend on an undefined memory layout:

- {#code_begin|test#} + {#code_begin|test|comptime_pointers#} const expect = @import("std").testing.expect; test "comptime pointers" { @@ -2212,7 +2310,7 @@ test "comptime pointers" { {#code_end#}

To convert an integer address into a pointer, use {#syntax#}@intToPtr{#endsyntax#}. To convert a pointer to an integer, use {#syntax#}@ptrToInt{#endsyntax#}:

- {#code_begin|test#} + {#code_begin|test|integer_pointer_conversion#} const expect = @import("std").testing.expect; test "@ptrToInt and @intToPtr" { @@ -2224,7 +2322,7 @@ test "@ptrToInt and @intToPtr" { {#code_end#}

Zig is able to preserve memory addresses in comptime code, as long as the pointer is never dereferenced:

- {#code_begin|test#} + {#code_begin|test|comptime_pointer_conversion#} const expect = @import("std").testing.expect; test "comptime @intToPtr" { @@ -2244,7 +2342,7 @@ test "comptime @intToPtr" { should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}. In the following code, loads and stores with {#syntax#}mmio_ptr{#endsyntax#} are guaranteed to all happen and in the same order as in source code:

- {#code_begin|test#} + {#code_begin|test|volatile#} const expect = @import("std").testing.expect; test "volatile" { @@ -2263,7 +2361,7 @@ test "volatile" { operation that Zig cannot protect you against. Use {#syntax#}@ptrCast{#endsyntax#} only when other conversions are not possible.

- {#code_begin|test#} + {#code_begin|test|pointer_casting#} const std = @import("std"); const expect = std.testing.expect; @@ -2301,7 +2399,7 @@ test "pointer child type" { In Zig, a pointer type has an alignment value. If the value is equal to the alignment of the underlying type, it can be omitted from the type:

- {#code_begin|test#} + {#code_begin|test|variable_alignment#} const std = @import("std"); const expect = std.testing.expect; @@ -2323,7 +2421,7 @@ test "variable alignment" { You can specify alignment on variables and functions. If you do this, then pointers to them get the specified alignment:

- {#code_begin|test#} + {#code_begin|test|variable_func_alignment#} const expect = @import("std").testing.expect; var foo: u8 align(4) = 100; @@ -2660,7 +2758,7 @@ test "linked list" { Each struct field may have an expression indicating the default field value. Such expressions are executed at {#link|comptime#}, and allow the field to be omitted in a struct literal expression:

- {#code_begin|test#} + {#code_begin|test|default_field_values#} const Foo = struct { a: i32 = 1234, b: i32, @@ -2709,7 +2807,7 @@ test "default struct initialization fields" { in a {#link|@bitCast#} or a {#link|@ptrCast#} to reinterpret memory. This even works at {#link|comptime#}:

- {#code_begin|test#} + {#code_begin|test|packed_structs#} const std = @import("std"); const native_endian = @import("builtin").target.cpu.arch.endian(); const expect = std.testing.expect; @@ -2750,7 +2848,7 @@ fn doTheTest() !void {

Zig allows the address to be taken of a non-byte-aligned field:

- {#code_begin|test#} + {#code_begin|test|pointer_to_non-byte_aligned_field#} const std = @import("std"); const expect = std.testing.expect; @@ -2806,7 +2904,7 @@ fn bar(x: *const u3) u3 {

Pointers to non-ABI-aligned fields share the same address as the other fields within their host integer:

- {#code_begin|test#} + {#code_begin|test|pointer_to_non-bit_aligned_field#} const std = @import("std"); const expect = std.testing.expect; @@ -2830,7 +2928,7 @@ test "pointer to non-bit-aligned field" {

This can be observed with {#link|@bitOffsetOf#} and {#link|offsetOf#}:

- {#code_begin|test#} + {#code_begin|test|test_bitOffsetOf_offsetOf#} const std = @import("std"); const expect = std.testing.expect; @@ -2875,7 +2973,7 @@ test "overaligned pointer to packed struct" {

It's also possible to set alignment of struct fields:

- {#code_begin|test#} + {#code_begin|test|test_aligned_struct_fields#} const std = @import("std"); const expectEqual = std.testing.expectEqual; @@ -3129,7 +3227,7 @@ export fn entry(foo: Foo) void { _ = foo; }

Enum literals allow specifying the name of an enum field without specifying the enum type:

- {#code_begin|test#} + {#code_begin|test|test_enum_literals#} const std = @import("std"); const expect = std.testing.expect; @@ -3171,7 +3269,7 @@ test "switch using enum literals" { A switch on a non-exhaustive enum can include a '_' prong as an alternative to an {#syntax#}else{#endsyntax#} prong with the difference being that it makes it a compile error if all the known tag names are not handled by the switch.

- {#code_begin|test#} + {#code_begin|test|test_switch_non-exhaustive#} const std = @import("std"); const expect = std.testing.expect; @@ -3224,7 +3322,7 @@ test "simple union" { } {#code_end#}

You can activate another field by assigning the entire union:

- {#code_begin|test#} + {#code_begin|test|test_simple_union#} const std = @import("std"); const expect = std.testing.expect; @@ -3253,7 +3351,7 @@ test "simple union" { to use with {#link|switch#} expressions. Tagged unions coerce to their tag type: {#link|Type Coercion: unions and enums#}.

- {#code_begin|test#} + {#code_begin|test|test_switch_tagged_union#} const std = @import("std"); const expect = std.testing.expect; @@ -3291,7 +3389,7 @@ test "coerce to enum" {

In order to modify the payload of a tagged union in a switch expression, place a {#syntax#}*{#endsyntax#} before the variable name to make it a pointer:

- {#code_begin|test#} + {#code_begin|test|test_switch_modify_tagged_union#} const std = @import("std"); const expect = std.testing.expect; @@ -3320,7 +3418,7 @@ test "modify tagged union in switch" { Unions can be made to infer the enum tag type. Further, unions can have methods just like structs and enums.

- {#code_begin|test#} + {#code_begin|test|test_union_method#} const std = @import("std"); const expect = std.testing.expect; @@ -3352,7 +3450,7 @@ test "union method" { {#link|@tagName#} can be used to return a {#link|comptime#} {#syntax#}[:0]const u8{#endsyntax#} value representing the field name:

- {#code_begin|test#} + {#code_begin|test|test_tagName#} const std = @import("std"); const expect = std.testing.expect; @@ -3377,7 +3475,7 @@ test "@tagName" { {#header_open|packed union#}

A {#syntax#}packed union{#endsyntax#} has well-defined in-memory layout and is eligible - to be in a {#link|packed struct#}. + to be in a {#link|packed struct#}.

{#header_close#} {#header_open|Anonymous Union Literals#} @@ -3448,7 +3546,7 @@ test "access variable after block scope" {

Blocks are expressions. When labeled, {#syntax#}break{#endsyntax#} can be used to return a value from the block:

- {#code_begin|test#} + {#code_begin|test|test_labeled_break#} const std = @import("std"); const expect = std.testing.expect; @@ -3482,7 +3580,7 @@ test "inside test block" { Because of this, when you read Zig code you can rely on an identifier always meaning the same thing, within the scope it is defined. Note that you can, however use the same name if the scopes are separate:

- {#code_begin|test#} + {#code_begin|test|test_scopes#} test "separate scopes" { { const pi = 3.14; @@ -3569,7 +3667,7 @@ test "switch inside function" { done by placing a {#syntax#}*{#endsyntax#} before the capture variable name, turning it into a pointer.

- {#code_begin|test#} + {#code_begin|test|test_switch_tagged_union#} const expect = @import("std").testing.expect; test "switch on tagged union" { @@ -3636,7 +3734,7 @@ test "exhaustive switching" { {#link|Enum Literals#} can be useful to use with {#syntax#}switch{#endsyntax#} to avoid repetitively specifying {#link|enum#} or {#link|union#} types:

- {#code_begin|test#} + {#code_begin|test|test_exhaustive_switch#} const std = @import("std"); const expect = std.testing.expect; @@ -3761,7 +3859,7 @@ fn rangeHasNumber(begin: usize, end: usize, number: usize) bool { {#header_open|Labeled while#}

When a {#syntax#}while{#endsyntax#} loop is labeled, it can be referenced from a {#syntax#}break{#endsyntax#} or {#syntax#}continue{#endsyntax#} from within a nested loop:

- {#code_begin|test#} + {#code_begin|test|test_nested_break#} test "nested break" { outer: while (true) { while (true) { @@ -3866,7 +3964,7 @@ fn eventuallyErrorSequence() anyerror!u32 { allows the code to do some things which only work at compile time, such as use types as first class values.

- {#code_begin|test#} + {#code_begin|test|test_inline_while#} const expect = @import("std").testing.expect; test "inline while loop" { @@ -3969,7 +4067,7 @@ test "for else" { {#header_open|Labeled for#}

When a {#syntax#}for{#endsyntax#} loop is labeled, it can be referenced from a {#syntax#}break{#endsyntax#} or {#syntax#}continue{#endsyntax#} from within a nested loop:

- {#code_begin|test#} + {#code_begin|test|test_nested_break#} const std = @import("std"); const expect = std.testing.expect; @@ -4005,7 +4103,7 @@ test "nested continue" { The capture value and iterator value of inlined for loops are compile-time known.

- {#code_begin|test#} + {#code_begin|test|test_inline_loop#} const expect = @import("std").testing.expect; test "inline for loop" { @@ -4278,16 +4376,16 @@ test "errdefer unwinding" { {#header_close#} {#header_open|unreachable#}

- In {#syntax#}Debug{#endsyntax#} and {#syntax#}ReleaseSafe{#endsyntax#} mode, and when using zig test, + In {#syntax#}Debug{#endsyntax#} and {#syntax#}ReleaseSafe{#endsyntax#} mode, and when using zig test, {#syntax#}unreachable{#endsyntax#} emits a call to {#syntax#}panic{#endsyntax#} with the message reached unreachable code.

In {#syntax#}ReleaseFast{#endsyntax#} mode, the optimizer uses the assumption that {#syntax#}unreachable{#endsyntax#} code - will never be hit to perform optimizations. However, zig test even in {#syntax#}ReleaseFast{#endsyntax#} mode + will never be hit to perform optimizations. However, zig test even in {#syntax#}ReleaseFast{#endsyntax#} mode still emits {#syntax#}unreachable{#endsyntax#} as calls to {#syntax#}panic{#endsyntax#}.

{#header_open|Basics#} - {#code_begin|test#} + {#code_begin|test|test_unreachable#} // unreachable is used to assert that control flow will never happen upon a // particular location: test "basic math" { @@ -4343,7 +4441,7 @@ test "type of unreachable" {

When resolving types together, such as {#syntax#}if{#endsyntax#} clauses or {#syntax#}switch{#endsyntax#} prongs, the {#syntax#}noreturn{#endsyntax#} type is compatible with every other type. Consider:

- {#code_begin|test#} + {#code_begin|test|test_noreturn#} fn foo(condition: bool, b: u32) void { const a = if (condition) b else return; _ = a; @@ -4354,7 +4452,7 @@ test "noreturn" { } {#code_end#}

Another use case for {#syntax#}noreturn{#endsyntax#} is the {#syntax#}exit{#endsyntax#} function:

- {#code_begin|test#} + {#code_begin|test|noreturn_from_exit#} {#target_windows#} pub extern "kernel32" fn ExitProcess(exit_code: c_uint) callconv(if (@import("builtin").target.cpu.arch == .i386) .Stdcall else .C) noreturn; @@ -4451,7 +4549,7 @@ fn foo() void { } as parameters, Zig may choose to copy and pass by value, or pass by reference, whichever way Zig decides will be faster. This is made possible, in part, by the fact that parameters are immutable.

- {#code_begin|test#} + {#code_begin|test|pass_by_reference_or_value#} const Point = struct { x: i32, y: i32, @@ -4481,7 +4579,7 @@ test "pass struct to function" { In this case the parameter types will be inferred when the function is called. Use {#link|@TypeOf#} and {#link|@typeInfo#} to get information about the inferred type.

- {#code_begin|test#} + {#code_begin|test|test_fn_type_inference#} const expect = @import("std").testing.expect; fn addFortyTwo(x: anytype) @TypeOf(x) { @@ -4499,7 +4597,7 @@ test "fn type inference" { {#header_close#} {#header_open|Function Reflection#} - {#code_begin|test#} + {#code_begin|test|test_fn_reflection#} const expect = @import("std").testing.expect; test "fn reflection" { @@ -4524,7 +4622,7 @@ test "fn reflection" {

You can {#link|coerce|Type Coercion#} an error from a subset to a superset:

- {#code_begin|test#} + {#code_begin|test|coercing_subset_to_superset#} const std = @import("std"); const FileOpenError = error { @@ -4608,7 +4706,7 @@ const err = (error {FileNotFound}).FileNotFound;

Here is a function to parse a string into a 64-bit integer:

- {#code_begin|test#} + {#code_begin|test|error_union_parsing_u64#} const std = @import("std"); const maxInt = std.math.maxInt; @@ -4791,7 +4889,7 @@ fn createFoo(param: i32) !Foo {

An error union is created with the {#syntax#}!{#endsyntax#} binary operator. You can use compile-time reflection to access the child type of an error union:

- {#code_begin|test#} + {#code_begin|test|test_error_union#} const expect = @import("std").testing.expect; test "error union" { @@ -4823,7 +4921,7 @@ test "error union" { {#syntax#}LinuxFileOpenError || WindowsFileOpenError{#endsyntax#} for the error set of opening files.

- {#code_begin|test#} + {#code_begin|test|test_merging_error_sets#} const A = error{ NotDir, @@ -4859,7 +4957,7 @@ test "merge error sets" { Because many functions in Zig return a possible error, Zig supports inferring the error set. To infer the error set for a function, use this syntax:

-{#code_begin|test#} +{#code_begin|test|inferred_error_sets#} // With an inferred error set pub fn add_inferred(comptime T: type, a: T, b: T) !T { var answer: T = undefined; @@ -5173,7 +5271,7 @@ fn doAThing(optional_foo: ?*Foo) void { {#header_open|Optional Type#}

An optional is created by putting {#syntax#}?{#endsyntax#} in front of a type. You can use compile-time reflection to access the child type of an optional:

- {#code_begin|test#} + {#code_begin|test|test_optional_type#} const expect = @import("std").testing.expect; test "optional type" { @@ -5200,7 +5298,7 @@ const optional_value: ?i32 = null; {#header_open|Optional Pointers#}

An optional pointer is guaranteed to be the same size as a pointer. The {#syntax#}null{#endsyntax#} of the optional is guaranteed to be address 0.

- {#code_begin|test#} + {#code_begin|test|test_optional_pointer#} const expect = @import("std").testing.expect; test "optional pointers" { @@ -5232,7 +5330,7 @@ test "optional pointers" {

Type coercion occurs when one type is expected, but different type is provided:

- {#code_begin|test#} + {#code_begin|test|type_coercion#} test "type coercion - variable declaration" { var a: u8 = 1; var b: u16 = a; @@ -5272,7 +5370,7 @@ test "type coercion - @as builtin" {

These casts are no-ops at runtime since the value representation does not change.

- {#code_begin|test#} + {#code_begin|test|no_op_casts#} test "type coercion - const qualification" { var a: i32 = 1; var b: *i32 = &a; @@ -5284,7 +5382,7 @@ fn foo(_: *const i32) void {}

In addition, pointers coerce to const optional pointers:

- {#code_begin|test#} + {#code_begin|test|pointer_coerce_const_optional#} const std = @import("std"); const expect = std.testing.expect; const mem = std.mem; @@ -5301,7 +5399,7 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" { {#link|Integers#} coerce to integer types which can represent every value of the old type, and likewise {#link|Floats#} coerce to float types which can represent every value of the old type.

- {#code_begin|test#} + {#code_begin|test|test_integer_widening#} const std = @import("std"); const expect = std.testing.expect; const mem = std.mem; @@ -5429,7 +5527,7 @@ test "*T to *[1]T" {

The payload type of {#link|Optionals#}, as well as {#link|null#}, coerce to the optional type.

- {#code_begin|test#} + {#code_begin|test|test_coerce_optionals#} const std = @import("std"); const expect = std.testing.expect; @@ -5442,7 +5540,7 @@ test "coerce to optionals" { } {#code_end#}

It works nested inside the {#link|Error Union Type#}, too:

- {#code_begin|test#} + {#code_begin|test|test_corerce_optional_wrapped_error_union#} const std = @import("std"); const expect = std.testing.expect; @@ -5459,7 +5557,7 @@ test "coerce to optionals wrapped in error union" {

The payload type of an {#link|Error Union Type#} as well as the {#link|Error Set Type#} coerce to the error union type:

- {#code_begin|test#} + {#code_begin|test|test_coerce_to_error_union#} const std = @import("std"); const expect = std.testing.expect; @@ -5476,7 +5574,7 @@ test "coercion to error unions" {

When a number is {#link|comptime#}-known to be representable in the destination type, it may be coerced:

- {#code_begin|test#} + {#code_begin|test|test_coerce_large_to_small#} const std = @import("std"); const expect = std.testing.expect; @@ -5492,7 +5590,7 @@ test "coercing large integer type to smaller one when value is comptime known to when they are {#link|comptime#}-known to be a field of the union that has only one possible value, such as {#link|void#}:

- {#code_begin|test#} + {#code_begin|test|test_coerce_unions_enums#} const std = @import("std"); const expect = std.testing.expect; @@ -5525,7 +5623,7 @@ test "coercion between unions and enums" { regardless of const.

TODO document the reasoning for this

TODO document whether vice versa should work and why

- {#code_begin|test#} + {#code_begin|test|coerce_zero_bit_types#} test "coercion of zero bit types" { var x: void = {}; var y: *void = x; @@ -5715,7 +5813,7 @@ export fn entry() void { {#syntax#}Map(Key, Value){#endsyntax#}, one can pass {#syntax#}void{#endsyntax#} for the {#syntax#}Value{#endsyntax#} type to make it into a {#syntax#}Set{#endsyntax#}:

- {#code_begin|test#} + {#code_begin|test|void_in_hashmap#} const std = @import("std"); const expect = std.testing.expect; @@ -5755,7 +5853,7 @@ fn foo() i32 { } {#code_end#}

However, if the expression has type {#syntax#}void{#endsyntax#}, there will be no error. Function return values can also be explicitly ignored by assigning them to {#syntax#}_{#endsyntax#}.

- {#code_begin|test#} + {#code_begin|test|void_ignored#} test "void is ignored" { returnsVoid(); } @@ -5774,7 +5872,7 @@ fn foo() i32 { {#header_open|Pointers to Zero Bit Types#}

Pointers to zero bit types also have zero bits. They always compare equal to each other:

- {#code_begin|test#} + {#code_begin|test|pointers_to_zero_bits#} const std = @import("std"); const expect = std.testing.expect; @@ -5826,10 +5924,10 @@ test "using std namespace" { {#code_end#}

{#syntax#}usingnamespace{#endsyntax#} has an important use case when organizing the public - API of a file or package. For example, one might have c.zig with all of the + API of a file or package. For example, one might have c.zig with all of the {#link|C imports|Import from C Header File#}:

-
{#syntax#}
+      {#syntax_block|zig|c.zig#}
 pub usingnamespace @cImport({
     @cInclude("epoxy/gl.h");
     @cInclude("GLFW/glfw3.h");
@@ -5837,7 +5935,7 @@ pub usingnamespace @cImport({
     @cDefine("STBI_NO_STDIO", "");
     @cInclude("stb_image.h");
 });
-      {#endsyntax#}
+ {#end_syntax_block#}

The above example demonstrates using {#syntax#}pub{#endsyntax#} to qualify the {#syntax#}usingnamespace{#endsyntax#} additionally makes the imported declarations @@ -5923,7 +6021,7 @@ test "try to compare bools" { value is known at compile-time. This means that we actually could make this work for the bool type if we wanted to:

- {#code_begin|test#} + {#code_begin|test|comptime_max_with_bool#} fn max(comptime T: type, a: T, b: T) T { if (T == bool) { return a or b; @@ -6086,7 +6184,7 @@ test "foo" {

Let's look at an example:

- {#code_begin|test#} + {#code_begin|test|fibonacci_recursion#} const expect = @import("std").testing.expect; fn fibonacci(index: u32) u32 { @@ -6179,7 +6277,7 @@ test "fibonacci" { {#syntax#}comptime{#endsyntax#} expressions. This means that we can use functions to initialize complex static data. For example:

- {#code_begin|test#} + {#code_begin|test|N_primes#} const first_25_primes = firstNPrimes(25); const sum_of_first_25_primes = sum(&first_25_primes); @@ -6480,7 +6578,7 @@ pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {

Dissecting the syntax:

-
{#syntax#}// Inline assembly is an expression which returns a value.
+      {#syntax_block|zig|Assembly Syntax Explained#}// Inline assembly is an expression which returns a value.
 // the `asm` keyword begins the expression.
 _ = asm
 // `volatile` is an optional modifier that tells Zig this
@@ -6535,7 +6633,7 @@ volatile (
 // output. In this example we list $rcx and $r11 because it is known the
 // kernel syscall does not preserve these registers.
     : "rcx", "r11"
-);{#endsyntax#}
+);{#end_syntax_block#}

For i386 and x86_64 targets, the syntax is AT&T syntax, rather than the more popular Intel syntax. This is due to technical constraints; assembly parsing is @@ -6661,7 +6759,7 @@ test "global assembly" { return to the callsite (in the case of the first suspension), or resumer (in the case of subsequent suspensions).

- {#code_begin|test#} + {#code_begin|test|suspend_no_resume#} const std = @import("std"); const expect = std.testing.expect; @@ -6688,7 +6786,7 @@ fn func() void { {#syntax#}resume{#endsyntax#} operation on a different thread. {#link|@frame#} provides access to the async function frame pointer.

- {#code_begin|test#} + {#code_begin|test|async_suspend_block#} const std = @import("std"); const expect = std.testing.expect; @@ -6726,7 +6824,7 @@ fn testSuspendBlock() void { However, the async function can be directly resumed from the suspend block, in which case it never returns to its resumer and continues executing.

- {#code_begin|test#} + {#code_begin|test|resume_from_suspend#} const std = @import("std"); const expect = std.testing.expect; @@ -6762,7 +6860,7 @@ fn testResumeFromSuspend(my_result: *i32) void { execution would continue at the most recent {#syntax#}async{#endsyntax#} callsite or {#syntax#}resume{#endsyntax#} callsite, and the return value of the async function would be lost.

- {#code_begin|test#} + {#code_begin|test|async_await#} const std = @import("std"); const expect = std.testing.expect; @@ -6806,7 +6904,7 @@ fn func() void { does not suspend; instead it copies the return value directly from the target function's frame.

- {#code_begin|test#} + {#code_begin|test|async_await_sequence#} const std = @import("std"); const expect = std.testing.expect; @@ -7084,7 +7182,7 @@ comptime { read after {#link|await|Async and Await#} completes. Any result location provided to {#syntax#}await{#endsyntax#} will copy the result from {#syntax#}result_ptr{#endsyntax#}.

- {#code_begin|test#} + {#code_begin|test|async_struct_field_fn_pointer#} const std = @import("std"); const expect = std.testing.expect; @@ -7526,7 +7624,7 @@ test "main" { not encountered by analysis, the program compiles successfully and the generated executable prints:

- {#code_begin|test#} + {#code_begin|test|without_compileLog#} const print = @import("std").debug.print; const num1 = blk: { @@ -7758,7 +7856,7 @@ export fn @"A function name that is a complete sentence."() void {}
{#syntax#}@field(lhs: anytype, comptime field_name: []const u8) (field){#endsyntax#}

Performs field access by a compile-time string. Works on both fields and declarations.

- {#code_begin|test#} + {#code_begin|test|field_decl_access_by_string#} const std = @import("std"); const Point = struct { @@ -7843,7 +7941,7 @@ test "decl access by string" { This type is suitable to be used as the return type of {#link|async|Async and Await#} which allows one to, for example, heap-allocate an async function frame:

- {#code_begin|test#} + {#code_begin|test|heap_allocated_frame#} const std = @import("std"); test "heap allocated frame" { @@ -7889,7 +7987,7 @@ fn func() void { Returns whether or not a {#link|struct#}, {#link|enum#}, or {#link|union#} has a declaration matching {#syntax#}name{#endsyntax#}.

- {#code_begin|test#} + {#code_begin|test|hasDecl#} const std = @import("std"); const expect = std.testing.expect; @@ -8104,7 +8202,7 @@ mem.set(u8, dest, c);{#endsyntax#} designers targeting Wasm. So unless you are writing a new allocator from scratch, you should use something like {#syntax#}@import("std").heap.WasmPageAllocator{#endsyntax#}.

- {#code_begin|test#} + {#code_begin|test|wasmMemoryGrow#} const std = @import("std"); const native_arch = @import("builtin").target.cpu.arch; const expect = std.testing.expect; @@ -8291,7 +8389,7 @@ test "foo" { } {#code_end#}

Now we use {#syntax#}@setEvalBranchQuota{#endsyntax#}:

- {#code_begin|test#} + {#code_begin|test|setEvalBranchQuota#} test "foo" { comptime { @setEvalBranchQuota(1001); @@ -8490,7 +8588,7 @@ test "@setRuntimeSafety" { Produces a vector of length {#syntax#}len{#endsyntax#} where each element is the value {#syntax#}scalar{#endsyntax#}:

- {#code_begin|test#} + {#code_begin|test|vector_splat#} const std = @import("std"); const expect = std.testing.expect; @@ -8524,7 +8622,7 @@ test "vector @splat" {
  • {#syntax#}.Min{#endsyntax#}, {#syntax#}.Max{#endsyntax#}, {#syntax#}.Add{#endsyntax#}, {#syntax#}.Mul{#endsyntax#} are available for {#link|floating point|Floats#} vectors,
  • -
  • Every operator is available for {#link|integer|Integers#} vectors. +
  • Every operator is available for {#link|integer|Integers#} vectors.
  • Note that {#syntax#}.Add{#endsyntax#} and {#syntax#}.Mul{#endsyntax#} @@ -8532,7 +8630,7 @@ test "vector @splat" { types the operation associativity is preserved, unless the float mode is set to {#syntax#}Optimized{#endsyntax#}.

    - {#code_begin|test#} + {#code_begin|test|vector_reduce#} const std = @import("std"); const expect = std.testing.expect; @@ -8554,7 +8652,7 @@ test "vector @reduce" {

    Returns a {#syntax#}SourceLocation{#endsyntax#} struct representing the function's name and location in the source code. This must be called in a function.

    - {#code_begin|test#} + {#code_begin|test|source_location#} const std = @import("std"); const expect = std.testing.expect; @@ -8568,7 +8666,7 @@ fn doTheTest() !void { try expect(src.line == 9); try expect(src.column == 17); try expect(std.mem.endsWith(u8, src.fn_name, "doTheTest")); - try expect(std.mem.endsWith(u8, src.file, "test.zig")); + try expect(std.mem.endsWith(u8, src.file, "source_location.zig")); } {#code_end#} {#header_close#} @@ -8749,7 +8847,7 @@ fn doTheTest() !void { Returns the innermost struct, enum, or union that this function call is inside. This can be useful for an anonymous struct that needs to refer to itself:

    - {#code_begin|test#} + {#code_begin|test|this_innermost#} const std = @import("std"); const expect = std.testing.expect; @@ -8884,7 +8982,7 @@ test "integer truncation" {

    The expressions are evaluated, however they are guaranteed to have no runtime side-effects:

    - {#code_begin|test#} + {#code_begin|test|no_runtime_side_effects#} const std = @import("std"); const expect = std.testing.expect; @@ -8925,9 +9023,9 @@ fn foo(comptime T: type, ptr: *T) T {
  • {#link|ReleaseSmall#}
  • - To add standard build options to a build.zig file: + To add standard build options to a build.zig file:

    - {#code_begin|syntax#} + {#code_begin|syntax|build#} const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { @@ -8939,11 +9037,13 @@ pub fn build(b: *Builder) void {

    This causes these options to be available:

    -
      -Drelease-safe=[bool] optimizations on and safety on
    -  -Drelease-fast=[bool] optimizations on and safety off
    -  -Drelease-small=[bool] size optimizations on and safety off
    +
    +
    -Drelease-safe=[bool]
    Optimizations on and safety on
    +
    -Drelease-fast=[bool]
    Optimizations on and safety off
    +
    -Drelease-small=[bool]
    Size optimizations on and safety off
    +
    {#header_open|Debug#} -
    $ zig build-exe example.zig
    + {#shell_samp#}$ zig build-exe example.zig{#end_shell_samp#}
    • Fast compilation speed
    • Safety checks enabled
    • @@ -8953,7 +9053,7 @@ pub fn build(b: *Builder) void {
    {#header_close#} {#header_open|ReleaseFast#} -
    $ zig build-exe example.zig -O ReleaseFast
    + {#shell_samp#}$ zig build-exe example.zig -O ReleaseFast{#end_shell_samp#}
    • Fast runtime performance
    • Safety checks disabled
    • @@ -8963,7 +9063,7 @@ pub fn build(b: *Builder) void {
    {#header_close#} {#header_open|ReleaseSafe#} -
    $ zig build-exe example.zig -O ReleaseSafe
    + {#shell_samp#}$ zig build-exe example.zig -O ReleaseSafe{#end_shell_samp#}
    • Medium runtime performance
    • Safety checks enabled
    • @@ -8973,7 +9073,7 @@ pub fn build(b: *Builder) void {
    {#header_close#} {#header_open|ReleaseSmall#} -
    $ zig build-exe example.zig -O ReleaseSmall
    + {#shell_samp#}$ zig build-exe example.zig -O ReleaseSmall{#end_shell_samp#}
    • Medium runtime performance
    • Safety checks disabled
    • @@ -8986,7 +9086,7 @@ pub fn build(b: *Builder) void { {#header_close#} {#header_open|Single Threaded Builds#} -

      Zig has a compile option --single-threaded which has the following effects:

      +

      Zig has a compile option --single-threaded which has the following effects:

      • All {#link|Thread Local Variables#} are treated as regular {#link|Container Level Variables#}.
      • The overhead of {#link|Async Functions#} becomes equivalent to function call overhead.
      • @@ -9197,7 +9297,7 @@ pub fn main() void {
      • {#syntax#}-%{#endsyntax#} (wraparound negation)
      • {#syntax#}*%{#endsyntax#} (wraparound multiplication)
      - {#code_begin|test#} + {#code_begin|test|wraparound_semantics#} const std = @import("std"); const expect = std.testing.expect; const minInt = std.math.minInt; @@ -9935,14 +10035,14 @@ const separator = if (builtin.os.tag == builtin.Os.windows) '\\' else '/';
    • Custom tasks.

    - To use the build system, run zig build --help + To use the build system, run zig build --help to see a command-line usage help menu. This will include project-specific options that were declared in the build.zig script.

    {#header_open|Building an Executable#} -

    This build.zig file is automatically generated - by zig init-exe.

    +

    This build.zig file is automatically generated + by zig init-exe.

    {#code_begin|syntax|build#} const Builder = @import("std").build.Builder; @@ -9975,8 +10075,8 @@ pub fn build(b: *Builder) void { {#header_close#} {#header_open|Building a Library#} -

    This build.zig file is automatically generated - by zig init-lib.

    +

    This build.zig file is automatically generated + by zig init-lib.

    {#code_begin|syntax|build#} const Builder = @import("std").build.Builder; @@ -10035,7 +10135,7 @@ lib.addCSourceFile("src/lib.c", &[_][]const u8{ {#header_open|Import from C Header File#}

    The {#syntax#}@cImport{#endsyntax#} builtin function can be used - to directly import symbols from .h files: + to directly import symbols from .h files:

    {#code_begin|exe#} {#link_libc#} @@ -10051,7 +10151,7 @@ pub fn main() void {

    The {#syntax#}@cImport{#endsyntax#} function takes an expression as a parameter. This expression is evaluated at compile-time and is used to control - preprocessor directives and include multiple .h files: + preprocessor directives and include multiple .h files:

    {#code_begin|syntax#} const builtin = @import("builtin"); @@ -10072,66 +10172,65 @@ const c = @cImport({ {#header_close#} {#header_open|C Translation CLI#} - Zig's C translation capability is available as a CLI tool via zig translate-c. + Zig's C translation capability is available as a CLI tool via zig translate-c. It requires a single filename as an argument. It may also take a set of optional flags that are forwarded to clang. It writes the translated file to stdout. {#header_open|Command line flags#}
    • - -I: + -I: Specify a search directory for include files. May be used multiple times. Equivalent to - clang's -I flag. The current directory is not included by default; - use -I. to include it. + clang's -I flag. The current directory is not included by default; + use -I. to include it.
    • - -D: Define a preprocessor macro. Equivalent to + -D: Define a preprocessor macro. Equivalent to - clang's -D flag. + clang's -D flag.
    • - -cflags [flags] --: Pass arbitrary additional + -cflags [flags] --: Pass arbitrary additional command line - flags to clang. Note: the list of flags must end with -- + flags to clang. Note: the list of flags must end with --
    • - -target: The {#link|target triple|Targets#} for the translated Zig code. + -target: The {#link|target triple|Targets#} for the translated Zig code. If no target is specified, the current host target will be used.
    {#header_close#} {#header_open|Using -target and -cflags#}

    - Important! When translating C code with zig translate-c, - you must use the same -target triple that you will use when compiling - the translated code. In addition, you must ensure that the -cflags used, - if any, match the cflags used by code on the target system. Using the incorrect -target - or -cflags could result in clang or Zig parse failures, or subtle ABI incompatibilities + Important! When translating C code with zig translate-c, + you must use the same -target triple that you will use when compiling + the translated code. In addition, you must ensure that the -cflags used, + if any, match the cflags used by code on the target system. Using the incorrect -target + or -cflags could result in clang or Zig parse failures, or subtle ABI incompatibilities when linking with C code.

    -

    varytarget.h

    -
    long FOO = __LONG_MAX__;
    -
    $ zig translate-c -target thumb-freestanding-gnueabihf varytarget.h|grep FOO
    -pub export var FOO: c_long = 2147483647;
    -
    $ zig translate-c -target x86_64-macos-gnu varytarget.h|grep FOO
    -pub export var FOO: c_long = 9223372036854775807;
    -

    varycflags.h

    -
    enum FOO { BAR };
    -int do_something(enum FOO foo);
    -
    $ zig translate-c varycflags.h|grep -B1 do_something
    -pub const enum_FOO = c_uint;
    -pub extern fn do_something(foo: enum_FOO) c_int;
    -
    $ zig translate-c -cflags -fshort-enums -- varycflags.h|grep -B1 do_something
    -pub const enum_FOO = u8;
    -pub extern fn do_something(foo: enum_FOO) c_int;
    + {#syntax_block|c|varytarget.h#}long FOO = __LONG_MAX__;{#end_syntax_block#} + {#shell_samp#}$ zig translate-c -target thumb-freestanding-gnueabihf varytarget.h|grep FOO +pub export var FOO: c_long = 2147483647; +$ zig translate-c -target x86_64-macos-gnu varytarget.h|grep FOO +pub export var FOO: c_long = 9223372036854775807;{#end_shell_samp#} + {#syntax_block|c|varycflags.h#}enum FOO { BAR }; +int do_something(enum FOO foo); + {#end_syntax_block#} + {#shell_samp#}$ zig translate-c varycflags.h|grep -B1 do_something +pub const enum_FOO = c_uint; +pub extern fn do_something(foo: enum_FOO) c_int; +$ zig translate-c -cflags -fshort-enums -- varycflags.h|grep -B1 do_something +pub const enum_FOO = u8; +pub extern fn do_something(foo: enum_FOO) c_int;{#end_shell_samp#} {#header_close#} {#header_open|@cImport vs translate-c#} -

    {#syntax#}@cImport{#endsyntax#} and zig translate-c use the same underlying +

    {#syntax#}@cImport{#endsyntax#} and zig translate-c use the same underlying C translation functionality, so on a technical level they are equivalent. In practice, {#syntax#}@cImport{#endsyntax#} is useful as a way to quickly and easily access numeric constants, typedefs, and record types without needing any extra setup. If you need to pass {#link|cflags|Using -target and -cflags#} to clang, or if you would like to edit the translated code, it is recommended to use - zig translate-c and save the results to a file. Common reasons for editing + zig translate-c and save the results to a file. Common reasons for editing the generated code include: changing {#syntax#}anytype{#endsyntax#} parameters in function-like macros to more specific types; changing {#syntax#}[*c]T{#endsyntax#} pointers to {#syntax#}[*]T{#endsyntax#} or {#syntax#}*T{#endsyntax#} pointers for improved type safety; and @@ -10142,14 +10241,14 @@ pub extern fn do_something(foo: enum_FOO) c_int; {#header_close#} {#header_open|C Translation Caching#}

    - The C translation feature (whether used via zig translate-c or + The C translation feature (whether used via zig translate-c or {#syntax#}@cImport{#endsyntax#}) integrates with the Zig caching system. Subsequent runs with the same source file, target, and cflags will use the cache instead of repeatedly translating the same code.

    To see where the cached files are stored when compiling code that uses {#syntax#}@cImport{#endsyntax#}, - use the --verbose-cimport flag: + use the --verbose-cimport flag:

    {#code_begin|exe|verbose#} {#link_libc#} @@ -10163,10 +10262,10 @@ pub fn main() void { } {#code_end#}

    - cimport.h contains the file to translate (constructed from calls to + cimport.h contains the file to translate (constructed from calls to {#syntax#}@cInclude{#endsyntax#}, {#syntax#}@cDefine{#endsyntax#}, and {#syntax#}@cUndef{#endsyntax#}), - cimport.h.d is the list of file dependencies, and - cimport.zig contains the translated output. + cimport.h.d is the list of file dependencies, and + cimport.zig contains the translated output.

    {#see_also|Import from C Header File|C Translation CLI|@cInclude|@cImport#} {#header_close#} @@ -10206,22 +10305,22 @@ pub fn main() void { Zig.

    Consider the following example:

    -

    macro.c

    -
    #define MAKELOCAL(NAME, INIT) int NAME = INIT
    +      {#syntax_block|c|macro.c#}#define MAKELOCAL(NAME, INIT) int NAME = INIT
     int foo(void) {
        MAKELOCAL(a, 1);
        MAKELOCAL(b, 2);
        return a + b;
    -}
    -
    $ zig translate-c macro.c > macro.zig
    -
    -

    macro.zig

    -
    {#syntax#}pub export fn foo() c_int {
    +}
    +      {#end_syntax_block#}
    +      {#shell_samp#}$ zig translate-c macro.c > macro.zig{#end_shell_samp#}
    +      {#code_begin|syntax|macro#}
    +pub export fn foo() c_int {
         var a: c_int = 1;
         var b: c_int = 2;
         return a + b;
     }
    -pub const MAKELOCAL = @compileError("unable to translate C expr: unexpected token .Equal"); // macro.c:1:9{#endsyntax#}
    +pub const MAKELOCAL = @compileError("unable to translate C expr: unexpected token .Equal"); // macro.c:1:9 + {#code_end#}

    Note that {#syntax#}foo{#endsyntax#} was translated correctly despite using a non-translateable macro. {#syntax#}MAKELOCAL{#endsyntax#} was demoted to {#syntax#}@compileError{#endsyntax#} since it cannot be expressed as a Zig function; this simply means that you cannot directly use @@ -10272,31 +10371,27 @@ pub const MAKELOCAL = @compileError("unable to translate C expr: unexpected toke to call into. The {#syntax#}export{#endsyntax#} keyword in front of functions, variables, and types causes them to be part of the library API:

    -

    mathtest.zig

    - {#code_begin|syntax#} + {#code_begin|syntax|mathtest#} export fn add(a: i32, b: i32) i32 { return a + b; } {#code_end#}

    To make a static library:

    -
    $ zig build-lib mathtest.zig
    -
    + {#shell_samp#}$ zig build-lib mathtest.zig{#end_shell_samp#}

    To make a shared library:

    -
    $ zig build-lib mathtest.zig -dynamic
    -
    + {#shell_samp#}$ zig build-lib mathtest.zig -dynamic{#end_shell_samp#}

    Here is an example with the {#link|Zig Build System#}:

    -

    test.c

    -
    // This header is generated by zig from mathtest.zig
    +      {#syntax_block|c|test.c#}// This header is generated by zig from mathtest.zig
     #include "mathtest.h"
    -#include <stdio.h>
    +#include 
     
     int main(int argc, char **argv) {
         int32_t result = add(42, 1337);
         printf("%d\n", result);
         return 0;
    -}
    -

    build.zig

    - {#code_begin|syntax#} +} + {#end_syntax_block#} + {#code_begin|syntax|build#} const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { @@ -10315,18 +10410,15 @@ pub fn build(b: *Builder) void { test_step.dependOn(&run_cmd.step); } {#code_end#} -

    terminal

    -
    $ zig build test
    -1379
    -
    + {#shell_samp#}$ zig build test +1379{#end_shell_samp#} {#see_also|export#} {#header_close#} {#header_open|Mixing Object Files#}

    You can mix Zig object files with any other object files that respect the C ABI. Example:

    -

    base64.zig

    - {#code_begin|syntax#} + {#code_begin|syntax|base64#} const base64 = @import("std").base64; export fn decode_base_64( @@ -10343,12 +10435,11 @@ export fn decode_base_64( return decoded_size; } {#code_end#} -

    test.c

    -
    // This header is generated by zig from base64.zig
    +      {#syntax_block|c|test.c#}// This header is generated by zig from base64.zig
     #include "base64.h"
     
    -#include <string.h>
    -#include <stdio.h>
    +#include 
    +#include 
     
     int main(int argc, char **argv) {
         const char *encoded = "YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz";
    @@ -10359,9 +10450,9 @@ int main(int argc, char **argv) {
         puts(buf);
     
         return 0;
    -}
    -

    build.zig

    - {#code_begin|syntax#} +} + {#end_syntax_block#} + {#code_begin|syntax|build#} const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { @@ -10374,10 +10465,9 @@ pub fn build(b: *Builder) void { exe.install(); } {#code_end#} -

    terminal

    -
    $ zig build
    +      {#shell_samp#}$ zig build
     $ ./zig-out/bin/test
    -all your base are belong to us
    +all your base are belong to us{#end_shell_samp#} {#see_also|Targets|Zig Build System#} {#header_close#} {#header_close#} @@ -10395,9 +10485,7 @@ export fn add(a: i32, b: i32) void { print(a + b); } {#code_end#} - {#header_close#} -

    test.js

    -
    const fs = require('fs');
    +      {#syntax_block|javascript|test.js#}const fs = require('fs');
     const source = fs.readFileSync("./math.wasm");
     const typedArray = new Uint8Array(source);
     
    @@ -10407,9 +10495,10 @@ WebAssembly.instantiate(typedArray, {
       }}).then(result => {
       const add = result.instance.exports.add;
       add(1, 2);
    -});
    -
    $ node test.js
    -The result is 3
    +});{#end_syntax_block#} + {#shell_samp#}$ node test.js +The result is 3{#end_shell_samp#} + {#header_close#} {#header_open|WASI#}

    Zig's support for WebAssembly System Interface (WASI) is under active development. Example of using the standard library and reading command line arguments:

    @@ -10428,10 +10517,10 @@ pub fn main() !void { } } {#code_end#} -
    $ wasmtime args.wasm 123 hello
    +      {#shell_samp#}$ wasmtime args.wasm 123 hello
     0: args.wasm
     1: 123
    -2: hello
    +2: hello{#end_shell_samp#}

    A more interesting example would be extracting the list of preopens from the runtime. This is now supported in the standard library via {#syntax#}std.fs.wasi.PreopenList{#endsyntax#}:

    {#code_begin|exe|preopens#} @@ -10453,9 +10542,9 @@ pub fn main() !void { } } {#code_end#} -
    $ wasmtime --dir=. preopens.wasm
    +      {#shell_samp#}$ wasmtime --dir=. preopens.wasm
     0: Preopen{ .fd = 3, .type = PreopenType{ .Dir = '.' } }
    -
    + {#end_shell_samp#} {#header_close#} {#header_close#} {#header_open|Targets#} @@ -10464,7 +10553,7 @@ pub fn main() !void { what it looks like to execute zig targets on a Linux x86_64 computer:

    -
    $ zig targets
    +      {#shell_samp#}$ zig targets
     Architectures:
       arm
         v8_4a
    @@ -10701,7 +10790,7 @@ Available libcs:
       wasm32-wasi-musl
       x86_64-linux-gnu
       x86_64-linux-gnux32
    -  x86_64-linux-musl
    + x86_64-linux-musl{#end_shell_samp#}

    The Zig Standard Library ({#syntax#}@import("std"){#endsyntax#}) has architecture, environment, and operating system abstractions, and thus takes additional work to support more platforms. @@ -10771,9 +10860,9 @@ coding style.

    File names fall into two categories: types and namespaces. If the file (implicitly a struct) has top level fields, it should be named like any - other struct with fields using {#syntax#}TitleCase{#endsyntax#}. Otherwise, - it should use {#syntax#}snake_case{#endsyntax#}. Directory names should be - {#syntax#}snake_case{#endsyntax#}. + other struct with fields using TitleCase. Otherwise, + it should use snake_case. Directory names should be + snake_case.

    These are general rules of thumb; if it makes sense to do something different, @@ -10782,7 +10871,7 @@ coding style.

    {#header_close#} {#header_open|Examples#} -
    {#syntax#}
    +      {#syntax_block|zig|style_example.zig#}
     const namespace_name = @import("dir_name/file_name.zig");
     const TypeName = @import("dir_name/TypeName.zig");
     var global_var: i32 = undefined;
    @@ -10826,9 +10915,9 @@ const XmlParser = struct {
     
     // The initials BE (Big Endian) are just another word in Zig identifier names.
     fn readU32Be() u32 {}
    -      {#endsyntax#}
    + {#end_syntax_block#}

    - See the Zig Standard Library for more examples. + See the {#link|Zig Standard Library#} for more examples.

    {#header_close#} {#header_open|Doc Comment Guidance#} @@ -10863,7 +10952,7 @@ fn readU32Be() u32 {} but use of hard tabs is discouraged. See {#link|Grammar#}.

    - Note that running zig fmt on a source file will implement all recommendations mentioned here. + Note that running zig fmt on a source file will implement all recommendations mentioned here. Note also that the stage1 compiler does not yet support CR or HT control characters.

    @@ -10881,18 +10970,18 @@ fn readU32Be() u32 {} {#header_open|Keyword Reference#}

    + + - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
    Keywords
    - Keyword - - Description - KeywordDescription
    +
    {#syntax#}align{#endsyntax#}
    - +
    {#syntax#}align{#endsyntax#} can be used to specify the alignment of a pointer. It can also be used after a variable or function declaration to specify the alignment of pointers to that variable or function. @@ -10902,9 +10991,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}allowzero{#endsyntax#}
    - +
    The pointer attribute {#syntax#}allowzero{#endsyntax#} allows a pointer to have address zero.
      @@ -10913,9 +11002,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}and{#endsyntax#}
    - +
    The boolean operator {#syntax#}and{#endsyntax#}.
      @@ -10924,9 +11013,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}anyframe{#endsyntax#}
    - +
    {#syntax#}anyframe{#endsyntax#} can be used as a type for variables which hold pointers to function frames.
      @@ -10935,9 +11024,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}anytype{#endsyntax#}
    - +
    Function parameters and struct fields can be declared with {#syntax#}anytype{#endsyntax#} in place of the type. The type will be inferred where the function is called or the struct is instantiated. @@ -10947,9 +11036,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}asm{#endsyntax#}
    - +
    {#syntax#}asm{#endsyntax#} begins an inline assembly expression. This allows for directly controlling the machine code generated on compilation.
      @@ -10958,9 +11047,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}async{#endsyntax#}
    - +
    {#syntax#}async{#endsyntax#} can be used before a function call to get a pointer to the function's frame when it suspends.
      @@ -10969,9 +11058,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}await{#endsyntax#}
    - +
    {#syntax#}await{#endsyntax#} can be used to suspend the current function until the frame provided after the {#syntax#}await{#endsyntax#} completes. {#syntax#}await{#endsyntax#} copies the value returned from the target function's frame to the caller. @@ -10981,9 +11070,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}break{#endsyntax#}
    - +
    {#syntax#}break{#endsyntax#} can be used with a block label to return a value from the block. It can also be used to exit a loop before iteration completes naturally. @@ -10993,9 +11082,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}catch{#endsyntax#}
    - +
    {#syntax#}catch{#endsyntax#} can be used to evaluate an expression if the expression before it evaluates to an error. The expression after the {#syntax#}catch{#endsyntax#} can optionally capture the error value. @@ -11005,9 +11094,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}comptime{#endsyntax#}
    - +
    {#syntax#}comptime{#endsyntax#} before a declaration can be used to label variables or function parameters as known at compile time. It can also be used to guarantee an expression is run at compile time. @@ -11017,9 +11106,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}const{#endsyntax#}
    - +
    {#syntax#}const{#endsyntax#} declares a variable that can not be modified. Used as a pointer attribute, it denotes the value referenced by the pointer cannot be modified. @@ -11029,9 +11118,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}continue{#endsyntax#}
    - +
    {#syntax#}continue{#endsyntax#} can be used in a loop to jump back to the beginning of the loop.
      @@ -11040,9 +11129,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}defer{#endsyntax#}
    - +
    {#syntax#}defer{#endsyntax#} will execute an expression when control flow leaves the current block.
      @@ -11051,9 +11140,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}else{#endsyntax#}
    - +
    {#syntax#}else{#endsyntax#} can be used to provide an alternate branch for {#syntax#}if{#endsyntax#}, {#syntax#}switch{#endsyntax#}, {#syntax#}while{#endsyntax#}, and {#syntax#}for{#endsyntax#} expressions. @@ -11066,9 +11155,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}enum{#endsyntax#}
    - +
    {#syntax#}enum{#endsyntax#} defines an enum type.
      @@ -11077,9 +11166,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}errdefer{#endsyntax#}
    - +
    {#syntax#}errdefer{#endsyntax#} will execute an expression when control flow leaves the current block if the function returns an error.
      @@ -11088,9 +11177,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}error{#endsyntax#}
    - +
    {#syntax#}error{#endsyntax#} defines an error type.
      @@ -11099,9 +11188,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}export{#endsyntax#}
    - +
    {#syntax#}export{#endsyntax#} makes a function or variable externally visible in the generated object file. Exported functions default to the C calling convention. @@ -11111,9 +11200,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}extern{#endsyntax#}
    - +
    {#syntax#}extern{#endsyntax#} can be used to declare a function or variable that will be resolved at link time, when linking statically or at runtime, when linking dynamically. @@ -11123,9 +11212,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}false{#endsyntax#}
    - +
    The boolean value {#syntax#}false{#endsyntax#}.
      @@ -11134,9 +11223,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}fn{#endsyntax#}
    - +
    {#syntax#}fn{#endsyntax#} declares a function.
      @@ -11145,9 +11234,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}for{#endsyntax#}
    - +
    A {#syntax#}for{#endsyntax#} expression can be used to iterate over the elements of a slice, array, or tuple.
      @@ -11156,9 +11245,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}if{#endsyntax#}
    - +
    An {#syntax#}if{#endsyntax#} expression can test boolean expressions, optional values, or error unions. For optional values or error unions, the if expression can capture the unwrapped value. @@ -11168,9 +11257,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}inline{#endsyntax#}
    - +
    {#syntax#}inline{#endsyntax#} can be used to label a loop expression such that it will be unrolled at compile time. It can also be used to force a function to be inlined at all call sites. @@ -11180,9 +11269,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}noalias{#endsyntax#}
    - +
    The {#syntax#}noalias{#endsyntax#} keyword.
      @@ -11191,9 +11280,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}nosuspend{#endsyntax#}
    - +
    The {#syntax#}nosuspend{#endsyntax#} keyword can be used in front of a block, statement or expression, to mark a scope where no suspension points are reached. In particular, inside a {#syntax#}nosuspend{#endsyntax#} scope: @@ -11209,9 +11298,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}null{#endsyntax#}
    - +
    The optional value {#syntax#}null{#endsyntax#}.
      @@ -11220,9 +11309,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}or{#endsyntax#}
    - +
    The boolean operator {#syntax#}or{#endsyntax#}.
      @@ -11231,9 +11320,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}orelse{#endsyntax#}
    - +
    {#syntax#}orelse{#endsyntax#} can be used to evaluate an expression if the expression before it evaluates to null.
      @@ -11242,9 +11331,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}packed{#endsyntax#}
    - +
    The {#syntax#}packed{#endsyntax#} keyword before a struct definition changes the struct's in-memory layout to the guaranteed {#syntax#}packed{#endsyntax#} layout. @@ -11254,9 +11343,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}pub{#endsyntax#}
    - +
    The {#syntax#}pub{#endsyntax#} in front of a top level declaration makes the declaration available to reference from a different file than the one it is declared in. @@ -11266,9 +11355,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}resume{#endsyntax#}
    - +
    {#syntax#}resume{#endsyntax#} will continue execution of a function frame after the point the function was suspended.
      @@ -11277,9 +11366,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}return{#endsyntax#}
    - +
    {#syntax#}return{#endsyntax#} exits a function with a value.
      @@ -11288,9 +11377,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}linksection{#endsyntax#}
    - +
    The {#syntax#}linksection{#endsyntax#} keyword.
      @@ -11299,9 +11388,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}struct{#endsyntax#}
    - +
    {#syntax#}struct{#endsyntax#} defines a struct.
      @@ -11310,9 +11399,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}suspend{#endsyntax#}
    - +
    {#syntax#}suspend{#endsyntax#} will cause control flow to return to the call site or resumer of the function. {#syntax#}suspend{#endsyntax#} can also be used before a block within a function, @@ -11323,9 +11412,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}switch{#endsyntax#}
    - +
    A {#syntax#}switch{#endsyntax#} expression can be used to test values of a common type. {#syntax#}switch{#endsyntax#} cases can capture field values of a {#link|Tagged union#}. @@ -11335,9 +11424,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}test{#endsyntax#}
    - +
    The {#syntax#}test{#endsyntax#} keyword can be used to denote a top-level block of code used to make sure behavior meets expectations. @@ -11347,9 +11436,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}threadlocal{#endsyntax#}
    - +
    {#syntax#}threadlocal{#endsyntax#} can be used to specify a variable as thread-local.
      @@ -11358,9 +11447,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}true{#endsyntax#}
    - +
    The boolean value {#syntax#}true{#endsyntax#}.
      @@ -11369,9 +11458,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}try{#endsyntax#}
    - +
    {#syntax#}try{#endsyntax#} evaluates an error union expression. If it is an error, it returns from the current function with the same error. @@ -11382,9 +11471,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}undefined{#endsyntax#}
    - +
    {#syntax#}undefined{#endsyntax#} can be used to leave a value uninitialized.
      @@ -11393,9 +11482,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}union{#endsyntax#}
    - +
    {#syntax#}union{#endsyntax#} defines a union.
      @@ -11404,23 +11493,23 @@ fn readU32Be() u32 {}
    +
    {#syntax#}unreachable{#endsyntax#}
    - +
    {#syntax#}unreachable{#endsyntax#} can be used to assert that control flow will never happen upon a particular location. Depending on the build mode, {#syntax#}unreachable{#endsyntax#} may emit a panic.
      -
    • Emits a panic in {#syntax#}Debug{#endsyntax#} and {#syntax#}ReleaseSafe{#endsyntax#} mode, or when using zig test.
    • -
    • Does not emit a panic in {#syntax#}ReleaseFast{#endsyntax#} mode, unless zig test is being used.
    • +
    • Emits a panic in {#syntax#}Debug{#endsyntax#} and {#syntax#}ReleaseSafe{#endsyntax#} mode, or when using zig test.
    • +
    • Does not emit a panic in {#syntax#}ReleaseFast{#endsyntax#} mode, unless zig test is being used.
    • See also {#link|unreachable#}
    +
    {#syntax#}usingnamespace{#endsyntax#}
    - +
    {#syntax#}usingnamespace{#endsyntax#} is a top-level declaration that imports all the public declarations of the operand, which must be a struct, union, or enum, into the current scope. @@ -11430,9 +11519,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}var{#endsyntax#}
    - +
    {#syntax#}var{#endsyntax#} declares a variable that may be modified.
      @@ -11441,9 +11530,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}volatile{#endsyntax#}
    - +
    {#syntax#}volatile{#endsyntax#} can be used to denote loads or stores of a pointer have side effects. It can also modify an inline assembly expression to denote it has side effects. @@ -11453,9 +11542,9 @@ fn readU32Be() u32 {}
    +
    {#syntax#}while{#endsyntax#}
    - +
    A {#syntax#}while{#endsyntax#} expression can be used to repeatedly test a boolean, optional, or error union expression, and cease looping when that expression evaluates to false, null, or an error, respectively. @@ -11464,6 +11553,7 @@ fn readU32Be() u32 {}
    {#header_close#} @@ -12034,7 +12124,7 @@ keyword <- KEYWORD_align / KEYWORD_allowzero / KEYWORD_and / KEYWORD_anyframe
  • Together we serve the users.
  • {#header_close#} -
    +