diff options
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | build.zig | 10 | ||||
| -rw-r--r-- | doc/docgen.zig | 543 | ||||
| -rw-r--r-- | doc/home.html.in | 724 | ||||
| -rw-r--r-- | doc/langref.html.in | 1142 | ||||
| -rw-r--r-- | src/bigint.cpp | 12 | ||||
| -rw-r--r-- | src/codegen.cpp | 48 | ||||
| -rw-r--r-- | std/build.zig | 2 | ||||
| -rw-r--r-- | std/crypto/blake2.zig | 4 | ||||
| -rw-r--r-- | std/crypto/index.zig | 11 | ||||
| -rw-r--r-- | std/crypto/md5.zig | 8 | ||||
| -rw-r--r-- | std/crypto/sha1.zig | 2 | ||||
| -rw-r--r-- | std/crypto/sha2.zig | 5 | ||||
| -rw-r--r-- | std/crypto/sha3.zig | 281 | ||||
| -rw-r--r-- | std/crypto/throughput_test.zig | 43 | ||||
| -rw-r--r-- | std/hash_map.zig | 7 | ||||
| -rw-r--r-- | std/mem.zig | 14 | ||||
| -rw-r--r-- | test/cases/math.zig | 28 |
18 files changed, 1372 insertions, 1513 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a090d9f29..fd39dd30da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -368,6 +368,7 @@ set(ZIG_STD_FILES "crypto/md5.zig" "crypto/sha1.zig" "crypto/sha2.zig" + "crypto/sha3.zig" "crypto/blake2.zig" "cstr.zig" "debug/failing_allocator.zig" @@ -15,23 +15,17 @@ pub fn build(b: &Builder) -> %void { var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); + const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe); var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8 { docgen_exe.getOutputPath(), + rel_zig_exe, "doc/langref.html.in", os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable, }); docgen_cmd.step.dependOn(&docgen_exe.step); - var docgen_home_cmd = b.addCommand(null, b.env_map, [][]const u8 { - docgen_exe.getOutputPath(), - "doc/home.html.in", - os.path.join(b.allocator, b.cache_root, "home.html") catch unreachable, - }); - docgen_home_cmd.step.dependOn(&docgen_exe.step); - const docs_step = b.step("docs", "Build documentation"); docs_step.dependOn(&docgen_cmd.step); - docs_step.dependOn(&docgen_home_cmd.step); const test_step = b.step("test", "Run all the tests"); diff --git a/doc/docgen.zig b/doc/docgen.zig index f3bb7df6b1..1972a00374 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -1,10 +1,16 @@ const std = @import("std"); const io = std.io; const os = std.os; +const warn = std.debug.warn; +const mem = std.mem; + +const max_doc_file_size = 10 * 1024 * 1024; + +const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt(); pub fn main() -> %void { // TODO use a more general purpose allocator here - var inc_allocator = try std.heap.IncrementingAllocator.init(5 * 1024 * 1024); + var inc_allocator = try std.heap.IncrementingAllocator.init(max_doc_file_size); defer inc_allocator.deinit(); const allocator = &inc_allocator.allocator; @@ -12,6 +18,9 @@ pub fn main() -> %void { if (!args_it.skip()) @panic("expected self arg"); + const zig_exe = try (args_it.next(allocator) ?? @panic("expected zig exe arg")); + defer allocator.free(zig_exe); + const in_file_name = try (args_it.next(allocator) ?? @panic("expected input arg")); defer allocator.free(in_file_name); @@ -25,39 +34,533 @@ pub fn main() -> %void { defer out_file.close(); var file_in_stream = io.FileInStream.init(&in_file); - var buffered_in_stream = io.BufferedInStream.init(&file_in_stream.stream); + + const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size); var file_out_stream = io.FileOutStream.init(&out_file); var buffered_out_stream = io.BufferedOutStream.init(&file_out_stream.stream); - gen(&buffered_in_stream.stream, &buffered_out_stream.stream); - try buffered_out_stream.flush(); + var tokenizer = Tokenizer.init(in_file_name, input_file_bytes); + var toc = try genToc(allocator, &tokenizer); + try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe); + try buffered_out_stream.flush(); } -const State = enum { - Start, - Derp, +const Token = struct { + id: Id, + start: usize, + end: usize, + + const Id = enum { + Invalid, + Content, + BracketOpen, + TagContent, + Separator, + BracketClose, + Eof, + }; }; -// TODO look for code segments +const Tokenizer = struct { + buffer: []const u8, + index: usize, + state: State, + source_file_name: []const u8, -fn gen(in: &io.InStream, out: &io.OutStream) { - var state = State.Start; - while (true) { - const byte = in.readByte() catch |err| { - if (err == error.EndOfStream) { - return; - } - std.debug.panic("{}", err); + const State = enum { + Start, + LBracket, + Hash, + TagName, + Eof, + }; + + fn init(source_file_name: []const u8, buffer: []const u8) -> Tokenizer { + return Tokenizer { + .buffer = buffer, + .index = 0, + .state = State.Start, + .source_file_name = source_file_name, + }; + } + + fn next(self: &Tokenizer) -> Token { + var result = Token { + .id = Token.Id.Eof, + .start = self.index, + .end = undefined, }; - switch (state) { - State.Start => switch (byte) { + while (self.index < self.buffer.len) : (self.index += 1) { + const c = self.buffer[self.index]; + switch (self.state) { + State.Start => switch (c) { + '{' => { + self.state = State.LBracket; + }, + else => { + result.id = Token.Id.Content; + }, + }, + State.LBracket => switch (c) { + '#' => { + if (result.id != Token.Id.Eof) { + self.index -= 1; + self.state = State.Start; + break; + } else { + result.id = Token.Id.BracketOpen; + self.index += 1; + self.state = State.TagName; + break; + } + }, + else => { + result.id = Token.Id.Content; + self.state = State.Start; + }, + }, + State.TagName => switch (c) { + '|' => { + if (result.id != Token.Id.Eof) { + break; + } else { + result.id = Token.Id.Separator; + self.index += 1; + break; + } + }, + '#' => { + self.state = State.Hash; + }, + else => { + result.id = Token.Id.TagContent; + }, + }, + State.Hash => switch (c) { + '}' => { + if (result.id != Token.Id.Eof) { + self.index -= 1; + self.state = State.TagName; + break; + } else { + result.id = Token.Id.BracketClose; + self.index += 1; + self.state = State.Start; + break; + } + }, + else => { + result.id = Token.Id.TagContent; + self.state = State.TagName; + }, + }, + State.Eof => unreachable, + } + } else { + switch (self.state) { + State.Start, State.LBracket, State.Eof => {}, else => { - out.writeByte(byte) catch unreachable; + result.id = Token.Id.Invalid; }, + } + self.state = State.Eof; + } + result.end = self.index; + return result; + } + + const Location = struct { + line: usize, + column: usize, + line_start: usize, + line_end: usize, + }; + + fn getTokenLocation(self: &Tokenizer, token: &const Token) -> Location { + var loc = Location { + .line = 0, + .column = 0, + .line_start = 0, + .line_end = 0, + }; + for (self.buffer) |c, i| { + if (i == token.start) { + loc.line_end = i; + while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {} + return loc; + } + if (c == '\n') { + loc.line += 1; + loc.column = 0; + loc.line_start = i + 1; + } else { + loc.column += 1; + } + } + return loc; + } +}; + +error ParseError; + +fn parseError(tokenizer: &Tokenizer, token: &const Token, comptime fmt: []const u8, args: ...) -> error { + const loc = tokenizer.getTokenLocation(token); + warn("{}:{}:{}: error: " ++ fmt ++ "\n", tokenizer.source_file_name, loc.line + 1, loc.column + 1, args); + if (loc.line_start <= loc.line_end) { + warn("{}\n", tokenizer.buffer[loc.line_start..loc.line_end]); + { + var i: usize = 0; + while (i < loc.column) : (i += 1) { + warn(" "); + } + } + { + const caret_count = token.end - token.start; + var i: usize = 0; + while (i < caret_count) : (i += 1) { + warn("~"); + } + } + warn("\n"); + } + return error.ParseError; +} + +fn assertToken(tokenizer: &Tokenizer, token: &const Token, id: Token.Id) -> %void { + if (token.id != id) { + return parseError(tokenizer, token, "expected {}, found {}", @tagName(id), @tagName(token.id)); + } +} + +fn eatToken(tokenizer: &Tokenizer, id: Token.Id) -> %Token { + const token = tokenizer.next(); + try assertToken(tokenizer, token, id); + return token; +} + +const HeaderOpen = struct { + name: []const u8, + url: []const u8, + n: usize, +}; + +const SeeAlsoItem = struct { + name: []const u8, + token: Token, +}; + +const Code = struct { + id: Id, + name: []const u8, + source_token: Token, + + const Id = enum { + Test, + Exe, + Error, + }; +}; + +const Node = union(enum) { + Content: []const u8, + Nav, + HeaderOpen: HeaderOpen, + SeeAlso: []const SeeAlsoItem, + Code: Code, +}; + +const Toc = struct { + nodes: []Node, + toc: []u8, + urls: std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8), +}; + +const Action = enum { + Open, + Close, +}; + +fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) -> %Toc { + var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator); + %defer urls.deinit(); + + var header_stack_size: usize = 0; + var last_action = Action.Open; + + var toc_buf = try std.Buffer.initSize(allocator, 0); + defer toc_buf.deinit(); + + var toc_buf_adapter = io.BufferOutStream.init(&toc_buf); + var toc = &toc_buf_adapter.stream; + + var nodes = std.ArrayList(Node).init(allocator); + defer nodes.deinit(); + + try toc.writeByte('\n'); + + while (true) { + const token = tokenizer.next(); + switch (token.id) { + Token.Id.Eof => { + if (header_stack_size != 0) { + return parseError(tokenizer, token, "unbalanced headers"); + } + try toc.write(" </ul>\n"); + break; + }, + Token.Id.Content => { + try nodes.append(Node {.Content = tokenizer.buffer[token.start..token.end] }); + }, + Token.Id.BracketOpen => { + const tag_token = try eatToken(tokenizer, Token.Id.TagContent); + const tag_name = tokenizer.buffer[tag_token.start..tag_token.end]; + + if (mem.eql(u8, tag_name, "nav")) { + _ = try eatToken(tokenizer, Token.Id.BracketClose); + + try nodes.append(Node.Nav); + } else if (mem.eql(u8, tag_name, "header_open")) { + _ = try eatToken(tokenizer, Token.Id.Separator); + const content_token = try eatToken(tokenizer, Token.Id.TagContent); + const content = tokenizer.buffer[content_token.start..content_token.end]; + _ = try eatToken(tokenizer, Token.Id.BracketClose); + + header_stack_size += 1; + + const urlized = try urlize(allocator, content); + try nodes.append(Node{.HeaderOpen = HeaderOpen { + .name = content, + .url = urlized, + .n = header_stack_size, + }}); + if (try urls.put(urlized, tag_token)) |other_tag_token| { + parseError(tokenizer, tag_token, "duplicate header url: #{}", urlized) catch {}; + parseError(tokenizer, other_tag_token, "other tag here") catch {}; + return error.ParseError; + } + if (last_action == Action.Open) { + try toc.writeByte('\n'); + try toc.writeByteNTimes(' ', header_stack_size * 4); + try toc.write("<ul>\n"); + } else { + last_action = Action.Open; + } + try toc.writeByteNTimes(' ', 4 + header_stack_size * 4); + try toc.print("<li><a href=\"#{}\">{}</a>", urlized, content); + } else if (mem.eql(u8, tag_name, "header_close")) { + if (header_stack_size == 0) { + return parseError(tokenizer, tag_token, "unbalanced close header"); + } + header_stack_size -= 1; + _ = try eatToken(tokenizer, Token.Id.BracketClose); + + if (last_action == Action.Close) { + try toc.writeByteNTimes(' ', 8 + header_stack_size * 4); + try toc.write("</ul></li>\n"); + } else { + try toc.write("</li>\n"); + last_action = Action.Close; + } + } else if (mem.eql(u8, tag_name, "see_also")) { + var list = std.ArrayList(SeeAlsoItem).init(allocator); + %defer list.deinit(); + + while (true) { + const see_also_tok = tokenizer.next(); + switch (see_also_tok.id) { + Token.Id.TagContent => { + const content = tokenizer.buffer[see_also_tok.start..see_also_tok.end]; + try list.append(SeeAlsoItem { + .name = content, + .token = see_also_tok, + }); + }, + Token.Id.Separator => {}, + Token.Id.BracketClose => { + try nodes.append(Node {.SeeAlso = list.toOwnedSlice() } ); + break; + }, + else => return parseError(tokenizer, see_also_tok, "invalid see_also token"), + } + } + } else if (mem.eql(u8, tag_name, "code_begin")) { + _ = try eatToken(tokenizer, Token.Id.Separator); + const code_kind_tok = try eatToken(tokenizer, Token.Id.TagContent); + var name: []const u8 = "test"; + 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 code_kind_str = tokenizer.buffer[code_kind_tok.start..code_kind_tok.end]; + var code_kind_id: Code.Id = undefined; + if (mem.eql(u8, code_kind_str, "exe")) { + code_kind_id = Code.Id.Exe; + } else if (mem.eql(u8, code_kind_str, "test")) { + code_kind_id = Code.Id.Test; + } else if (mem.eql(u8, code_kind_str, "error")) { + code_kind_id = Code.Id.Error; + } else { + return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", code_kind_str); + } + const source_token = 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, "code_end")) { + return parseError(tokenizer, end_code_tag, "expected code_end token"); + } + _ = try eatToken(tokenizer, Token.Id.BracketClose); + try nodes.append(Node {.Code = Code{ + .id = code_kind_id, + .name = name, + .source_token = source_token, + }}); + } else { + return parseError(tokenizer, tag_token, "unrecognized tag name: {}", tag_name); + } }, - State.Derp => unreachable, + else => return parseError(tokenizer, token, "invalid token"), } } + + return Toc { + .nodes = nodes.toOwnedSlice(), + .toc = toc_buf.toOwnedSlice(), + .urls = urls, + }; +} + +fn urlize(allocator: &mem.Allocator, input: []const u8) -> %[]u8 { + var buf = try std.Buffer.initSize(allocator, 0); + defer buf.deinit(); + + var buf_adapter = io.BufferOutStream.init(&buf); + var out = &buf_adapter.stream; + for (input) |c| { + switch (c) { + 'a'...'z', 'A'...'Z', '_', '-' => { + try out.writeByte(c); + }, + ' ' => { + try out.writeByte('-'); + }, + else => {}, + } + } + return buf.toOwnedSlice(); +} + +fn escapeHtml(allocator: &mem.Allocator, input: []const u8) -> %[]u8 { + var buf = try std.Buffer.initSize(allocator, 0); + defer buf.deinit(); + + var buf_adapter = io.BufferOutStream.init(&buf); + var out = &buf_adapter.stream; + for (input) |c| { + try switch (c) { + '&' => out.write("&"), + '<' => out.write("<"), + '>' => out.write(">"), + '"' => out.write("""), + else => out.writeByte(c), + }; + } + return buf.toOwnedSlice(); +} + +error ExampleFailedToCompile; + +fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: &io.OutStream, zig_exe: []const u8) -> %void { + for (toc.nodes) |node| { + switch (node) { + Node.Content => |data| { + try out.write(data); + }, + Node.Nav => { + try out.write(toc.toc); + }, + Node.HeaderOpen => |info| { + try out.print("<h{} id=\"{}\">{}</h{}>\n", info.n, info.url, info.name, info.n); + }, + Node.SeeAlso => |items| { + try out.write("<p>See also:</p><ul>\n"); + for (items) |item| { + const url = try urlize(allocator, item.name); + if (!toc.urls.contains(url)) { + return parseError(tokenizer, item.token, "url not found: {}", url); + } + try out.print("<li><a href=\"#{}\">{}</a></li>\n", url, item.name); + } + try out.write("</ul>\n"); + }, + Node.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"); + const escaped_source = try escapeHtml(allocator, trimmed_raw_source); + try out.print("<pre><code class=\"zig\">{}</code></pre>", escaped_source); + const tmp_dir_name = "docgen_tmp"; + try os.makePath(allocator, tmp_dir_name); + const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name); + const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext); + const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext); + const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext); + try io.writeFile(tmp_source_file_name, trimmed_raw_source, null); + + switch (code.id) { + Code.Id.Exe => { + { + const args = [][]const u8 {zig_exe, "build-exe", tmp_source_file_name, "--output", tmp_bin_file_name}; + const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size); + switch (result.term) { + os.ChildProcess.Term.Exited => |exit_code| { + if (exit_code != 0) { + warn("{}\nThe following command exited with code {}:\n", result.stderr, exit_code); + for (args) |arg| warn("{} ", arg) else warn("\n"); + return parseError(tokenizer, code.source_token, "example failed to compile"); + } + }, + else => { + warn("{}\nThe following command crashed:\n", result.stderr); + for (args) |arg| warn("{} ", arg) else warn("\n"); + return parseError(tokenizer, code.source_token, "example failed to compile"); + }, + } + } + const args = [][]const u8 {tmp_bin_file_name}; + const result = try os.ChildProcess.exec(allocator, args, null, null, max_doc_file_size); + switch (result.term) { + os.ChildProcess.Term.Exited => |exit_code| { + if (exit_code != 0) { + warn("The following command exited with code {}:\n", exit_code); + for (args) |arg| warn("{} ", arg) else warn("\n"); + return parseError(tokenizer, code.source_token, "example exited with code {}", exit_code); + } + }, + else => { + warn("The following command crashed:\n"); + for (args) |arg| warn("{} ", arg) else warn("\n"); + return parseError(tokenizer, code.source_token, "example crashed"); + }, + } + try out.print("<pre><code class=\"sh\">$ zig build-exe {}.zig\n$ ./{}\n{}{}</code></pre>\n", code.name, code.name, result.stderr, result.stdout); + }, + Code.Id.Test => { + @panic("TODO"); + }, + Code.Id.Error => { + @panic("TODO"); + }, + } + }, + } + } + } diff --git a/doc/home.html.in b/doc/home.html.in deleted file mode 100644 index 086a078a90..0000000000 --- a/doc/home.html.in +++ /dev/null @@ -1,724 +0,0 @@ -<!doctype html> -<html> - <head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> - <title>The Zig Programming Language</title> - <link rel="stylesheet" type="text/css" href="highlight/styles/default.css"> - <style type="text/css"> - img { - max-width: 100%; - } - </style> - </head> - <body> - <img src="zig-logo.svg"> - <p> - Zig is an open-source programming language designed for <strong>robustness</strong>, - <strong>optimality</strong>, and <strong>clarity</strong>. - </p> - <p> - <a href="download/">Download</a> | - <a href="documentation/master/">Documentation</a> | - <a href="https://github.com/zig-lang/zig">Source Code</a> | - <a href="https://github.com/zig-lang/zig/issues">Bug Tracker</a> | - <a href="https://webchat.freenode.net/?channels=%23zig">IRC</a> | - <a href="https://www.patreon.com/andrewrk">Donate $1/month</a> - </p> - <h2>Feature Highlights</h2> - <ul> - <li>Manual memory management. Memory allocation failure is handled correctly. Edge cases matter!</li> - <li>Zig competes with C instead of depending on it. The Zig Standard Library does not depend on libc.</li> - <li>Small, simple language. Focus on debugging your application rather than debugging your knowledge of your programming language.</li> - <li>A fresh take on error handling that resembles what well-written C error handling looks like, - minus the boilerplate and verbosity.</li> - <li>Debug mode optimizes for fast compilation time and crashing with a stack trace when undefined behavior - <em>would</em> happen.</li> - <li>ReleaseFast mode produces heavily optimized code. What other projects call - "Link Time Optimization" Zig does automatically.</li> - <li>ReleaseSafe mode produces optimized code but keeps safety checks enabled. Disable safety checks in the bottlenecks of your code.</li> - <li>Generic data structures and functions.</li> - <li>Compile-time reflection and compile-time code execution.</li> - <li>Import .h files and directly use C types, variables, and functions.</li> - <li>Export functions, variables, and types for C code to depend on. Automatically generate .h files.</li> - <li>Nullable type instead of null pointers.</li> - <li>Order independent top level declarations.</li> - <li>Friendly toward package maintainers. Reproducible build, bootstrapping process carefully documented. Issues filed by package maintainers are considered especially important.</li> - <li>Cross-compiling is a first-class use case.</li> - <li>No preprocessor. Instead Zig has a few carefully designed features that - provide a way to accomplish things you might do with a preprocessor.</li> - </ul> - <h2 id="reading-material">Reading Material</h2> - <ul> - <li>2018-01-03 - <a href="http://andrewkelley.me/post/zig-december-2017-in-review.html">December 2017 in Review</a></li> - <li>2017-10-17 - <a href="download/0.1.1/release-notes.html">Zig 0.1.1 Release Notes</a></li> - <li>2017-07-19 - <a href="http://tiehuis.github.io/iterative-replacement-of-c-with-zig">Iterative Replacement of C with Zig</a></li> - <li>2017-02-16 - <a href="http://andrewkelley.me/post/a-better-way-to-implement-bit-fields.html">A Better Way to Implement Bit-Fields</a></li> - <li>2017-02-13 - <a href="http://andrewkelley.me/post/zig-already-more-knowable-than-c.html">Zig: Already More Knowable Than C</a></li> - <li>2017-01-30 - <a href="http://andrewkelley.me/post/zig-programming-language-blurs-line-compile-time-run-time.html">Zig Programming Language Blurs the Line Between Compile-Time and Run-Time</a></li> - <li>2016-02-08 - <a href="http://andrewkelley.me/post/intro-to-zig.html">Introduction to the Zig Programming Language</a></li> - </ul> - <h2 id="source-examples">Source Code Examples</h2> - <ul> - <li><a href="#hello">Hello World</a></li> - <li><a href="#hello_libc">Hello World with libc</a></li> - <li><a href="#parse">Parsing Unsigned Integers</a></li> - <li><a href="#hashmap">HashMap with Custom Allocator</a></li> - <li><a href="#tetris">Tetris Clone</a></li> - <li><a href="#clashos">Bare Bones Operating System</a></li> - <li><a href="#cat">Cat Utility</a></li> - <li><a href="#multiline-strings">Multiline String Syntax</a></li> - <li><a href="#mersenne">Mersenne Twister Random Number Generator</a></li> - </ul> - <h3 id="hello">Hello World</h3> - <pre><code class="zig">const std = @import("std"); - -pub fn main() -> %void { - // If this program is run without stdout attached, exit with an error. - var stdout_file = try std.io.getStdOut(); - // If this program encounters pipe failure when printing to stdout, exit - // with an error. - try stdout_file.write("Hello, world!\n"); -}</code></pre> - <p>Build this with:</p> - <pre>zig build-exe hello.zig</pre> - <h3 id="hello_libc">Hello World with libc</h3> - <pre><code class="zig">const c = @cImport({ - // See https://github.com/zig-lang/zig/issues/515 - @cDefine("_NO_CRT_STDIO_INLINE", "1"); - @cInclude("stdio.h"); - @cInclude("string.h"); -}); - -const msg = c"Hello, world!\n"; - -export fn main(argc: c_int, argv: &&u8) -> c_int { - if (c.printf(msg) != c_int(c.strlen(msg))) - return -1; - - return 0; -}</code></pre> - <p>Build this with:</p> - <pre>zig build-exe hello.zig --library c</pre> - <h3 id="parse">Parsing Unsigned Integers</h3> - <pre><code class="zig">pub fn parseUnsigned(comptime T: type, buf: []u8, radix: u8) -> %T { - var x: T = 0; - - for (buf) |c| { - const digit = try charToDigit(c, radix); - x = try mulOverflow(T, x, radix); - x = try addOverflow(T, x, digit); - } - - return x; -} - -error InvalidChar; - -fn charToDigit(c: u8, radix: u8) -> %u8 { - const value = switch (c) { - '0' ... '9' => c - '0', - 'A' ... 'Z' => c - 'A' + 10, - 'a' ... 'z' => c - 'a' + 10, - else => return error.InvalidChar, - }; - - if (value >= radix) - return error.InvalidChar; - - return value; -} - -error Overflow; - -pub fn mulOverflow(comptime T: type, a: T, b: T) -> %T { - var answer: T = undefined; - if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer -} - -pub fn addOverflow(comptime T: type, a: T, b: T) -> %T { - var answer: T = undefined; - if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer -} - -fn getNumberWithDefault(s: []u8) -> u32 { - parseUnsigned(u32, s, 10) catch 42 -} - -fn getNumberOrCrash(s: []u8) -> u32 { - %%parseUnsigned(u32, s, 10) -} - -fn addTwoTogetherOrReturnErr(a_str: []u8, b_str: []u8) -> %u32 { - const a = parseUnsigned(u32, a_str, 10) catch |err| return err; - const b = parseUnsigned(u32, b_str, 10) catch |err| return err; - return a + b; -}</code></pre> - <h3 id="hashmap">HashMap with Custom Allocator</h3> - <pre><code class="zig">const debug = @import("debug.zig"); -const assert = debug.assert; -const math = @import("math.zig"); -const mem = @import("mem.zig"); -const Allocator = mem.Allocator; - -const want_modification_safety = !@compileVar("is_release"); -const debug_u32 = if (want_modification_safety) u32 else void; - -pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn(key: K)->u32, - comptime eql: fn(a: K, b: K)->bool) -> type -{ - struct { - entries: []Entry, - size: usize, - max_distance_from_start_index: usize, - allocator: &Allocator, - // this is used to detect bugs where a hashtable is edited while an iterator is running. - modification_count: debug_u32, - - const Self = this; - - pub const Entry = struct { - used: bool, - distance_from_start_index: usize, - key: K, - value: V, - }; - - pub const Iterator = struct { - hm: &Self, - // how many items have we returned - count: usize, - // iterator through the entry array - index: usize, - // used to detect concurrent modification - initial_modification_count: debug_u32, - - pub fn next(it: &Iterator) -> ?&Entry { - if (want_modification_safety) { - assert(it.initial_modification_count == it.hm.modification_count); // concurrent modification - } - if (it.count >= it.hm.size) return null; - while (it.index < it.hm.entries.len) : (it.index += 1) { - const entry = &it.hm.entries[it.index]; - if (entry.used) { - it.index += 1; - it.count += 1; - return entry; - } - } - unreachable // no next item - } - }; - - pub fn init(hm: &Self, allocator: &Allocator) { - hm.entries = []Entry{}; - hm.allocator = allocator; - hm.size = 0; - hm.max_distance_from_start_index = 0; - // it doesn't actually matter what we set this to since we use wrapping integer arithmetic - hm.modification_count = undefined; - } - - pub fn deinit(hm: &Self) { - hm.allocator.free(Entry, hm.entries); - } - - pub fn clear(hm: &Self) { - for (hm.entries) |*entry| { - entry.used = false; - } - hm.size = 0; - hm.max_distance_from_start_index = 0; - hm.incrementModificationCount(); - } - - pub fn put(hm: &Self, key: K, value: V) -> %void { - if (hm.entries.len == 0) { - try hm.initCapacity(16); - } - hm.incrementModificationCount(); - - // if we get too full (60%), double the capacity - if (hm.size * 5 >= hm.entries.len * 3) { - const old_entries = hm.entries; - try hm.initCapacity(hm.entries.len * 2); - // dump all of the old elements into the new table - for (old_entries) |*old_entry| { - if (old_entry.used) { - hm.internalPut(old_entry.key, old_entry.value); - } - } - hm.allocator.free(Entry, old_entries); - } - - hm.internalPut(key, value); - } - - pub fn get(hm: &Self, key: K) -> ?&Entry { - return hm.internalGet(key); - } - - pub fn remove(hm: &Self, key: K) { - hm.incrementModificationCount(); - const start_index = hm.keyToIndex(key); - {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) { - const index = (start_index + roll_over) % hm.entries.len; - var entry = &hm.entries[index]; - - assert(entry.used); // key not found - - if (!eql(entry.key, key)) continue; - - while (roll_over < hm.entries.len) : (roll_over += 1) { - const next_index = (start_index + roll_over + 1) % hm.entries.len; - const next_entry = &hm.entries[next_index]; - if (!next_entry.used or next_entry.distance_from_start_index == 0) { - entry.used = false; - hm.size -= 1; - return; - } - *entry = *next_entry; - entry.distance_from_start_index -= 1; - entry = next_entry; - } - unreachable // shifting everything in the table - }} - unreachable // key not found - } - - pub fn entryIterator(hm: &Self) -> Iterator { - return Iterator { - .hm = hm, - .count = 0, - .index = 0, - .initial_modification_count = hm.modification_count, - }; - } - - fn initCapacity(hm: &Self, capacity: usize) -> %void { - hm.entries = try hm.allocator.alloc(Entry, capacity); - hm.size = 0; - hm.max_distance_from_start_index = 0; - for (hm.entries) |*entry| { - entry.used = false; - } - } - - fn incrementModificationCount(hm: &Self) { - if (want_modification_safety) { - hm.modification_count +%= 1; - } - } - - fn internalPut(hm: &Self, orig_key: K, orig_value: V) { - var key = orig_key; - var value = orig_value; - const start_index = hm.keyToIndex(key); - var roll_over: usize = 0; - var distance_from_start_index: usize = 0; - while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1}) { - const index = (start_index + roll_over) % hm.entries.len; - const entry = &hm.entries[index]; - - if (entry.used and !eql(entry.key, key)) { - if (entry.distance_from_start_index < distance_from_start_index) { - // robin hood to the rescue - const tmp = *entry; - hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index, - distance_from_start_index); - *entry = Entry { - .used = true, - .distance_from_start_index = distance_from_start_index, - .key = key, - .value = value, - }; - key = tmp.key; - value = tmp.value; - distance_from_start_index = tmp.distance_from_start_index; - } - continue; - } - - if (!entry.used) { - // adding an entry. otherwise overwriting old value with - // same key - hm.size += 1; - } - - hm.max_distance_from_start_index = math.max(distance_from_start_index, hm.max_distance_from_start_index); - *entry = Entry { - .used = true, - .distance_from_start_index = distance_from_start_index, - .key = key, - .value = value, - }; - return; - } - unreachable // put into a full map - } - - fn internalGet(hm: &Self, key: K) -> ?&Entry { - const start_index = hm.keyToIndex(key); - {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) { - const index = (start_index + roll_over) % hm.entries.len; - const entry = &hm.entries[index]; - - if (!entry.used) return null; - if (eql(entry.key, key)) return entry; - }} - return null; - } - - fn keyToIndex(hm: &Self, key: K) -> usize { - return usize(hash(key)) % hm.entries.len; - } - } -} - -test "basic hash map test" { - var map: HashMap(i32, i32, hash_i32, eql_i32) = undefined; - map.init(&debug.global_allocator); - defer map.deinit(); - - %%map.put(1, 11); - %%map.put(2, 22); - %%map.put(3, 33); - %%map.put(4, 44); - %%map.put(5, 55); - - assert((??map.get(2)).value == 22); - map.remove(2); - assert(if (const entry ?= map.get(2)) false else true); -} - -fn hash_i32(x: i32) -> u32 { - *(&u32)(&x) -} -fn eql_i32(a: i32, b: i32) -> bool { - a == b -}</code></pre> - <h3 id="tetris">Tetris Clone</h3> - <img src="tetris-screenshot.png"> - <p> - <a href="https://github.com/andrewrk/tetris">Source Code on GitHub</a> - </p> - <h3 id="clashos">Bare Bones Operating System</h3> - <p> - <a href="https://github.com/andrewrk/clashos">Source Code on GitHub</a> - </p> - <h3 id="cat">Cat Utility</h3> - <pre><code class="zig">const std = @import("std"); -const io = std.io; -const mem = std.mem; -const os = std.os; - -pub fn main() -> %void { - const exe = os.args.at(0); - var catted_anything = false; - var arg_i: usize = 1; - while (arg_i < os.args.count()) : (arg_i += 1) { - const arg = os.args.at(arg_i); - if (mem.eql(u8, arg, "-")) { - catted_anything = true; - try cat_stream(&io.stdin); - } else if (arg[0] == '-') { - return usage(exe); - } else { - var is = io.InStream.open(arg, null) catch |err| { - %%io.stderr.printf("Unable to open file: {}\n", @errorName(err)); - return err; - }; - defer is.close(); - - catted_anything = true; - try cat_stream(&is); - } - } - if (!catted_anything) { - try cat_stream(&io.stdin); - } - try io.stdout.flush(); -} - -fn usage(exe: []const u8) -> %void { - %%io.stderr.printf("Usage: {} [FILE]...\n", exe); - return error.Invalid; -} - -fn cat_stream(is: &io.InStream) -> %void { - var buf: [1024 * 4]u8 = undefined; - - while (true) { - const bytes_read = is.read(buf[0..]) catch |err| { - %%io.stderr.printf("Unable to read from stream: {}\n", @errorName(err)); - return err; - }; - - if (bytes_read == 0) { - break; - } - - io.stdout.write(buf[0..bytes_read]) catch |err| { - %%io.stderr.printf("Unable to write to stdout: {}\n", @errorName(err)); - return err; - }; - } -}</code></pre> - <h3 id="multiline-strings">Multiline String Syntax</h3> - <pre><code class="zig">pub fn createAllShaders() -> AllShaders { - var as : AllShaders = undefined; - - as.primitive = createShader( - \\#version 150 core - \\ - \\in vec3 VertexPosition; - \\ - \\uniform mat4 MVP; - \\ - \\void main(void) { - \\ gl_Position = vec4(VertexPosition, 1.0) * MVP; - \\} - , - \\#version 150 core - \\ - \\out vec4 FragColor; - \\ - \\uniform vec4 Color; - \\ - \\void main(void) { - \\ FragColor = Color; - \\} - , null); - - as.primitive_attrib_position = as.primitive.attrib_location(c"VertexPosition"); - as.primitive_uniform_mvp = as.primitive.uniform_location(c"MVP"); - as.primitive_uniform_color = as.primitive.uniform_location(c"Color"); - - - - as.texture = createShader( - \\#version 150 core - \\ - \\in vec3 VertexPosition; - \\in vec2 TexCoord; - \\ - \\out vec2 FragTexCoord; - \\ - \\uniform mat4 MVP; - \\ - \\void main(void) - \\{ - \\ FragTexCoord = TexCoord; - \\ gl_Position = vec4(VertexPosition, 1.0) * MVP; - \\} - , - \\#version 150 core - \\ - \\in vec2 FragTexCoord; - \\out vec4 FragColor; - \\ - \\uniform sampler2D Tex; - \\ - \\void main(void) - \\{ - \\ FragColor = texture(Tex, FragTexCoord); - \\} - , null); - - as.texture_attrib_tex_coord = as.texture.attrib_location(c"TexCoord"); - as.texture_attrib_position = as.texture.attrib_location(c"VertexPosition"); - as.texture_uniform_mvp = as.texture.uniform_location(c"MVP"); - as.texture_uniform_tex = as.texture.uniform_location(c"Tex"); - - debug_gl.assert_no_error(); - - return as; -}</code></pre> - <h3 id="mersenne">Mersenne Twister Random Number Generator</h3> - <pre><code class="zig">const assert = @import("debug.zig").assert; -const rand_test = @import("rand_test.zig"); - -pub const MT19937_32 = MersenneTwister( - u32, 624, 397, 31, - 0x9908B0DF, - 11, 0xFFFFFFFF, - 7, 0x9D2C5680, - 15, 0xEFC60000, - 18, 1812433253); - -pub const MT19937_64 = MersenneTwister( - u64, 312, 156, 31, - 0xB5026F5AA96619E9, - 29, 0x5555555555555555, - 17, 0x71D67FFFEDA60000, - 37, 0xFFF7EEE000000000, - 43, 6364136223846793005); - -/// Use `init` to initialize this state. -pub const Rand = struct { - const Rng = if (@sizeOf(usize) >= 8) MT19937_64 else MT19937_32; - - rng: Rng, - - /// Initialize random state with the given seed. - pub fn init(r: &Rand, seed: usize) { - r.rng.init(seed); - } - - /// Get an integer with random bits. - pub fn scalar(r: &Rand, comptime T: type) -> T { - if (T == usize) { - return r.rng.get(); - } else { - var result: [@sizeOf(T)]u8 = undefined; - r.fillBytes(result); - return ([]T)(result)[0]; - } - } - - /// Fill `buf` with randomness. - pub fn fillBytes(r: &Rand, buf: []u8) { - var bytes_left = buf.len; - while (bytes_left >= @sizeOf(usize)) { - ([]usize)(buf[buf.len - bytes_left...])[0] = r.rng.get(); - bytes_left -= @sizeOf(usize); - } - if (bytes_left > 0) { - var rand_val_array : [@sizeOf(usize)]u8 = undefined; - ([]usize)(rand_val_array)[0] = r.rng.get(); - while (bytes_left > 0) { - buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left]; - bytes_left -= 1; - } - } - } - - /// Get a random unsigned integer with even distribution between `start` - /// inclusive and `end` exclusive. - // TODO support signed integers and then rename to "range" - pub fn rangeUnsigned(r: &Rand, comptime T: type, start: T, end: T) -> T { - const range = end - start; - const leftover = @maxValue(T) % range; - const upper_bound = @maxValue(T) - leftover; - var rand_val_array : [@sizeOf(T)]u8 = undefined; - - while (true) { - r.fillBytes(rand_val_array); - const rand_val = ([]T)(rand_val_array)[0]; - if (rand_val < upper_bound) { - return start + (rand_val % range); - } - } - } - - /// Get a floating point value in the range 0.0..1.0. - pub fn float(r: &Rand, comptime T: type) -> T { - // TODO Implement this way instead: - // const int = @int_type(false, @sizeOf(T) * 8); - // const mask = ((1 << @float_mantissa_bit_count(T)) - 1); - // const rand_bits = r.rng.scalar(int) & mask; - // return @float_compose(T, false, 0, rand_bits) - 1.0 - const int_type = @intType(false, @sizeOf(T) * 8); - const precision = if (T == f32) { - 16777216 - } else if (T == f64) { - 9007199254740992 - } else { - @compileError("unknown floating point type") - }; - return T(r.rangeUnsigned(int_type, 0, precision)) / T(precision); - } -}; - -fn MersenneTwister( - comptime int: type, comptime n: usize, comptime m: usize, comptime r: int, - comptime a: int, - comptime u: int, comptime d: int, - comptime s: int, comptime b: int, - comptime t: int, comptime c: int, - comptime l: int, comptime f: int) -> type -{ - struct { - const Self = this; - - array: [n]int, - index: usize, - - pub fn init(mt: &Self, seed: int) { - mt.index = n; - - var prev_value = seed; - mt.array[0] = prev_value; - {var i: usize = 1; while (i < n) : (i += 1) { - prev_value = int(i) +% f *% (prev_value ^ (prev_value >> (int.bit_count - 2))); - mt.array[i] = prev_value; - }}; - } - - pub fn get(mt: &Self) -> int { - const mag01 = []int{0, a}; - const LM: int = (1 << r) - 1; - const UM = ~LM; - - if (mt.index >= n) { - var i: usize = 0; - - while (i < n - m) : (i += 1) { - const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM); - mt.array[i] = mt.array[i + m] ^ (x >> 1) ^ mag01[x & 0x1]; - } - - while (i < n - 1) : (i += 1) { - const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM); - mt.array[i] = mt.array[i + m - n] ^ (x >> 1) ^ mag01[x & 0x1]; - - } - const x = (mt.array[i] & UM) | (mt.array[0] & LM); - mt.array[i] = mt.array[m - 1] ^ (x >> 1) ^ mag01[x & 0x1]; - - mt.index = 0; - } - - var x = mt.array[mt.index]; - mt.index += 1; - - x ^= ((x >> u) & d); - x ^= ((x <<% s) & b); - x ^= ((x <<% t) & c); - x ^= (x >> l); - - return x; - } - } -} - -test "float 32" { - var r: Rand = undefined; - r.init(42); - - {var i: usize = 0; while (i < 1000) : (i += 1) { - const val = r.float(f32); - assert(val >= 0.0); - assert(val < 1.0); - }} -} - -test "MT19937_64" { - var rng: MT19937_64 = undefined; - rng.init(rand_test.mt64_seed); - for (rand_test.mt64_data) |value| { - assert(value == rng.get()); - } -} - -test "MT19937_32" { - var rng: MT19937_32 = undefined; - rng.init(rand_test.mt32_seed); - for (rand_test.mt32_data) |value| { - assert(value == rng.get()); - } -}</code></pre> - <script src="highlight/highlight.pack.js"></script> - <script>hljs.initHighlightingOnLoad();</script> - </body> -</html> diff --git a/doc/langref.html.in b/doc/langref.html.in index 94bc780959..11952cd17d 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -31,221 +31,10 @@ </head> <body> <div id="nav"> - <ul> - <li><a href="#introduction">Introduction</a></li> - <li><a href="#hello-world">Hello World</a></li> - <li><a href="#source-encoding">Source Encoding</a></li> - <li><a href="#values">Values</a></li> - <ul> - <li><a href="#primitive-types">Primitive Types</a></li> - <li><a href="#primitive-values">Primitive Values</a></li> - <li><a href="#string-literals">String Literals</a> - <ul> - <li><a href="#string-literal-escapes">Escape Sequences</a></li> - <li><a href="#multiline-string-literals">Multiline String Literals</a></li> - </ul> - </li> - <li><a href="#values-assignment">Assignment</a></li> - </ul> - </li> - <li><a href="#integers">Integers</a> - <ul> - <li><a href="#integer-literals">Integer Literals</a></li> - <li><a href="#runtime-integer-values">Runtime Integer Values</a></li> - </ul> - </li> - <li><a href="#floats">Floats</a> - <ul> - <li><a href="#float-literals">Float Literals</a></li> - <li><a href="#float-operations">Floating Point Operations</a></li> - </ul> - </li> - <li><a href="#operators">Operators</a> - <ul> - <li><a href="#operators-table">Table of Operators</a></li> - <li><a href="#operators-precedence">Precedence</a></li> - </ul> - </li> - <li><a href="#arrays">Arrays</a></li> - <li><a href="#pointers">Pointers</a> - <ul> - <li><a href="#alignment">Alignment</a></li> - <li><a href="#type-based-alias-analysis">Type Based Alias Analysis</a></li> - </ul> - </li> - <li><a href="#slices">Slices</a></li> - <li><a href="#struct">struct</a></li> - <li><a href="#enum">enum</a></li> - <li><a href="#union">union</a></li> - <li><a href="#switch">switch</a></li> - <li><a href="#while">while</a></li> - <li><a href="#for">for</a></li> - <li><a href="#if">if</a></li> - <li><a href="#goto">goto</a></li> - <li><a href="#defer">defer</a></li> - <li><a href="#unreachable">unreachable</a> - <ul> - <li><a href="#unreachable-basics">Basics</a></li> - <li><a href="#unreachable-comptime">At Compile-Time</a></li> - </ul> - </li> - <li><a href="#noreturn">noreturn</a></li> - <li><a href="#functions">Functions</a> - <ul> - <li><a href="#functions-by-val-params">Pass-by-val Parameters</a> - </ul> - </li> - <li><a href="#errors">Errors</a></li> - <li><a href="#nullables">Nullables</a></li> - <li><a href="#casting">Casting</a></li> - <li><a href="#void">void</a></li> - <li><a href="#this">this</a></li> - <li><a href="#comptime">comptime</a> - <ul> - <li><a href="#introducing-compile-time-concept">Introducing the Compile-Time Concept</a></li> - <ul> - <li><a href="#compile-time-parameters">Compile-time parameters</a></li> - <li><a href="#compile-time-variables">Compile-time variables</a></li> - <li><a href="#compile-time-expressions">Compile-time expressions</a></li> - </ul> - <li><a href="#generic-data-structures">Generic Data Structures</a></li> - <li><a href="#case-study-printf">Case Study: printf in Zig</a></li> - </ul> - </li> - <li><a href="#inline">inline</a></li> - <li><a href="#assembly">assembly</a></li> - <li><a href="#atomics">Atomics</a></li> - <li><a href="#builtin-functions">Builtin Functions</a> - <ul> - <li><a href="#builtin-addWithOverflow">@addWithOverflow</a></li> - <li><a href="#builtin-alignCast">@alignCast</a></li> - <li><a href="#builtin-alignOf">@alignOf</a></li> - <li><a href="#builtin-ArgType">@ArgType</a></li> - <li><a href="#builtin-bitCast">@bitCast</a></li> - <li><a href="#builtin-breakpoint">@breakpoint</a></li> - <li><a href="#builtin-cDefine">@cDefine</a></li> - <li><a href="#builtin-cImport">@cImport</a></li> - <li><a href="#builtin-cInclude">@cInclude</a></li> - <li><a href="#builtin-cUndef">@cUndef</a></li> - <li><a href="#builtin-canImplicitCast">@canImplicitCast</a></li> - <li><a href="#builtin-clz">@clz</a></li> - <li><a href="#builtin-cmpxchg">@cmpxchg</a></li> - <li><a href="#builtin-compileError">@compileError</a></li> - <li><a href="#builtin-compileLog">@compileLog</a></li> - <li><a href="#builtin-ctz">@ctz</a></li> - <li><a href="#builtin-divExact">@divExact</a></li> - <li><a href="#builtin-divFloor">@divFloor</a></li> - <li><a href="#builtin-divTrunc">@divTrunc</a></li> - <li><a href="#builtin-embedFile">@embedFile</a></li> - <li><a href="#builtin-export">@export</a></li> - <li><a href="#builtin-tagName">@tagName</a></li> - <li><a href="#builtin-TagType">@TagType</a></li> - <li><a href="#builtin-EnumTagType">@EnumTagType</a></li> - <li><a href="#builtin-errorName">@errorName</a></li> - <li><a href="#builtin-errorReturnTrace">@errorReturnTrace</a></li> - <li><a href="#builtin-fence">@fence</a></li> - <li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li> - <li><a href="#builtin-frameAddress">@frameAddress</a></li> - <li><a href="#builtin-import">@import</a></li> - <li><a href="#builtin-inlineCall">@inlineCall</a></li> - <li><a href="#builtin-intToPtr">@intToPtr</a></li> - <li><a href="#builtin-IntType">@IntType</a></li> - <li><a href="#builtin-maxValue">@maxValue</a></li> - <li><a href="#builtin-memberCount">@memberCount</a></li> - <li><a href="#builtin-memberName">@memberName</a></li> - <li><a href="#builtin-memberType">@memberType</a></li> - <li><a href="#builtin-memcpy">@memcpy</a></li> - <li><a href="#builtin-memset">@memset</a></li> - <li><a href="#builtin-minValue">@minValue</a></li> - <li><a href="#builtin-mod">@mod</a></li> - <li><a href="#builtin-mulWithOverflow">@mulWithOverflow</a></li> - <li><a href="#builtin-noInlineCall">@noInlineCall</a></li> - <li><a href="#builtin-offsetOf">@offsetOf</a></li> - <li><a href="#builtin-OpaqueType">@OpaqueType</a></li> - <li><a href="#builtin-panic">@panic</a></li> - <li><a href="#builtin-ptrCast">@ptrCast</a></li> - <li><a href="#builtin-ptrToInt">@ptrToInt</a></li> - <li><a href="#builtin-rem">@rem</a></li> - <li><a href="#builtin-returnAddress">@returnAddress</a></li> - <li><a href="#builtin-setDebugSafety">@setDebugSafety</a></li> - <li><a href="#builtin-setEvalBranchQuota">@setEvalBranchQuota</a></li> - <li><a href="#builtin-setFloatMode">@setFloatMode</a></li> - <li><a href="#builtin-setGlobalLinkage">@setGlobalLinkage</a></li> - <li><a href="#builtin-setGlobalSection">@setGlobalSection</a></li> - <li><a href="#builtin-shlExact">@shlExact</a></li> - <li><a href="#builtin-shlWithOverflow">@shlWithOverflow</a></li> - <li><a href="#builtin-shrExact">@shrExact</a></li> - <li><a href="#builtin-sizeOf">@sizeOf</a></li> - <li><a href="#builtin-subWithOverflow">@subWithOverflow</a></li> - <li><a href="#builtin-truncate">@truncate</a></li> - <li><a href="#builtin-typeId">@typeId</a></li> - <li><a href="#builtin-typeName">@typeName</a></li> - <li><a href="#builtin-typeOf">@typeOf</a></li> - </ul> - </li> - <li><a href="#build-mode">Build Mode</a> - <ul> - <li><a href="#build-mode-debug">Debug</a></li> - <li><a href="#build-mode-release-fast">ReleaseFast</a></li> - <li><a href="#build-mode-release-safe">ReleaseSafe</a></li> - </ul> - </li> - <li><a href="#undefined-behavior">Undefined Behavior</a> - <ul> - <li><a href="#undef-unreachable">Reaching Unreachable Code</a></li> - <li><a href="#undef-index-out-of-bounds">Index out of Bounds</a></li> - <li><a href="#undef-cast-negative-unsigned">Cast Negative Number to Unsigned Integer</a></li> - <li><a href="#undef-cast-truncates-data">Cast Truncates Data</a></li> - <li><a href="#undef-integer-overflow">Integer Overflow</a> - <ul> - <li><a href="#undef-int-overflow-default">Default Operations</a></li> - <li><a href="#undef-int-overflow-std">Standard Library Math Functions</a></li> - <li><a href="#undef-int-overflow-builtin">Builtin Overflow Functions</a></li> - <li><a href="#undef-int-overflow-wrap">Wrapping Operations</a></li> - - </ul> - </li> - <li><a href="#undef-shl-overflow">Exact Left Shift Overflow</a></li> - <li><a href="#undef-shr-overflow">Exact Right Shift Overflow</a></li> - <li><a href="#undef-division-by-zero">Division by Zero</a></li> - <li><a href="#undef-remainder-division-by-zero">Remainder Division by Zero</a></li> - <li><a href="#undef-exact-division-remainder">Exact Division Remainder</a></li> - <li><a href="#undef-slice-widen-remainder">Slice Widen Remainder</a></li> - <li><a href="#undef-attempt-unwrap-null">Attempt to Unwrap Null</a></li> - <li><a href="#undef-attempt-unwrap-error">Attempt to Unwrap Error</a></li> - <li><a href="#undef-invalid-error-code">Invalid Error Code</a></li> - <li><a href="#undef-invalid-enum-cast">Invalid Enum Cast</a></li> - <li><a href="#undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</a></li> - <li><a href="#undef-bad-union-field">Wrong Union Field Access</a></li> - </ul> - </li> - <li><a href="#memory">Memory</a></li> - <li><a href="#compile-variables">Compile Variables</a></li> - <li><a href="#root-source-file">Root Source File</a></li> - <li><a href="#zig-test">Zig Test</a></li> - <li><a href="#zig-build-system">Zig Build System</a></li> - <li><a href="#c">C</a> - <ul> - <li><a href="#c-type-primitives">C Type Primitives</a></li> - <li><a href="#c-string-literals">C String Literals</a></li> - <li><a href="#c-import">Import from C Header File</a></li> - <li><a href="#mixing-object-files">Mixing Object Files</a></li> - </ul> - </li> - <li><a href="#targets">Targets</a></li> - <li><a href="#style-guide">Style Guide</a> - <ul> - <li><a href="#style-guide-whitespace">Whitespace</a></li> - <li><a href="#style-guide-names">Names</a></li> - <li><a href="#style-guide-examples">Examples</a></li> - </ul> - </li> - <li><a href="#grammar">Grammar</a></li> - <li><a href="#zen">Zen</a></li> - </ul> + {#nav#} </div> <div id="contents"> - <h1 id="introduction">Zig Documentation</h1> + {#header_open|Introduction#} <p> Zig is an open-source programming language designed for <strong>robustness</strong>, <strong>optimality</strong>, and <strong>clarity</strong>. @@ -264,37 +53,35 @@ If you search for something specific in this documentation and do not find it, please <a href="https://github.com/zig-lang/www.ziglang.org/issues/new?title=I%20searched%20for%20___%20in%20the%20docs%20and%20didn%27t%20find%20it">file an issue</a> or <a href="https://webchat.freenode.net/?channels=%23zig">say something on IRC</a>. </p> - <h2 id="hello-world">Hello World</h2> - <pre><code class="zig">const std = @import("std"); + {#header_close#} + {#header_open|Hello World#} -pub fn main() -> %void { + {#code_begin|exe|hello#} +const std = @import("std"); + +pub fn main() -> %void { // If this program is run without stdout attached, exit with an error. var stdout_file = try std.io.getStdOut(); // If this program encounters pipe failure when printing to stdout, exit // with an error. try stdout_file.write("Hello, world!\n"); -}</code></pre> - <pre><code class="sh">$ zig build-exe hello.zig -$ ./hello -Hello, world!</code></pre> +} + {#code_end#} <p> Usually you don't want to write to stdout. You want to write to stderr. And you don't care if it fails. It's more like a <em>warning message</em> that you want to emit. For that you can use a simpler API: </p> - <pre><code class="zig">const warn = @import("std").debug.warn; + {#code_begin|exe|hello#} +const warn = @import("std").debug.warn; -pub fn main() -> %void { +pub fn main() -> %void { warn("Hello, world!\n"); -}</code></pre> - <p>See also:</p> - <ul> - <li><a href="#values">Values</a></li> - <li><a href="#builtin-import">@import</a></li> - <li><a href="#errors">Errors</a></li> - <li><a href="#root-source-file">Root Source File</a></li> - </ul> - <h2 id="source-encoding">Source Encoding</h2> +} + {#code_end#} + {#see_also|Values|@import|Errors|Root Source File#} + {#header_close#} + {#header_open|Source Encoding#} <p>Zig source code is encoded in UTF-8. An invalid UTF-8 byte sequence results in a compile error.</p> <p>Throughout all zig source code (including in comments), some codepoints are never allowed:</p> <ul> @@ -303,15 +90,18 @@ pub fn main() -> %void { </ul> <p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possbly the last line of the file).</p> <p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/zig-lang/zig/issues/663">issue #663</a></p> - <h2 id="values">Values</h2> - <pre><code class="zig">const warn = @import("std").debug.warn; -const os = @import("std").os; -const assert = @import("std").debug.assert; + {#header_close#} + {#header_open|Values#} + {#code_begin|exe|values#} +const std = @import("std"); +const warn = std.debug.warn; +const os = std.os; +const assert = std.debug.assert; // error declaration, makes `error.ArgNotFound` available error ArgNotFound; -pub fn main() -> %void { +pub fn main() -> %void { // integers const one_plus_one: i32 = 1 + 1; warn("1 + 1 = {}\n", one_plus_one); @@ -349,31 +139,9 @@ pub fn main() -> %void { warn("\nerror union 2\ntype: {}\nvalue: {}\n", @typeName(@typeOf(number_or_error)), number_or_error); -}</code></pre> - <pre><code class="sh">$ zig build-exe values.zig -$ ./values -1 + 1 = 2 -7.0 / 3.0 = 2.333333 -false -true -false - -nullable 1 -type: ?[]const u8 -value: null - -nullable 2 -type: ?[]const u8 -value: hi - -error union 1 -type: %i32 -value: error.ArgNotFound - -error union 2 -type: %i32 -value: 1234</code></pre> - <h3 id="primitive-types">Primitive Types</h2> +} + {#code_end#} + {#header_open|Primitive Types#} <table> <tr> <th> @@ -599,14 +367,9 @@ value: 1234</code></pre> <td>an error code</td> </tr> </table> - <p>See also:</p> - <ul> - <li><a href="#integers">Integers</a></li> - <li><a href="#floats">Floats</a></li> - <li><a href="#void">void</a></li> - <li><a href="#errors">Errors</a></li> - </ul> - <h3 id="primitive-values">Primitive Values</h3> + {#see_also|Integers|Floats|void|Errors#} + {#header_close#} + {#header_open|Primitive Values#} <table> <tr> <th> @@ -633,12 +396,9 @@ value: 1234</code></pre> <td>refers to the thing in immediate scope</td> </tr> </table> - <p>See also:</p> - <ul> - <li><a href="#nullables">Nullables</a></li> - <li><a href="#this">this</a></li> - </ul> - <h3 id="string-literals">String Literals</h3> + {#see_also|Nullables|this#} + {#header_close#} + {#header_open|String Literals#} <pre><code class="zig">const assert = @import("std").debug.assert; const mem = @import("std").mem; @@ -658,12 +418,8 @@ test "string literals" { }</code></pre> <pre><code class="sh">$ zig test string_literals.zig Test 1/1 string literals...OK</code></pre> - <p>See also:</p> - <ul> - <li><a href="#arrays">Arrays</a></li> - <li><a href="#zig-test">Zig Test</a></li> - </ul> - <h4 id="string-literal-escapes">Escape Sequences</h4> + {#see_also|Arrays|Zig Test#} + {#header_open|Escape Sequences#} <table> <tr> <th> @@ -711,7 +467,8 @@ Test 1/1 string literals...OK</code></pre> </tr> </table> <p>Note that the maximum valid Unicode point is <code>0x10ffff</code>.</p> - <h4 id="multiline-string-literals">Multiline String Literals</h4> + {#header_close#} + {#header_open|Multiline String Literals#} <p> Multiline string literals have no escapes and can span across multiple lines. To start a multiline string literal, use the <code>\\</code> token. Just like a comment, @@ -743,11 +500,10 @@ Test 1/1 string literals...OK</code></pre> In this example the variable <code>c_string_literal</code> has type <code>&const char</code> and has a terminating null byte. </p> - <p>See also:</p> - <ul> - <li><a href="#builtin-embedFile">@embedFile</a></li> - </ul> - <h3 id="values-assignment">Assignment</h3> + {#see_also|@embedFile#} + {#header_close#} + {#header_close#} + {#header_open|Assignment#} <p>Use <code>const</code> to assign a value to an identifier:</p> <pre><code class="zig">const x = 1234; @@ -798,14 +554,17 @@ test "init with undefined" { }</code></pre> <pre><code class="sh">$ zig test test.zig Test 1/1 init with undefined...OK</code></pre> - <h2 id="integers">Integers</h2> - <h3 id="integer-literals">Integer Literals</h3> + {#header_close#} + {#header_close#} + {#header_open|Integers#} + {#header_open|Integer Literals#} <pre><code class="zig">const decimal_int = 98222; const hex_int = 0xff; const another_hex_int = 0xFF; const octal_int = 0o755; const binary_int = 0b11110000;</code></pre> - <h3 id="runtime-integer-values">Runtime Integer Values</h3> + {#header_close#} + {#header_open|Runtime Integer Values#} <p> Integer literals have no size limitation, and if any undefined behavior occurs, the compiler catches it. @@ -827,14 +586,12 @@ const binary_int = 0b11110000;</code></pre> integer overflow. Also available are operations such as <code>+%</code> and <code>-%</code> which are defined to have wrapping arithmetic on all targets. </p> - <p>See also:</p> - <ul> - <li><a href="#undef-integer-overflow">Integer Overflow</a></li> - <li><a href="#undef-division-by-zero">Division By Zero</a></li> - <li><a href="#undef-int-overflow-wrap">Wrapping Operations</a></li> - </ul> - <h2 id="floats">Floats</h2> - <h3 id="float-literals">Float Literals</h3> + {#see_also|Integer Overflow|Division by Zero|Wrapping Operations#} + {#header_close#} + {#header_close#} + {#header_open|Floats#} + {#header_close#} + {#header_open|Float Literals#} <pre><code class="zig">const floating_point = 123.0E+77; const another_float = 123.0; const yet_another = 123.0e+77; @@ -842,7 +599,8 @@ const yet_another = 123.0e+77; const hex_floating_point = 0x103.70p-5; const another_hex_float = 0x103.70; const yet_another_hex_float = 0x103.70P-5;</code></pre> - <h3 id="float-operations">Floating Point Operations</h3> + {#header_close#} + {#header_open|Floating Point Operations#} <p>By default floating point operations use <code>Optimized</code> mode, but you can switch to <code>Strict</code> mode on a per-block basis:</p> <p>foo.zig</p> @@ -876,13 +634,10 @@ $ zig build-exe test.zig --object foo.o $ ./test optimized = 1.0e-2 strict = 9.765625e-3</code></pre> - <p>See also:</p> - <ul> - <li><a href="#builtin-setFloatMode">@setFloatMode</a></li> - <li><a href="#undef-division-by-zero">Division By Zero</a></li> - </ul> - <h2 id="operators">Operators</h2> - <h3 id="operators-table">Table of Operators</h2> + {#see_also|@setFloatMode|Division by Zero#} + {#header_close#} + {#header_open|Operators#} + {#header_open|Table of Operators#} <table> <tr> <th> @@ -1470,7 +1225,8 @@ const ptr = &x; </td> </tr> </table> - <h3 id="operators-precedence">Precedence</h3> + {#header_close#} + {#header_open|Precedence#} <pre><code>x() x[] x.y !x -x -%x ~x *x &x ?x %x %%x ??x x{} @@ -1485,7 +1241,9 @@ and or ?? catch = *= /= %= += -= <<= >>= &= ^= |=</code></pre> - <h2 id="arrays">Arrays</h2> + {#header_close#} + {#header_close#} + {#header_open|Arrays#} <pre><code class="zig">const assert = @import("std").debug.assert; const mem = @import("std").mem; @@ -1594,12 +1352,9 @@ Test 1/4 iterate over an array...OK Test 2/4 modify an array...OK Test 3/4 compile-time array initalization...OK Test 4/4 array initialization with function calls...OK</code></pre> - <p>See also:</p> - <ul> - <li><a href="#for">for</a></li> - <li><a href="#slices">Slices</a></li> - </ul> - <h2 id="pointers">Pointers</h2> + {#see_also|for|Slices#} + {#header_close#} + {#header_open|Pointers#} <pre><code class="zig">const assert = @import("std").debug.assert; test "address of syntax" { @@ -1737,7 +1492,7 @@ Test 5/8 volatile...OK Test 6/8 nullable pointers...OK Test 7/8 pointer casting...OK Test 8/8 pointer child type...OK</code></pre> - <h3 id="alignment">Alignment</h3> + {#header_open|Alignment#} <p> Each type has an <strong>alignment</strong> - a number of bytes such that, when a value of the type is loaded from or stored to memory, @@ -1838,7 +1593,8 @@ Test 1/1 pointer alignment safety...incorrect alignment Tests failed. Use the following command to reproduce the failure: ./test</code></pre> - <h3 id="type-based-alias-analysis">Type Based Alias Analysis</h3> + {#header_close#} + {#header_open|Type Based Alias Analysis#} <p>Zig uses Type Based Alias Analysis (also known as Strict Aliasing) to perform some optimizations. This means that pointers of different types must not alias the same memory, with the exception of <code>u8</code>. Pointers to @@ -1849,12 +1605,10 @@ Tests failed. Use the following command to reproduce the failure: <p>Instead, use <a href="#builtin-bitCast">@bitCast</a>: <pre><code class="zig">@bitCast(u32, f32(12.34))</code></pre> <p>As an added benefit, the <code>@bitcast</code> version works at compile-time.</p> - <p>See also:</p> - <ul> - <li><a href="#slices">Slices</a></li> - <li><a href="#memory">Memory</a></li> - </ul> - <h2 id="slices">Slices</h2> + {#see_also|Slices|Memory#} + {#header_close#} + {#header_close#} + {#header_open|Slices#} <pre><code class="zig">const assert = @import("std").debug.assert; test "basic slices" { @@ -1948,13 +1702,9 @@ test "slice widening" { Test 1/3 using slices for strings...OK Test 2/3 slice pointer...OK Test 3/3 slice widening...OK</code></pre> - <p>See also:</p> - <ul> - <li><a href="#pointers">Pointers</a></li> - <li><a href="#for">for</a></li> - <li><a href="#arrays">Arrays</a></li> - </ul> - <h2 id="struct">struct</h2> + {#see_also|Pointers|for|Arrays#} + {#header_close#} + {#header_open|struct#} <pre><code class="zig">// Declare a struct. // Zig gives no guarantees about the order of fields and whether or // not there will be padding. @@ -2094,12 +1844,9 @@ Test 1/4 dot product...OK Test 2/4 struct namespaced variable...OK Test 3/4 field parent pointer...OK Test 4/4 linked list...OK</code></pre> - <p>See also:</p> - <ul> - <li><a href="#comptime">comptime</a></li> - <li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li> - </ul> - <h2 id="enum">enum</h2> + {#see_also|comptime|@fieldParentPtr#} + {#header_close#} + {#header_open|enum#} <pre><code class="zig">const assert = @import("std").debug.assert; const mem = @import("std").mem; @@ -2210,13 +1957,9 @@ Test 5/8 @TagType...OK Test 6/8 @memberCount...OK Test 7/8 @memberName...OK Test 8/8 @tagName...OK</code></pre> - <p>See also:</p> - <ul> - <li><a href="#builtin-memberName">@memberName</a></li> - <li><a href="#builtin-memberCount">@memberCount</a></li> - <li><a href="#builtin-tagName">@tagName</a></li> - </ul> - <h2 id="union">union</h2> + {#see_also|@memberName|@memberCount|@tagName#} + {#header_close#} + {#header_open|union#} <pre><code class="zig">const assert = @import("std").debug.assert; const mem = @import("std").mem; @@ -2323,7 +2066,8 @@ Test 7/7 @tagName...OK</code></pre> Unions with an enum tag are generated as a struct with a tag field and union field. Zig sorts the order of the tag and union field by the largest alignment. </p> - <h2 id="switch">switch</h2> + {#header_close#} + {#header_open|switch#} <pre><code class="zig">const assert = @import("std").debug.assert; const builtin = @import("builtin"); @@ -2419,14 +2163,9 @@ test "switch inside function" { Test 1/2 switch simple...OK Test 2/2 switch enum...OK Test 3/3 switch inside function...OK</code></pre> - <p>See also:</p> - <ul> - <li><a href="#comptime">comptime</a></li> - <li><a href="#enum">enum</a></li> - <li><a href="#builtin-compileError">@compileError</a></li> - <li><a href="#compile-variables">Compile Variables</a></li> - </ul> - <h2 id="while">while</h2> + {#see_also|comptime|enum|@compileError|Compile Variables#} + {#header_close#} + {#header_open|while#} <pre><code class="zig">const assert = @import("std").debug.assert; test "while basic" { @@ -2587,15 +2326,9 @@ Test 5/8 while loop continuation expression, more complicated...OK Test 6/8 while else...OK Test 7/8 while null capture...OK Test 8/8 inline while loop...OK</code></pre> - <p>See also:</p> - <ul> - <li><a href="#if">if</a></li> - <li><a href="#nullables">Nullables</a></li> - <li><a href="#errors">Errors</a></li> - <li><a href="#comptime">comptime</a></li> - <li><a href="#unreachable">unreachable</a></li> - </ul> - <h2 id="for">for</h2> + {#see_also|if|Nullables|Errors|comptime|unreachable#} + {#header_close#} + {#header_open|for#} <pre><code class="zig">const assert = @import("std").debug.assert; test "for basics" { @@ -2689,14 +2422,9 @@ Test 1/4 for basics...OK Test 2/4 for reference...OK Test 3/4 for else...OK Test 4/4 inline for loop...OK</code></pre> - <p>See also:</p> - <ul> - <li><a href="#while">while</a></li> - <li><a href="#comptime">comptime</a></li> - <li><a href="#arrays">Arrays</a></li> - <li><a href="#slices">Slices</a></li> - </ul> - <h2 id="if">if</h2> + {#see_also|while|comptime|Arrays|Slices#} + {#header_close#} + {#header_open|if#} <pre><code class="zig">// If expressions have three uses, corresponding to the three types: // * bool // * ?T @@ -2809,28 +2537,9 @@ test "if error union" { Test 1/3 if boolean...OK Test 2/3 if nullable...OK Test 3/3 if error union...OK</code></pre> - <p>See also:</p> - <ul> - <li><a href="#nullables">Nullables</a></li> - <li><a href="#errors">Errors</a></li> - </ul> - <h2 id="goto">goto</h2> - <pre><code class="zig">const assert = @import("std").debug.assert; - -test "goto" { - var value = false; - goto label; - value = true; - -label: - assert(value == false); -} -</code></pre> - <pre><code class="sh">$ zig test goto.zig -Test 1/1 goto...OK -</code></pre> -<p>Note that there are <a href="https://github.com/zig-lang/zig/issues/346">plans to remove goto</a></p> - <h2 id="defer">defer</h2> + {#see_also|Nullables|Errors#} + {#header_close#} + {#header_open|defer#} <pre><code class="zig">const assert = @import("std").debug.assert; const printf = @import("std").io.stdout.printf; @@ -2916,11 +2625,9 @@ encountered an error! end of function OK </code></pre> - <p>See also:</p> - <ul> - <li><a href="#errors">Errors</a></li> - </ul> - <h2 id="unreachable">unreachable</h2> + {#see_also|Errors#} + {#header_close#} + {#header_open|unreachable#} <p> In <code>Debug</code> and <code>ReleaseSafe</code> mode, and when using <code>zig test</code>, <code>unreachable</code> emits a call to <code>panic</code> with the message <code>reached unreachable code</code>. @@ -2930,7 +2637,7 @@ OK will never be hit to perform optimizations. However, <code>zig test</code> even in <code>ReleaseFast</code> mode still emits <code>unreachable</code> as calls to <code>panic</code>. </p> - <h3 id="unreachable-basics">Basics</h3> + {#header_open|Basics#} <pre><code class="zig">// unreachable is used to assert that control flow will never happen upon a // particular location: test "basic math" { @@ -2974,7 +2681,8 @@ lib/zig/std/special/bootstrap.zig:34:25: 0x0000000000214750 in ??? (test) Tests failed. Use the following command to reproduce the failure: ./test</code></pre> - <h3 id="unreachable-comptime">At Compile-Time</h3> + {#header_close#} + {#header_open|At Compile-Time#} <pre><code class="zig">const assert = @import("std").debug.assert; comptime { @@ -2989,13 +2697,10 @@ comptime { test.zig:9:12: error: unreachable code assert(@typeOf(unreachable) == noreturn); ^</code></pre> - <p>See also:</p> - <ul> - <li><a href="#zig-test">Zig Test</a></li> - <li><a href="#build-mode">Build Mode</a></li> - <li><a href="#comptime">comptime</a></li> - </ul> - <h2 id="noreturn">noreturn</h2> + {#see_also|Zig Test|Build Mode|comptime#} + {#header_close#} + {#header_close#} + {#header_open|noreturn#} <p> <code>noreturn</code> is the type of: </p> @@ -3029,7 +2734,8 @@ fn bar() -> %u32 { } const assert = @import("std").debug.assert;</code></pre> - <h2 id="functions">Functions</h2> + {#header_close#} + {#header_open|Functions#} <pre><code class="zig">const assert = @import("std").debug.assert; // Functions are declared like this @@ -3091,7 +2797,7 @@ comptime { fn foo() { }</code></pre> <pre><code class="sh">$ zig build-obj test.zig</code></pre> - <h3 id="functions-by-val-params">Pass-by-value Parameters</h3> + {#header_open|Pass-by-value Parameters#} <p> In Zig, structs, unions, and enums with payloads cannot be passed by value to a function. @@ -3127,7 +2833,9 @@ export fn entry() { the C ABI does allow passing structs and unions by value. So functions which use the C calling convention may pass structs and unions by value. </p> - <h2 id="errors">Errors</h2> + {#header_close#} + {#header_close#} + {#header_open|Errors#} <p> One of the distinguishing features of Zig is its exception handling strategy. </p> @@ -3315,13 +3023,9 @@ pub fn parseU64(buf: []const u8, radix: u8) -> %u64 { in other languages. </li> </ul> - <p>See also:</p> - <ul> - <li><a href="#defer">defer</a></li> - <li><a href="#if">if</a></li> - <li><a href="#switch">switch</a></li> - </ul> - <h2 id="nullables">Nullables</h2> + {#see_also|defer|if|switch#} + {#header_close#} + {#header_open|Nullables#} <p> One area that Zig provides safety without compromising efficiency or readability is with the nullable type. @@ -3415,7 +3119,8 @@ fn doAThing() -> ?&Foo { The optimizer can sometimes make better decisions knowing that pointer arguments cannot be null. </p> - <h2 id="casting">Casting</h2> + {#header_close#} + {#header_open|Casting#} <p>TODO: explain implicit vs explicit casting</p> <p>TODO: resolve peer types builtin</p> <p>TODO: truncate builtin</p> @@ -3424,24 +3129,27 @@ fn doAThing() -> ?&Foo { <p>TODO: ptr to int builtin</p> <p>TODO: ptrcast builtin</p> <p>TODO: explain number literals vs concrete types</p> - <h2 id="void">void</h2> + {#header_close#} + {#header_open|void#} <p>TODO: assigning void has no codegen</p> <p>TODO: hashmap with void becomes a set</p> <p>TODO: difference between c_void and void</p> <p>TODO: void is the default return value of functions</p> <p>TODO: functions require assigning the return value</p> - <h2 id="this">this</h2> + {#header_close#} + {#header_open|this#} <p>TODO: example of this referring to Self struct</p> <p>TODO: example of this referring to recursion function</p> <p>TODO: example of this referring to basic block for @setDebugSafety</p> - <h2 id="comptime">comptime</h2> + {#header_close#} + {#header_open|comptime#} <p> Zig places importance on the concept of whether an expression is known at compile-time. There are a few different places this concept is used, and these building blocks are used to keep the language small, readable, and powerful. </p> - <h3 id="introducing-compile-time-concept">Introducing the Compile-Time Concept</h3> - <h4 id="compile-time-parameters">Compile-Time Parameters</h4> + {#header_open|Introducing the Compile-Time Concept#} + {#header_open|Compile-Time Parameters#} <p> Compile-time parameters is how Zig implements generics. It is compile-time duck typing. </p> @@ -3549,7 +3257,8 @@ fn letsTryToCompareBools(a: bool, b: bool) -> bool { This works the same way for <code>switch</code> expressions - they are implicitly inlined when the target expression is compile-time known. </p> - <h4 id="compile-time-variables">Compile-Time Variables</h4> + {#header_close#} + {#header_open|Compile-Time Variables#} <p> In Zig, the programmer can label variables as <code>comptime</code>. This guarantees to the compiler that every load and store of the variable is performed at compile-time. Any violation of this results in a @@ -3631,7 +3340,8 @@ fn performFn(start_value: i32) -> i32 { later in this article, allows expressiveness that in other languages requires using macros, generated code, or a preprocessor to accomplish. </p> - <h4 id="compile-time-expressions">Compile-Time Expressions</h4> + {#header_close#} + {#header_open|Compile-Time Expressions#} <p> In Zig, it matters whether a given expression is known at compile-time or run-time. A programmer can use a <code>comptime</code> expression to guarantee that the expression will be evaluated at compile-time. @@ -3860,7 +3570,9 @@ fn sum(numbers: []i32) -> i32 { we could call the <code>sum</code> function as is with a slice of numbers whose length and values were only known at run-time. </p> - <h3 id="generic-data-structures">Generic Data Structures</h3> + {#header_close#} + {#header_close#} + {#header_open|Generic Data Structures#} <p> Zig uses these capabilities to implement generic data structures without introducing any special-case syntax. If you followed along so far, you may already know how to create a @@ -3895,19 +3607,21 @@ fn sum(numbers: []i32) -> i32 { <code>Node</code> refers to itself as a pointer, which is not actually an infinite regression, so it works fine. </p> - <h3 id="case-study-printf">Case Study: printf in Zig</h3> + {#header_close#} + {#header_open|Case Study: printf in Zig#} <p> - Putting all of this together, let's seee how <code>printf</code> works in Zig. + Putting all of this together, let's see how <code>printf</code> works in Zig. </p> - <pre><code class="zig">const warn = @import("std").debug.warn; + {#code_begin|exe|printf#} +const warn = @import("std").debug.warn; const a_number: i32 = 1234; const a_string = "foobar"; -pub fn main(args: [][]u8) -> %void { +pub fn main() { warn("here is a string: '{}' here is a number: {}\n", a_string, a_number); -}</code></pre> - <pre><code>here is a string: 'foobar' here is a number: 1234</code></pre> +} + {#code_end#} <p> Let's crack open the implementation of this and see how it works: @@ -4027,15 +3741,17 @@ pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) -> Zig doesn't care whether the format argument is a string literal, only that it is a compile-time known value that is implicitly castable to a <code>[]const u8</code>: </p> - <pre><code class="zig">const warn = @import("std").debug.warn; + {#code_begin|exe|printf#} +const warn = @import("std").debug.warn; const a_number: i32 = 1234; const a_string = "foobar"; const fmt = "here is a string: '{}' here is a number: {}\n"; -pub fn main(args: [][]u8) -> %void { +pub fn main() { warn(fmt, a_string, a_number); -}</code></pre> +} + {#code_end#} <p> This works fine. </p> @@ -4045,35 +3761,42 @@ pub fn main(args: [][]u8) -> %void { a macro language or a preprocessor language. It's Zig all the way down. </p> <p>TODO: suggestion to not use inline unless necessary</p> - <h2 id="inline">inline</h2> + {#header_close#} + {#header_close#} + {#header_open|inline#} <p>TODO: inline while</p> <p>TODO: inline for</p> <p>TODO: suggestion to not use inline unless necessary</p> - <h2 id="assembly">Assembly</h2> + {#header_close#} + {#header_open|Assembly#} <p>TODO: example of inline assembly</p> <p>TODO: example of module level assembly</p> <p>TODO: example of using inline assembly return value</p> <p>TODO: example of using inline assembly assigning values to variables</p> - <h2 id="atomics">Atomics</h2> + {#header_close#} + {#header_open|Atomics#} <p>TODO: @fence()</p> <p>TODO: @atomic rmw</p> <p>TODO: builtin atomic memory ordering enum</p> - <h2 id="builtin-functions">Builtin Functions</h2> + {#header_close#} + {#header_open|Builtin Functions#} <p> Builtin functions are provided by the compiler and are prefixed with <code>@</code>. The <code>comptime</code> keyword on a parameter means that the parameter must be known at compile time. </p> - <h3 id="builtin-addWithOverflow">@addWithOverflow</h3> + {#header_open|@addWithOverflow#} <pre><code class="zig">@addWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool</code></pre> <p> Performs <code>*result = a + b</code>. If overflow or underflow occurs, stores the overflowed bits in <code>result</code> and returns <code>true</code>. If no overflow or underflow occurs, returns <code>false</code>. </p> - <h3 id="builtin-ArgType">@ArgType</h3> + {#header_close#} + {#header_open|@ArgType#} <p>TODO</p> - <h3 id="builtin-bitCast">@bitCast</h3> + {#header_close#} + {#header_open|@bitCast#} <pre><code class="zig">@bitCast(comptime DestType: type, value: var) -> DestType</code></pre> <p> Converts a value of one type to another type. @@ -4094,7 +3817,8 @@ pub fn main(args: [][]u8) -> %void { <p> Works at compile-time if <code>value</code> is known at compile time. It's a compile error to bitcast a struct to a scalar type of the same size since structs have undefined layout. However if the struct is packed then it works. </p> - <h3 id="builtin-breakpoint">@breakpoint</h3> + {#header_close#} + {#header_open|@breakpoint#} <pre><code class="zig">@breakpoint()</code></pre> <p> This function inserts a platform-specific debug trap instruction which causes @@ -4104,7 +3828,8 @@ pub fn main(args: [][]u8) -> %void { This function is only valid within function scope. </p> - <h3 id="builtin-alignCast">@alignCast</h3> + {#header_close#} + {#header_open|@alignCast#} <pre><code class="zig">@alignCast(comptime alignment: u29, ptr: var) -> var</code></pre> <p> <code>ptr</code> can be <code>&T</code>, <code>fn()</code>, <code>?&T</code>, @@ -4114,7 +3839,8 @@ pub fn main(args: [][]u8) -> %void { <p>A <a href="#undef-incorrect-pointer-alignment">pointer alignment safety check</a> is added to the generated code to make sure the pointer is aligned as promised.</p> - <h3 id="builtin-alignOf">@alignOf</h3> + {#header_close#} + {#header_open|@alignOf#} <pre><code class="zig">@alignOf(comptime T: type) -> (number literal)</code></pre> <p> This function returns the number of bytes that this type should be aligned to @@ -4129,12 +3855,9 @@ comptime { The result is a target-specific compile time constant. It is guaranteed to be less than or equal to <a href="#builtin-sizeOf">@sizeOf(T)</a>. </p> - <p>See also:</p> - <ul> - <li><a href="#alignment">Alignment</a></li> - </ul> - - <h3 id="builtin-cDefine">@cDefine</h3> + {#see_also|Alignment#} + {#header_close#} + {#header_open|@cDefine#} <pre><code class="zig">@cDefine(comptime name: []u8, value)</code></pre> <p> This function can only occur inside <code>@cImport</code>. @@ -4151,15 +3874,9 @@ comptime { Use the void value, like this: </p> <pre><code class="zig">@cDefine("_GNU_SOURCE", {})</code></pre> - <p>See also:</p> - <ul> - <li><a href="#c-import">Import from C Header File</a></li> - <li><a href="#builtin-cInclude">@cInclude</a></li> - <li><a href="#builtin-cImport">@cImport</a></li> - <li><a href="#builtin-cUndef">@cUndef</a></li> - <li><a href="#void">void</a></li> - </ul> - <h3 id="builtin-cImport">@cImport</h3> + {#see_also|Import from C Header File|@cInclude|@cImport|@cUndef|void#} + {#header_close#} + {#header_open|@cImport#} <pre><code class="zig">@cImport(expression) -> (namespace)</code></pre> <p> This function parses C code and imports the functions, types, variables, and @@ -4170,14 +3887,9 @@ comptime { <code>@cInclude</code>, <code>@cDefine</code>, and <code>@cUndef</code> work within this expression, appending to a temporary buffer which is then parsed as C code. </p> - <p>See also:</p> - <ul> - <li><a href="#c-import">Import from C Header File</a></li> - <li><a href="#builtin-cInclude">@cInclude</a></li> - <li><a href="#builtin-cDefine">@cDefine</a></li> - <li><a href="#builtin-cUndef">@cUndef</a></li> - </ul> - <h3 id="builtin-cInclude">@cInclude</h3> + {#see_also|Import from C Header File|@cInclude|@cDefine|@cUndef#} + {#header_close#} + {#header_open|@cInclude#} <pre><code class="zig">@cInclude(comptime path: []u8)</code></pre> <p> This function can only occur inside <code>@cImport</code>. @@ -4186,14 +3898,9 @@ comptime { This appends <code>#include <$path>\n</code> to the <code>c_import</code> temporary buffer. </p> - <p>See also:</p> - <ul> - <li><a href="#c-import">Import from C Header File</a></li> - <li><a href="#builtin-cImport">@cImport</a></li> - <li><a href="#builtin-cDefine">@cDefine</a></li> - <li><a href="#builtin-cUndef">@cUndef</a></li> - </ul> - <h3 id="builtin-cUndef">@cUndef</h3> + {#see_also|Import from C Header File|@cImport|@cDefine|@cUndef#} + {#header_close#} + {#header_open|@cUndef#} <pre><code class="zig">@cUndef(comptime name: []u8)</code></pre> <p> This function can only occur inside <code>@cImport</code>. @@ -4202,19 +3909,15 @@ comptime { This appends <code>#undef $name</code> to the <code>@cImport</code> temporary buffer. </p> - <p>See also:</p> - <ul> - <li><a href="#c-import">Import from C Header File</a></li> - <li><a href="#builtin-cImport">@cImport</a></li> - <li><a href="#builtin-cDefine">@cDefine</a></li> - <li><a href="#builtin-cInclude">@cInclude</a></li> - </ul> - <h3 id="builtin-canImplicitCast">@canImplicitCast</h3> + {#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#} + {#header_close#} + {#header_open|@canImplicitCast#} <pre><code class="zig">@canImplicitCast(comptime T: type, value) -> bool</code></pre> <p> Returns whether a value can be implicitly casted to a given type. </p> - <h3 id="builtin-clz">@clz</h3> + {#header_close#} + {#header_open|@clz#} <pre><code class="zig">@clz(x: T) -> U</code></pre> <p> This function counts the number of leading zeroes in <code>x</code> which is an integer @@ -4228,7 +3931,8 @@ comptime { If <code>x</code> is zero, <code>@clz</code> returns <code>T.bit_count</code>. </p> - <h3 id="builtin-cmpxchg">@cmpxchg</h3> + {#header_close#} + {#header_open|@cmpxchg#} <pre><code class="zig">@cmpxchg(ptr: &T, cmp: T, new: T, success_order: AtomicOrder, fail_order: AtomicOrder) -> bool</code></pre> <p> This function performs an atomic compare exchange operation. @@ -4237,12 +3941,9 @@ comptime { <code>AtomicOrder</code> can be found with <code>@import("builtin").AtomicOrder</code>. </p> <p><code>@typeOf(ptr).alignment</code> must be <code>>= @sizeOf(T).</code></p> - <p>See also:</p> - <ul> - <li><a href="#compile-variables">Compile Variables</a></li> - </ul> - - <h3 id="builtin-compileError">@compileError</h3> + {#see_also|Compile Variables#} + {#header_close#} + {#header_open|@compileError#} <pre><code class="zig">@compileError(comptime msg: []u8)</code></pre> <p> This function, when semantically analyzed, causes a compile error with the @@ -4253,7 +3954,8 @@ comptime { using <code>if</code> or <code>switch</code> with compile time constants, and <code>comptime</code> functions. </p> - <h3 id="builtin-compileLog">@compileLog</h3> + {#header_close#} + {#header_open|@compileLog#} <pre><code class="zig">@compileLog(args: ...)</code></pre> <p> This function prints the arguments passed to it at compile-time. @@ -4303,7 +4005,7 @@ test.zig:6:2: error: found compile log statement program compiles successfully and the generated executable prints: </p> <pre><code class="sh">Runtime in main, num1 = 100.</code></pre> - <h3 id="builtin-ctz">@ctz</h3> +{{@ctheader_open:z}} <pre><code class="zig">@ctz(x: T) -> U</code></pre> <p> This function counts the number of trailing zeroes in <code>x</code> which is an integer @@ -4316,7 +4018,8 @@ test.zig:6:2: error: found compile log statement <p> If <code>x</code> is zero, <code>@ctz</code> returns <code>T.bit_count</code>. </p> - <h3 id="builtin-divExact">@divExact</h3> + {#header_close#} + {#header_open|@divExact#} <pre><code class="zig">@divExact(numerator: T, denominator: T) -> T</code></pre> <p> Exact division. Caller guarantees <code>denominator != 0</code> and @@ -4326,13 +4029,10 @@ test.zig:6:2: error: found compile log statement <li><code>@divExact(6, 3) == 2</code></li> <li><code>@divExact(a, b) * b == a</code></li> </ul> - <p>See also:</p> - <ul> - <li><a href="#builtin-divTrunc">@divTrunc</a></li> - <li><a href="#builtin-divFloor">@divFloor</a></li> - <li><code>@import("std").math.divExact</code></li> - </ul> - <h3 id="builtin-divFloor">@divFloor</h3> + <p>For a function that returns a possible error code, use <code>@import("std").math.divExact</code>.</p> + {#see_also|@divTrunc|@divFloor#} + {#header_close#} + {#header_open|@divFloor#} <pre><code class="zig">@divFloor(numerator: T, denominator: T) -> T</code></pre> <p> Floored division. Rounds toward negative infinity. For unsigned integers it is @@ -4343,13 +4043,10 @@ test.zig:6:2: error: found compile log statement <li><code>@divFloor(-5, 3) == -2</code></li> <li><code>@divFloor(a, b) + @mod(a, b) == a</code></li> </ul> - <p>See also:</p> - <ul> - <li><a href="#builtin-divTrunc">@divTrunc</a></li> - <li><a href="#builtin-divExact">@divExact</a></li> - <li><code>@import("std").math.divFloor</code></li> - </ul> - <h3 id="builtin-divTrunc">@divTrunc</h3> + <p>For a function that returns a possible error code, use <code>@import("std").math.divFloor</code>.</p> + {#see_also|@divTrunc|@divExact#} + {#header_close#} + {#header_open|@divTrunc#} <pre><code class="zig">@divTrunc(numerator: T, denominator: T) -> T</code></pre> <p> Truncated division. Rounds toward zero. For unsigned integers it is @@ -4360,13 +4057,10 @@ test.zig:6:2: error: found compile log statement <li><code>@divTrunc(-5, 3) == -1</code></li> <li><code>@divTrunc(a, b) + @rem(a, b) == a</code></li> </ul> - <p>See also:</p> - <ul> - <li><a href="#builtin-divFloor">@divFloor</a></li> - <li><a href="#builtin-divExact">@divExact</a></li> - <li><code>@import("std").math.divTrunc</code></li> - </ul> - <h3 id="builtin-embedFile">@embedFile</h3> + <p>For a function that returns a possible error code, use <code>@import("std").math.divTrunc</code>.</p> + {#see_also|@divFloor|@divExact#} + {#header_close#} + {#header_open|@embedFile#} <pre><code class="zig">@embedFile(comptime path: []const u8) -> [X]u8</code></pre> <p> This function returns a compile time constant fixed-size array with length @@ -4376,21 +4070,21 @@ test.zig:6:2: error: found compile log statement <p> <code>path</code> is absolute or relative to the current file, just like <code>@import</code>. </p> - <p>See also:</p> - <ul> - <li><a href="#builtin-import">@import</a></li> - </ul> - <h3 id="builtin-export">@export</h3> + {#see_also|@import#} + {#header_close#} + {#header_open|@export#} <pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) -> []const u8</code></pre> <p> Creates a symbol in the output object file. </p> - <h3 id="builtin-tagName">@tagName</h3> + {#header_close#} + {#header_open|@tagName#} <pre><code class="zig">@tagName(value: var) -> []const u8</code></pre> <p> Converts an enum value or union value to a slice of bytes representing the name. </p> - <h3 id="builtin-TagType">@TagType</h3> + {#header_close#} + {#header_open|@TagType#} <pre><code class="zig">@TagType(T: type) -> type</code></pre> <p> For an enum, returns the integer type that is used to store the enumeration value. @@ -4398,7 +4092,8 @@ test.zig:6:2: error: found compile log statement <p> For a union, returns the enum type that is used to store the tag value. </p> - <h3 id="builtin-errorName">@errorName</h3> + {#header_close#} + {#header_open|@errorName#} <pre><code class="zig">@errorName(err: error) -> []u8</code></pre> <p> This function returns the string representation of an error. If an error @@ -4413,14 +4108,16 @@ test.zig:6:2: error: found compile log statement or all calls have a compile-time known value for <code>err</code>, then no error name table will be generated. </p> - <h3 id="builtin-errorReturnTrace">@errorReturnTrace</h3> + {#header_close#} + {#header_open|@errorReturnTrace#} <pre><code class="zig">@errorReturnTrace() -> ?&builtin.StackTrace</code></pre> <p> If the binary is built with error return tracing, and this function is invoked in a function that calls a function with an error or error union return type, returns a stack trace object. Otherwise returns `null`. </p> - <h3 id="builtin-fence">@fence</h3> + {#header_close#} + {#header_open|@fence#} <pre><code class="zig">@fence(order: AtomicOrder)</code></pre> <p> The <code>fence</code> function is used to introduce happens-before edges between operations. @@ -4428,17 +4125,16 @@ test.zig:6:2: error: found compile log statement <p> <code>AtomicOrder</code> can be found with <code>@import("builtin").AtomicOrder</code>. </p> - <p>See also:</p> - <ul> - <li><a href="#compile-variables">Compile Variables</a></li> - </ul> - <h3 id="builtin-fieldParentPtr">@fieldParentPtr</h3> + {#see_also|Compile Variables#} + {#header_close#} + {#header_open|@fieldParentPtr#} <pre><code class="zig">@fieldParentPtr(comptime ParentType: type, comptime field_name: []const u8, field_ptr: &T) -> &ParentType</code></pre> <p> Given a pointer to a field, returns the base pointer of a struct. </p> - <h3 id="builtin-frameAddress">@frameAddress</h3> + {#header_close#} + {#header_open|@frameAddress#} <pre><code class="zig">@frameAddress()</code></pre> <p> This function returns the base pointer of the current stack frame. @@ -4451,7 +4147,8 @@ test.zig:6:2: error: found compile log statement <p> This function is only valid within function scope. </p> - <h3 id="builtin-import">@import</h3> + {#header_close#} + {#header_open|@import#} <pre><code class="zig">@import(comptime path: []u8) -> (namespace)</code></pre> <p> This function finds a zig file corresponding to <code>path</code> and imports all the @@ -4469,12 +4166,9 @@ test.zig:6:2: error: found compile log statement <li><code>@import("std")</code> - Zig Standard Library</li> <li><code>@import("builtin")</code> - Compiler-provided types and variables</li> </ul> - <p>See also:</p> - <ul> - <li><a href="#compile-variables">Compile Variables</a></li> - <li><a href="#builtin-embedFile">@embedFile</a></li> - </ul> - <h3 id="builtin-inlineCall">@inlineCall</h3> + {#see_also|Compile Variables|@embedFile#} + {#header_close#} + {#header_open|@inlineCall#} <pre><code class="zig">@inlineCall(function: X, args: ...) -> Y</code></pre> <p> This calls a function, in the same way that invoking an expression with parentheses does: @@ -4489,21 +4183,21 @@ fn add(a: i32, b: i32) -> i32 { a + b }</code></pre> Unlike a normal function call, however, <code>@inlineCall</code> guarantees that the call will be inlined. If the call cannot be inlined, a compile error is emitted. </p> - <p>See also:</p> - <ul> - <li><a href="#builtin-noInlineCall">@noInlineCall</a></li> - </ul> - <h3 id="builtin-intToPtr">@intToPtr</h3> + {#see_also|@noInlineCall#} + {#header_close#} + {#header_open|@intToPtr#} <pre><code class="zig">@intToPtr(comptime DestType: type, int: usize) -> DestType</code></pre> <p> Converts an integer to a pointer. To convert the other way, use <a href="#builtin-ptrToInt">@ptrToInt</a>. </p> - <h3 id="builtin-IntType">@IntType</h3> + {#header_close#} + {#header_open|@IntType#} <pre><code class="zig">@IntType(comptime is_signed: bool, comptime bit_count: u8) -> type</code></pre> <p> This function returns an integer type with the given signness and bit count. </p> - <h3 id="builtin-maxValue">@maxValue</h3> + {#header_close#} + {#header_open|@maxValue#} <pre><code class="zig">@maxValue(comptime T: type) -> (number literal)</code></pre> <p> This function returns the maximum value of the integer type <code>T</code>. @@ -4511,7 +4205,8 @@ fn add(a: i32, b: i32) -> i32 { a + b }</code></pre> <p> The result is a compile time constant. </p> - <h3 id="builtin-memberCount">@memberCount</h3> + {#header_close#} + {#header_open|@memberCount#} <pre><code class="zig">@memberCount(comptime T: type) -> (number literal)</code></pre> <p> This function returns the number of enum values in an enum type. @@ -4519,11 +4214,14 @@ fn add(a: i32, b: i32) -> i32 { a + b }</code></pre> <p> The result is a compile time constant. </p> - <h3 id="builtin-memberName">@memberName</h3> + {#header_close#} + {#header_open|@memberName#} <p>TODO</p> - <h3 id="builtin-memberType">@memberType</h3> + {#header_close#} + {#header_open|@memberType#} <p>TODO</p> - <h3 id="builtin-memcpy">@memcpy</h3> + {#header_close#} + {#header_open|@memcpy#} <pre><code class="zig">@memcpy(noalias dest: &u8, noalias source: &const u8, byte_count: usize)</code></pre> <p> This function copies bytes from one region of memory to another. <code>dest</code> and @@ -4540,7 +4238,8 @@ fn add(a: i32, b: i32) -> i32 { a + b }</code></pre> <p>There is also a standard library function for this:</p> <pre><code class="zig">const mem = @import("std").mem; mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre> - <h3 id="builtin-memset">@memset</h3> + {#header_close#} + {#header_open|@memset#} <pre><code class="zig">@memset(dest: &u8, c: u8, byte_count: usize)</code></pre> <p> This function sets a region of memory to <code>c</code>. <code>dest</code> is a pointer. @@ -4556,7 +4255,8 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);</code></pre> <p>There is also a standard library function for this:</p> <pre><code>const mem = @import("std").mem; mem.set(u8, dest, c);</code></pre> - <h3 id="builtin-minValue">@minValue</h3> + {#header_close#} + {#header_open|@minValue#} <pre><code class="zig">@minValue(comptime T: type) -> (number literal)</code></pre> <p> This function returns the minimum value of the integer type T. @@ -4564,7 +4264,8 @@ mem.set(u8, dest, c);</code></pre> <p> The result is a compile time constant. </p> - <h3 id="builtin-mod">@mod</h3> + {#header_close#} + {#header_open|@mod#} <pre><code class="zig">@mod(numerator: T, denominator: T) -> T</code></pre> <p> Modulus division. For unsigned integers this is the same as @@ -4574,19 +4275,18 @@ mem.set(u8, dest, c);</code></pre> <li><code>@mod(-5, 3) == 1</code></li> <li><code>@divFloor(a, b) + @mod(a, b) == a</code></li> </ul> - <p>See also:</p> - <ul> - <li><a href="#builtin-rem">@rem</a></li> - <li><code>@import("std").math.mod</code></li> - </ul> - <h3 id="builtin-mulWithOverflow">@mulWithOverflow</h3> + <p>For a function that returns an error code, see <code>@import("std").math.mod</code>.</p> + {#see_also|@rem#} + {#header_close#} + {#header_open|@mulWithOverflow#} <pre><code class="zig">@mulWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool</code></pre> <p> Performs <code>*result = a * b</code>. If overflow or underflow occurs, stores the overflowed bits in <code>result</code> and returns <code>true</code>. If no overflow or underflow occurs, returns <code>false</code>. </p> - <h3 id="builtin-noInlineCall">@noInlineCall</h3> + {#header_close#} + {#header_open|@noInlineCall#} <pre><code class="zig">@noInlineCall(function: var, args: ...) -> var</code></pre> <p> This calls a function, in the same way that invoking an expression with parentheses does: @@ -4601,16 +4301,15 @@ fn add(a: i32, b: i32) -> i32 { a + b }</code></pre> Unlike a normal function call, however, <code>@noInlineCall</code> guarantees that the call will not be inlined. If the call must be inlined, a compile error is emitted. </p> - <p>See also:</p> - <ul> - <li><a href="#builtin-inlineCall">@inlineCall</a></li> - </ul> - <h3 id="builtin-offsetOf">@offsetOf</h3> + {#see_also|@inlineCall#} + {#header_close#} + {#header_open|@offsetOf#} <pre><code class="zig">@offsetOf(comptime T: type, comptime field_name: [] const u8) -> (number literal)</code></pre> <p> This function returns the byte offset of a field relative to its containing struct. </p> - <h3 id="builtin-OpaqueType">@OpaqueType</h3> + {#header_close#} + {#header_open|@OpaqueType#} <pre><code class="zig">@OpaqueType() -> type</code></pre> <p> Creates a new type with an unknown size and alignment. @@ -4630,7 +4329,8 @@ export fn foo(w: &Wat) { test.zig:5:9: error: expected type '&Derp', found '&Wat' bar(w); ^</code></pre> - <h3 id="builtin-panic">@panic</h3> + {#header_close#} + {#header_open|@panic#} <pre><code class="zig">@panic(message: []const u8) -> noreturn</code></pre> <p> Invokes the panic handler function. By default the panic handler function @@ -4644,17 +4344,15 @@ test.zig:5:9: error: expected type '&Derp', found '&Wat' <li>From library code, calling the programmer's panic function if they exposed one in the root source file.</li> <li>When mixing C and Zig code, calling the canonical panic implementation across multiple .o files.</li> </ul> - <p>See also:</p> - <ul> - <li><a href="#root-source-file">Root Source File</a></li> - </ul> - - <h3 id="builtin-ptrCast">@ptrCast</h3> + {#see_also|Root Source File#} + {#header_close#} + {#header_open|@ptrCast#} <pre><code class="zig">@ptrCast(comptime DestType: type, value: var) -> DestType</code></pre> <p> Converts a pointer of one type to a pointer of another type. </p> - <h3 id="builtin-ptrToInt">@ptrToInt</h3> + {#header_close#} + {#header_open|@ptrToInt#} <pre><code class="zig">@ptrToInt(value: var) -> usize</code></pre> <p> Converts <code>value</code> to a <code>usize</code> which is the address of the pointer. <code>value</code> can be one of these types: @@ -4667,7 +4365,8 @@ test.zig:5:9: error: expected type '&Derp', found '&Wat' </ul> <p>To convert the other way, use <a href="#builtin-intToPtr">@intToPtr</a></p> - <h3 id="builtin-rem">@rem</h3> + {#header_close#} + {#header_open|@rem#} <pre><code class="zig">@rem(numerator: T, denominator: T) -> T</code></pre> <p> Remainder division. For unsigned integers this is the same as @@ -4677,12 +4376,10 @@ test.zig:5:9: error: expected type '&Derp', found '&Wat' <li><code>@rem(-5, 3) == -2</code></li> <li><code>@divTrunc(a, b) + @rem(a, b) == a</code></li> </ul> - <p>See also:</p> - <ul> - <li><a href="#builtin-mod">@mod</a></li> - <li><code>@import("std").math.rem</code></li> - </ul> - <h3 id="builtin-returnAddress">@returnAddress</h3> + <p>For a function that returns an error code, see <code>@import("std").math.rem</code>.</p> + {#see_also|@mod#} + {#header_close#} + {#header_open|@returnAddress#} <pre><code class="zig">@returnAddress()</code></pre> <p> This function returns a pointer to the return address of the current stack @@ -4695,14 +4392,15 @@ test.zig:5:9: error: expected type '&Derp', found '&Wat' <p> This function is only valid within function scope. </p> - - <h3 id="builtin-setDebugSafety">@setDebugSafety</h3> + {#header_close#} + {#header_open|@setDebugSafety#} <pre><code class="zig">@setDebugSafety(scope, safety_on: bool)</code></pre> <p> Sets whether debug safety checks are on for a given scope. </p> - <h3 id="builtin-setEvalBranchQuota">@setEvalBranchQuota</h3> + {#header_close#} + {#header_open|@setEvalBranchQuota#} <pre><code class="zig">@setEvalBranchQuota(new_quota: usize)</code></pre> <p> Changes the maximum number of backwards branches that compile-time code @@ -4732,12 +4430,9 @@ test.zig:5:9: error: expected type '&Derp', found '&Wat' <pre><code class="sh">$ ./zig build-obj test.zig</code></pre> <p>(no output because it worked fine)</p> - <p>See also:</p> - <ul> - <li><a href="#comptime">comptime</a></li> - </ul> - - <h3 id="builtin-setFloatMode">@setFloatMode</h3> + {#see_also|comptime#} + {#header_close#} + {#header_open|@setFloatMode#} <pre><code class="zig">@setFloatMode(scope, mode: @import("builtin").FloatMode)</code></pre> <p> Sets the floating point mode for a given scope. Possible values are: @@ -4763,26 +4458,22 @@ test.zig:5:9: error: expected type '&Derp', found '&Wat' <code>Strict</code> - Floating point operations follow strict IEEE compliance. </li> </ul> - <p>See also:</p> - <ul> - <li><a href="#float-operations">Floating Point Operations</a></li> - </ul> - - <h3 id="builtin-setGlobalLinkage">@setGlobalLinkage</h3> + {#see_also|Floating Point Operations#} + {#header_close#} + {#header_open|@setGlobalLinkage#} <pre><code class="zig">@setGlobalLinkage(global_variable_name, comptime linkage: GlobalLinkage)</code></pre> <p> <code>GlobalLinkage</code> can be found with <code>@import("builtin").GlobalLinkage</code>. </p> - <p>See also:</p> - <ul> - <li><a href="#compile-variables">Compile Variables</a></li> - </ul> - <h3 id="builtin-setGlobalSection">@setGlobalSection</h3> + {#see_also|Compile Variables#} + {#header_close#} + {#header_open|@setGlobalSection#} <pre><code class="zig">@setGlobalSection(global_variable_name, comptime section_name: []const u8) -> bool</code></pre> <p> Puts the global variable in the specified section. </p> - <h3 id="builtin-shlExact">@shlExact</h3> + {#header_close#} + {#header_open|@shlExact#} <pre><code class="zig">@shlExact(value: T, shift_amt: Log2T) -> T</code></pre> <p> Performs the left shift operation (<code><<</code>). Caller guarantees @@ -4792,12 +4483,9 @@ test.zig:5:9: error: expected type '&Derp', found '&Wat' The type of <code>shift_amt</code> is an unsigned integer with <code>log2(T.bit_count)</code> bits. This is because <code>shift_amt >= T.bit_count</code> is undefined behavior. </p> - <p>See also:</p> - <ul> - <li><a href="#builtin-shrExact">@shrExact</a></li> - <li><a href="#builtin-shlWithOverflow">@shlWithOverflow</a></li> - </ul> - <h3 id="builtin-shlWithOverflow">@shlWithOverflow</h3> + {#see_also|@shrExact|@shlWithOverflow#} + {#header_close#} + {#header_open|@shlWithOverflow#} <pre><code class="zig">@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: &T) -> bool</code></pre> <p> Performs <code>*result = a << b</code>. If overflow or underflow occurs, @@ -4808,12 +4496,9 @@ test.zig:5:9: error: expected type '&Derp', found '&Wat' The type of <code>shift_amt</code> is an unsigned integer with <code>log2(T.bit_count)</code> bits. This is because <code>shift_amt >= T.bit_count</code> is undefined behavior. </p> - <p>See also:</p> - <ul> - <li><a href="#builtin-shlExact">@shlExact</a></li> - <li><a href="#builtin-shrExact">@shrExact</a></li> - </ul> - <h3 id="builtin-shrExact">@shrExact</h3> + {#see_also|@shlExact|@shrExact#} + {#header_close#} + {#header_open|@shrExact#} <pre><code class="zig">@shrExact(value: T, shift_amt: Log2T) -> T</code></pre> <p> Performs the right shift operation (<code>>></code>). Caller guarantees @@ -4823,11 +4508,9 @@ test.zig:5:9: error: expected type '&Derp', found '&Wat' The type of <code>shift_amt</code> is an unsigned integer with <code>log2(T.bit_count)</code> bits. This is because <code>shift_amt >= T.bit_count</code> is undefined behavior. </p> - <p>See also:</p> - <ul> - <li><a href="#builtin-shlExact">@shlExact</a></li> - </ul> - <h3 id="builtin-sizeOf">@sizeOf</h3> + {#see_also|@shlExact|@shlWithOverflow#} + {#header_close#} + {#header_open|@sizeOf#} <pre><code class="zig">@sizeOf(comptime T: type) -> (number literal)</code></pre> <p> This function returns the number of bytes it takes to store <code>T</code> in memory. @@ -4835,14 +4518,16 @@ test.zig:5:9: error: expected type '&Derp', found '&Wat' <p> The result is a target-specific compile time constant. </p> - <h3 id="builtin-subWithOverflow">@subWithOverflow</h3> + {#header_close#} + {#header_open|@subWithOverflow#} <pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool</code></pre> <p> Performs <code>*result = a - b</code>. If overflow or underflow occurs, stores the overflowed bits in <code>result</code> and returns <code>true</code>. If no overflow or underflow occurs, returns <code>false</code>. </p> - <h3 id="builtin-truncate">@truncate</h3> + {#header_close#} + {#header_open|@truncate#} <pre><code class="zig">@truncate(comptime T: type, integer) -> T</code></pre> <p> This function truncates bits from an integer type, resulting in a smaller @@ -4865,7 +4550,8 @@ const b: u8 = @truncate(u8, a); of endianness on the target platform. </p> - <h3 id="builtin-typeId">@typeId</h3> + {#header_close#} + {#header_open|@typeId#} <pre><code class="zig">@typeId(comptime T: type) -> @import("builtin").TypeId</code></pre> <p> Returns which kind of type something is. Possible values: @@ -4898,20 +4584,24 @@ const b: u8 = @truncate(u8, a); Opaque, };</code></pre> - <h3 id="builtin-typeName">@typeName</h3> + {#header_close#} + {#header_open|@typeName#} <pre><code class="zig">@typeName(T: type) -> []u8</code></pre> <p> This function returns the string representation of a type. </p> - <h3 id="builtin-typeOf">@typeOf</h3> + {#header_close#} + {#header_open|@typeOf#} <pre><code class="zig">@typeOf(expression) -> type</code></pre> <p> This function returns a compile-time constant, which is the type of the expression passed as an argument. The expression is evaluated. </p> - <h2 id="build-mode">Build Mode</h2> + {#header_close#} + {#header_close#} + {#header_open|Build Mode#} <p> Zig has three build modes: </p> @@ -4935,34 +4625,33 @@ pub fn build(b: &Builder) { </p> <pre><code class="sh"> -Drelease-safe=(bool) optimizations on and safety on -Drelease-fast=(bool) optimizations on and safety off</code></pre> - <h3 id="build-mode-debug">Debug</h2> + {#header_open|Debug#} <pre><code class="sh">$ zig build-exe example.zig</code></pre> <ul> <li>Fast compilation speed</li> <li>Safety checks enabled</li> <li>Slow runtime performance</li> </ul> - <h3 id="build-mode-release-fast">ReleaseFast</h2> + {#header_close#} + {#header_open|ReleaseFast#} <pre><code class="sh">$ zig build-exe example.zig --release-fast</code></pre> <ul> <li>Fast runtime performance</li> <li>Safety checks disabled</li> <li>Slow compilation speed</li> </ul> - <h3 id="build-mode-release-safe">ReleaseSafe</h2> + {#header_close#} + {#header_open|ReleaseSafe#} <pre><code class="sh">$ zig build-exe example.zig --release-safe</code></pre> <ul> <li>Medium runtime performance</li> <li>Safety checks enabled</li> <li>Slow compilation speed</li> </ul> - <p>See also:</p> - <ul> - <li><a href="#compile-variables">Compile Variables</a></li> - <li><a href="#zig-build-system">Zig Build System</a></li> - <li><a href="#undefined-behavior">Undefined Behavior</a></li> - </ul> - <h2 id="undefined-behavior">Undefined Behavior</h2> + {#see_also|Compile Variables|Zig Build System|Undefined Behavior#} + {#header_close#} + {#header_close#} + {#header_open|Undefined Behavior#} <p> Zig has many instances of undefined behavior. If undefined behavior is detected at compile-time, Zig emits an error. Most undefined behavior that @@ -5000,7 +4689,7 @@ Test 1/1 safety check...reached unreachable code Tests failed. Use the following command to reproduce the failure: ./test</code></pre> - <h3 id="undef-unreachable">Reaching Unreachable Code</h3> + {#header_open|Reaching Unreachable Code#} <p>At compile-time:</p> <pre><code class="zig">comptime { assert(false); @@ -5019,7 +4708,8 @@ fn assert(ok: bool) { comptime { ^</code></pre> <p>At runtime crashes with the message <code>reached unreachable code</code> and a stack trace.</p> - <h3 id="undef-index-out-of-bounds">Index out of Bounds</h3> + {#header_close#} + {#header_open|Index out of Bounds#} <p>At compile-time:</p> <pre><code class="zig">comptime { const array = "hello"; @@ -5030,7 +4720,8 @@ comptime { const garbage = array[5]; ^</code></pre> <p>At runtime crashes with the message <code>index out of bounds</code> and a stack trace.</p> - <h3 id="undef-cast-negative-unsigned">Cast Negative Number to Unsigned Integer</h3> + {#header_close#} + {#header_open|Cast Negative Number to Unsigned Integer#} <p>At compile-time:</p> <pre><code class="zig">comptime { const value: i32 = -1; @@ -5044,7 +4735,8 @@ comptime { If you are trying to obtain the maximum value of an unsigned integer, use <code>@maxValue(T)</code>, where <code>T</code> is the integer type, such as <code>u32</code>. </p> - <h3 id="undef-cast-truncates-data">Cast Truncates Data</h3> + {#header_close#} + {#header_open|Cast Truncates Data#} <p>At compile-time:</p> <pre><code class="zig">comptime { const spartan_count: u16 = 300; @@ -5060,8 +4752,9 @@ test.zig:3:20: error: cast from 'u16' to 'u8' truncates bits where <code>T</code> is the integer type, such as <code>u32</code>, and <code>value</code> is the value you want to truncate. </p> - <h3 id="undef-integer-overflow">Integer Overflow</h3> - <h4 id="undef-int-overflow-default">Default Operations</h4> + {#header_close#} + {#header_open|Integer Overflow#} + {#header_open|Default Operations#} <p>The following operators can cause integer overflow:</p> <ul> <li><code>+</code> (addition)</li> @@ -5083,7 +4776,8 @@ test.zig:3:20: error: cast from 'u16' to 'u8' truncates bits byte += 1; ^</code></pre> <p>At runtime crashes with the message <code>integer overflow</code> and a stack trace.</p> - <h4 id="undef-int-overflow-std">Standard Library Math Functions</h4> + {#header_close#} + {#header_open|Standard Library Math Functions#} <p>These functions provided by the standard library return possible errors.</p> <ul> <li><code>@import("std").math.add</code></li> @@ -5112,7 +4806,8 @@ pub fn main() -> %void { <pre><code class="sh">$ zig build-exe test.zig $ ./test unable to add one: Overflow</code></pre> - <h4 id="undef-int-overflow-builtin">Builtin Overflow Functions</h4> + {#header_close#} + {#header_open|Builtin Overflow Functions#} <p> These builtins return a <code>bool</code> of whether or not overflow occurred, as well as returning the overflowed bits: @@ -5140,7 +4835,8 @@ pub fn main() -> %void { <pre><code class="sh">$ zig build-exe test.zig $ ./test overflowed result: 9</code></pre> - <h4 id="undef-int-overflow-wrap">Wrapping Operations</h4> + {#header_close#} + {#header_open|Wrapping Operations#} <p> These operations have guaranteed wraparound semantics. </p> @@ -5159,7 +4855,9 @@ test "wraparound addition and subtraction" { const max_val = min_val -% 1; assert(max_val == @maxValue(i32)); }</code></pre> - <h3 id="undef-shl-overflow">Exact Left Shift Overflow</h3> + {#header_close#} + {#header_close#} + {#header_open|Exact Left Shift Overflow#} <p>At compile-time:</p> <pre><code class="zig">comptime { const x = @shlExact(u8(0b01010101), 2); @@ -5169,7 +4867,8 @@ test "wraparound addition and subtraction" { const x = @shlExact(u8(0b01010101), 2); ^</code></pre> <p>At runtime crashes with the message <code>left shift overflowed bits</code> and a stack trace.</p> - <h3 id="undef-shr-overflow">Exact Right Shift Overflow</h3> + {#header_close#} + {#header_open|Exact Right Shift Overflow#} <p>At compile-time:</p> <pre><code class="zig">comptime { const x = @shrExact(u8(0b10101010), 2); @@ -5179,7 +4878,8 @@ test "wraparound addition and subtraction" { const x = @shrExact(u8(0b10101010), 2); ^</code></pre> <p>At runtime crashes with the message <code>right shift overflowed bits</code> and a stack trace.</p> - <h3 id="undef-division-by-zero">Division by Zero</h3> + {#header_close#} + {#header_open|Division by Zero#} <p>At compile-time:</p> <pre><code class="zig">comptime { const a: i32 = 1; @@ -5192,7 +4892,8 @@ test "wraparound addition and subtraction" { ^</code></pre> <p>At runtime crashes with the message <code>division by zero</code> and a stack trace.</p> - <h3 id="undef-remainder-division-by-zero">Remainder Division by Zero</h3> + {#header_close#} + {#header_open|Remainder Division by Zero#} <p>At compile-time:</p> <pre><code class="zig">comptime { const a: i32 = 10; @@ -5205,11 +4906,14 @@ test "wraparound addition and subtraction" { ^</code></pre> <p>At runtime crashes with the message <code>remainder division by zero</code> and a stack trace.</p> - <h3 id="undef-exact-division-remainder">Exact Division Remainder</h3> + {#header_close#} + {#header_open|Exact Division Remainder#} <p>TODO</p> - <h3 id="undef-slice-widen-remainder">Slice Widen Remainder</h3> + {#header_close#} + {#header_open|Slice Widen Remainder#} <p>TODO</p> - <h3 id="undef-attempt-unwrap-null">Attempt to Unwrap Null</h3> + {#header_close#} + {#header_open|Attempt to Unwrap Null#} <p>At compile-time:</p> <pre><code class="zig">comptime { const nullable_number: ?i32 = null; @@ -5222,8 +4926,9 @@ test "wraparound addition and subtraction" { <p>At runtime crashes with the message <code>attempt to unwrap null</code> and a stack trace.</p> <p>One way to avoid this crash is to test for null instead of assuming non-null, with the <code>if</code> expression:</p> - <pre><code class="zig">const warn = @import("std").debug.warn; -pub fn main() -> %void { + {#code_begin|exe|test#} +const warn = @import("std").debug.warn; +pub fn main() { const nullable_number: ?i32 = null; if (nullable_number) |number| { @@ -5231,11 +4936,10 @@ pub fn main() -> %void { } else { warn("it's null\n"); } -}</code></pre> - <pre><code class="sh">% zig build-exe test.zig -$ ./test -it's null</code></pre> - <h3 id="undef-attempt-unwrap-error">Attempt to Unwrap Error</h3> +} + {#code_end#} + {#header_close#} + {#header_open|Attempt to Unwrap Error#} <p>At compile-time:</p> <pre><code class="zig">comptime { const number = %%getNumberOrFail(); @@ -5253,9 +4957,10 @@ fn getNumberOrFail() -> %i32 { <p>At runtime crashes with the message <code>attempt to unwrap error: ErrorCode</code> and a stack trace.</p> <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with the <code>if</code> expression:</p> - <pre><code class="zig">const warn = @import("std").debug.warn; + {#code_begin|exe|test#} +const warn = @import("std").debug.warn; -pub fn main() -> %void { +pub fn main() { const result = getNumberOrFail(); if (result) |number| { @@ -5267,14 +4972,12 @@ pub fn main() -> %void { error UnableToReturnNumber; -fn getNumberOrFail() -> %i32 { +fn getNumberOrFail() -> %i32 { return error.UnableToReturnNumber; -}</code></pre> - <pre><code class="sh">$ zig build-exe test.zig -$ ./test -got error: UnableToReturnNumber</code></pre> - - <h3 id="undef-invalid-error-code">Invalid Error Code</h3> +} + {#code_end#} + {#header_close#} + {#header_open|Invalid Error Code#} <p>At compile-time:</p> <pre><code class="zig">error AnError; comptime { @@ -5287,28 +4990,31 @@ comptime { const invalid_err = error(number); ^</code></pre> <p>At runtime crashes with the message <code>invalid error code</code> and a stack trace.</p> - <h3 id="undef-invalid-enum-cast">Invalid Enum Cast</h3> + {#header_close#} + {#header_open|Invalid Enum Cast#} <p>TODO</p> - <h3 id="undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</h3> + {#header_close#} + {#header_open|Incorrect Pointer Alignment#} <p>TODO</p> - <h3 id="undef-bad-union-field">Wrong Union Field Access</h3> + {#header_close#} + {#header_open|Wrong Union Field Access#} <p>TODO</p> - <h2 id="memory">Memory</h2> + {#header_close#} + {#header_close#} + {#header_open|Memory#} <p>TODO: explain no default allocator in zig</p> <p>TODO: show how to use the allocator interface</p> <p>TODO: mention debug allocator</p> <p>TODO: importance of checking for allocation failure</p> <p>TODO: mention overcommit and the OOM Killer</p> <p>TODO: mention recursion</p> - <p>See also:</p> - <ul> - <li><a href="#pointers">Pointers</a></li> - </ul> + {#see_also|Pointers#} - <h2 id="compile-variables">Compile Variables</h2> + {#header_close#} + {#header_open|Compile Variables#} <p> Compile variables are accessible by importing the <code>"builtin"</code> package, which the compiler makes available to every Zig source file. It contains @@ -5474,11 +5180,9 @@ pub const object_format = ObjectFormat.elf; pub const mode = Mode.ReleaseFast; pub const link_libs = [][]const u8 { };</code></pre> - <p>See also:</p> - <ul> - <li><a href="#build-mode">Build Mode</a></li> - </ul> - <h2 id="root-source-file">Root Source File</h2> + {#see_also|Build Mode#} + {#header_close#} + {#header_open|Root Source File#} <p>TODO: explain how root source file finds other files</p> <p>TODO: pub fn main</p> <p>TODO: pub fn panic</p> @@ -5486,17 +5190,20 @@ pub const link_libs = [][]const u8 { <p>TODO: order independent top level declarations</p> <p>TODO: lazy analysis</p> <p>TODO: using comptime { _ = @import() }</p> - <h2 id="zig-test">Zig Test</h2> + {#header_close#} + {#header_open|Zig Test#} <p>TODO: basic usage</p> <p>TODO: lazy analysis</p> <p>TODO: --test-filter</p> <p>TODO: --test-name-prefix</p> <p>TODO: testing in releasefast and releasesafe mode. assert still works</p> - <h2 id="zig-build-system">Zig Build System</h2> + {#header_close#} + {#header_open|Zig Build System#} <p>TODO: explain purpose, it's supposed to replace make/cmake</p> <p>TODO: example of building a zig executable</p> <p>TODO: example of building a C library</p> - <h2 id="c">C</h2> + {#header_close#} + {#header_open|C#} <p> Although Zig is independent of C, and, unlike most other languages, does not depend on libc, Zig acknowledges the importance of interacting with existing C code. @@ -5504,7 +5211,7 @@ pub const link_libs = [][]const u8 { <p> There are a few ways that Zig facilitates C interop. </p> - <h3 id="c-type-primitives">C Type Primitives</h3> + {#header_open|C Type Primitives#} <p> These have guaranteed C ABI compatibility and can be used like any other type. </p> @@ -5520,11 +5227,9 @@ pub const link_libs = [][]const u8 { <li><code>c_longdouble</code></li> <li><code>c_void</code></li> </ul> - <p>See also:</p> - <ul> - <li><a href="#primitive-types">Primitive Types</a></li> - </ul> - <h3 id="c-string-literals">C String Literals</h3> + {#see_also|Primitive Types#} + {#header_close#} + {#header_open|C String Literals#} <pre><code class="zig">extern fn puts(&const u8); pub fn main() -> %void { @@ -5535,11 +5240,9 @@ pub fn main() -> %void { c\\multiline C string literal ); }</code></pre> - <p>See also:</p> - <ul> - <li><a href="#string-literals">String Literals</a></li> - </ul> - <h3 id="c-import">Import from C Header File</h3> + {#see_also|String Literals#} + {#header_close#} + {#header_open|Import from C Header File#} <p> The <code>@cImport</code> builtin function can be used to directly import symbols from .h files: @@ -5566,19 +5269,14 @@ const c = @cImport({ } @cInclude("soundio.h"); });</code></pre> - <p>See also:</p> - <ul> - <li><a href="#builtin-cImport">@cImport</a></li> - <li><a href="#builtin-cInclude">@cInclude</a></li> - <li><a href="#builtin-cDefine">@cDefine</a></li> - <li><a href="#builtin-cUndef">@cUndef</a></li> - <li><a href="#builtin-import">@import</a></li> - </ul> - <h3 id="mixing-object-files">Mixing Object Files</h3> + {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#} + {#header_close#} + {#header_open|Mixing Object Files#} <p> You can mix Zig object files with any other object files that respect the C ABI. Example: </p> - <h4>base64.zig</h4> + {#header_close#} + {#header_open|base64.zig#} <pre><code class="zig">const base64 = @import("std").base64; export fn decode_base_64(dest_ptr: &u8, dest_len: usize, @@ -5592,7 +5290,7 @@ export fn decode_base_64(dest_ptr: &u8, dest_len: usize, return decoded_size; } </code></pre> - <h4>test.c</h4> +{{teheader_open:st.c}} <pre><code class="c">// This header is generated by zig from base64.zig #include "base64.h" @@ -5609,7 +5307,8 @@ int main(int argc, char **argv) { return 0; }</code></pre> - <h4>build.zig</h4> + {#header_close#} + {#header_open|build.zig#} <pre><code class="zig">const Builder = @import("std").build.Builder; pub fn build(b: &Builder) { @@ -5625,16 +5324,15 @@ pub fn build(b: &Builder) { b.default_step.dependOn(&exe.step); }</code></pre> - <h4>Terminal</h4> + {#header_close#} + {#header_open|Terminal#} <pre><code class="sh">$ zig build $ ./test all your base are belong to us</code></pre> - <p>See also:</p> - <ul> - <li><a href="#targets">Targets</a></li> - <li><a href="#zig-build-system">Zig Build System</a></li> - </ul> - <h2 id="targets">Targets</h2> + {#see_also|Targets|Zig Build System#} + {#header_close#} + {#header_close#} + {#header_open|Targets#} <p> Zig supports generating code for all targets that LLVM supports. Here is what it looks like to execute <code>zig targets</code> on a Linux x86_64 @@ -5760,14 +5458,15 @@ Environments: Linux x86_64. Not all standard library code requires operating system abstractions, however, so things such as generic data structures work an all above platforms. </p> - <h2 id="style-guide">Style Guide</h2> + {#header_close#} + {#header_open|Style Guide#} <p> These coding conventions are not enforced by the compiler, but they are shipped in this documentation along with the compiler in order to provide a point of reference, should anyone wish to point to an authority on agreed upon Zig coding style. </p> - <h3 id="style-guide-whitespace">Whitespace</h3> + {#header_open|Whitespace#} <ul> <li> 4 space indentation @@ -5782,7 +5481,8 @@ coding style. Line length: aim for 100; use common sense. </li> </ul> - <h3 id="style-guide-names">Names</h3> + {#header_close#} + {#header_open|Names#} <p> Roughly speaking: <code>camelCaseFunctionName</code>, <code>TitleCaseTypeName</code>, <code>snake_case_variable_name</code>. More precisely: @@ -5816,7 +5516,8 @@ coding style. do what makes sense. For example, if there is an established convention such as <code>ENOENT</code>, follow the established convention. </p> - <h3 id="style-guide-examples">Examples</h3> + {#header_close#} + {#header_open|Examples#} <pre><code class="zig">const namespace_name = @import("dir_name/file_name.zig"); var global_var: i32 = undefined; const const_name = 42; @@ -5858,7 +5559,9 @@ fn readU32Be() -> u32 {}</code></pre> <p> See the Zig Standard Library for more examples. </p> - <h2 id="grammar">Grammar</h2> + {#header_close#} + {#header_close#} + {#header_open|Grammar#} <pre><code>Root = many(TopLevelItem) EOF TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl @@ -6010,7 +5713,8 @@ KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "u ContainerDecl = option("extern" | "packed") ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression))) "{" many(ContainerMember) "}"</code></pre> - <h2 id="zen">Zen</h2> + {#header_close#} + {#header_open|Zen#} <ul> <li>Communicate intent precisely.</li> <li>Edge cases matter.</li> @@ -6024,8 +5728,10 @@ ContainerDecl = option("extern" | "packed") <li>Minimize energy spent on coding style.</li> <li>Together we serve end users.</li> </ul> - <h2>TODO</h2> + {#header_close#} + {#header_open|TODO#} <p>TODO: document changes from a31b23c46ba2a8c28df01adc1aa0b4d878b9a5cf (compile time reflection additions)</p> + {#header_close#} </div> <script src="highlight/highlight.pack.js"></script> <script>hljs.initHighlightingOnLoad();</script> diff --git a/src/bigint.cpp b/src/bigint.cpp index a68dd3a4b8..85e5dad4ad 100644 --- a/src/bigint.cpp +++ b/src/bigint.cpp @@ -1271,6 +1271,12 @@ void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2) { } void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2) { + if (op1->digit_count == 0) { + return bigint_init_bigint(dest, op2); + } + if (op2->digit_count == 0) { + return bigint_init_bigint(dest, op1); + } if (op1->is_negative || op2->is_negative) { // TODO this code path is untested size_t big_bit_count = max(bigint_bits_needed(op1), bigint_bits_needed(op2)); @@ -1289,14 +1295,16 @@ void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2) { dest->is_negative = false; const uint64_t *op1_digits = bigint_ptr(op1); const uint64_t *op2_digits = bigint_ptr(op2); + + assert(op1->digit_count > 0 && op2->digit_count > 0); + uint64_t first_digit = op1_digits[0] ^ op2_digits[0]; if (op1->digit_count == 1 && op2->digit_count == 1) { dest->digit_count = 1; - dest->data.digit = op1_digits[0] ^ op2_digits[0]; + dest->data.digit = first_digit; bigint_normalize(dest); return; } // TODO this code path is untested - uint64_t first_digit = dest->data.digit; dest->digit_count = max(op1->digit_count, op2->digit_count); dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count); dest->data.digits[0] = first_digit; diff --git a/src/codegen.cpp b/src/codegen.cpp index c72bb07c8b..15423d6315 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -921,31 +921,41 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) { return g->memcpy_fn_val; } +static LLVMValueRef get_return_address_fn_val(CodeGen *g) { + if (g->return_address_fn_val) + return g->return_address_fn_val; + + TypeTableEntry *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); + + LLVMTypeRef fn_type = LLVMFunctionType(return_type->type_ref, + &g->builtin_types.entry_i32->type_ref, 1, false); + g->return_address_fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type); + assert(LLVMGetIntrinsicID(g->return_address_fn_val)); + + return g->return_address_fn_val; +} + static LLVMValueRef get_return_err_fn(CodeGen *g) { if (g->return_err_fn != nullptr) return g->return_err_fn; assert(g->err_tag_type != nullptr); - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMTypeRef arg_types[] = { // error return trace pointer get_ptr_to_stack_trace_type(g)->type_ref, - // return address - ptr_u8, }; - LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); + LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false); LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); + addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address addLLVMFnAttr(fn_val, "cold"); LLVMSetLinkage(fn_val, LLVMInternalLinkage); LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); addLLVMFnAttr(fn_val, "nounwind"); add_uwtable_attr(g, fn_val); addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); - addLLVMArgAttr(fn_val, (unsigned)1, "nonnull"); if (g->build_mode == BuildModeDebug) { ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr); @@ -983,7 +993,9 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, ""); LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, ""); - LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, LLVMGetParam(fn_val, 1), usize_type_ref, ""); + LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); + LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, ""); + LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, ""); LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, ""); gen_store_untyped(g, address_value, address_slot, 0, false); @@ -1431,17 +1443,11 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns is_err_return = true; } if (is_err_return) { - LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError"); - LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block); - LLVMValueRef return_err_fn = get_return_err_fn(g); LLVMValueRef args[] = { g->cur_err_ret_trace_val, - block_address, }; - LLVMBuildBr(g->builder, return_block); - LLVMPositionBuilderAtEnd(g->builder, return_block); - LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 2, + LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); LLVMSetTailCall(call_instruction, true); } @@ -3291,20 +3297,6 @@ static LLVMValueRef ir_render_breakpoint(CodeGen *g, IrExecutable *executable, I return nullptr; } -static LLVMValueRef get_return_address_fn_val(CodeGen *g) { - if (g->return_address_fn_val) - return g->return_address_fn_val; - - TypeTableEntry *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); - - LLVMTypeRef fn_type = LLVMFunctionType(return_type->type_ref, - &g->builtin_types.entry_i32->type_ref, 1, false); - g->return_address_fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type); - assert(LLVMGetIntrinsicID(g->return_address_fn_val)); - - return g->return_address_fn_val; -} - static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executable, IrInstructionReturnAddress *instruction) { diff --git a/std/build.zig b/std/build.zig index 5d79b00c4f..2b61d4971b 100644 --- a/std/build.zig +++ b/std/build.zig @@ -760,7 +760,7 @@ const CrossTarget = struct { environ: builtin.Environ, }; -const Target = union(enum) { +pub const Target = union(enum) { Native: void, Cross: CrossTarget, diff --git a/std/crypto/blake2.zig b/std/crypto/blake2.zig index b08caa480e..7c943c752a 100644 --- a/std/crypto/blake2.zig +++ b/std/crypto/blake2.zig @@ -21,6 +21,8 @@ pub const Blake2s256 = Blake2s(256); fn Blake2s(comptime out_len: usize) -> type { return struct { const Self = this; + const block_size = 64; + const digest_size = out_len / 8; const iv = [8]u32 { 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, @@ -236,6 +238,8 @@ pub const Blake2b512 = Blake2b(512); fn Blake2b(comptime out_len: usize) -> type { return struct { const Self = this; + const block_size = 128; + const digest_size = out_len / 8; const iv = [8]u64 { 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, diff --git a/std/crypto/index.zig b/std/crypto/index.zig index 839704e3e7..ee7dc2aa0e 100644 --- a/std/crypto/index.zig +++ b/std/crypto/index.zig @@ -1,5 +1,5 @@ -pub const Md5 = @import("sha1.zig").Md5; -pub const Sha1 = @import("md5.zig").Sha1; +pub const Md5 = @import("md5.zig").Md5; +pub const Sha1 = @import("sha1.zig").Sha1; const sha2 = @import("sha2.zig"); pub const Sha224 = sha2.Sha224; @@ -7,6 +7,12 @@ pub const Sha256 = sha2.Sha256; pub const Sha384 = sha2.Sha384; pub const Sha512 = sha2.Sha512; +const sha3 = @import("sha3.zig"); +pub const Sha3_224 = sha3.Sha3_224; +pub const Sha3_256 = sha3.Sha3_256; +pub const Sha3_384 = sha3.Sha3_384; +pub const Sha3_512 = sha3.Sha3_512; + const blake2 = @import("blake2.zig"); pub const Blake2s224 = blake2.Blake2s224; pub const Blake2s256 = blake2.Blake2s256; @@ -17,5 +23,6 @@ test "crypto" { _ = @import("md5.zig"); _ = @import("sha1.zig"); _ = @import("sha2.zig"); + _ = @import("sha3.zig"); _ = @import("blake2.zig"); } diff --git a/std/crypto/md5.zig b/std/crypto/md5.zig index 02f1954380..b0c40a8424 100644 --- a/std/crypto/md5.zig +++ b/std/crypto/md5.zig @@ -14,14 +14,10 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) -> Round return RoundParam { .a = a, .b = b, .c = c, .d = d, .k = k, .s = s, .t = t }; } -/// const hash1 = Md5.hash("my input"); -/// -/// const hasher = Md5.init(); -/// hasher.update("my "); -/// hasher.update("input"); -/// const hash2 = hasher.final(); pub const Md5 = struct { const Self = this; + const block_size = 64; + const digest_size = 16; s: [4]u32, // Streaming Cache diff --git a/std/crypto/sha1.zig b/std/crypto/sha1.zig index bb68b62983..94f29bde44 100644 --- a/std/crypto/sha1.zig +++ b/std/crypto/sha1.zig @@ -16,6 +16,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) -> RoundParam { pub const Sha1 = struct { const Self = this; + const block_size = 64; + const digest_size = 20; s: [5]u32, // Streaming Cache diff --git a/std/crypto/sha2.zig b/std/crypto/sha2.zig index 5ddcb7df91..deb65cd321 100644 --- a/std/crypto/sha2.zig +++ b/std/crypto/sha2.zig @@ -58,6 +58,8 @@ pub const Sha256 = Sha2_32(Sha256Params); fn Sha2_32(comptime params: Sha2Params32) -> type { return struct { const Self = this; + const block_size = 64; + const digest_size = params.out_len / 8; s: [8]u32, // Streaming Cache @@ -372,7 +374,8 @@ pub const Sha512 = Sha2_64(Sha512Params); fn Sha2_64(comptime params: Sha2Params64) -> type { return struct { const Self = this; - const u9 = @IntType(false, 9); + const block_size = 128; + const digest_size = params.out_len / 8; s: [8]u64, // Streaming Cache diff --git a/std/crypto/sha3.zig b/std/crypto/sha3.zig new file mode 100644 index 0000000000..8ba7cf20d5 --- /dev/null +++ b/std/crypto/sha3.zig @@ -0,0 +1,281 @@ +const mem = @import("../mem.zig"); +const math = @import("../math/index.zig"); +const endian = @import("../endian.zig"); +const debug = @import("../debug/index.zig"); +const builtin = @import("builtin"); +const htest = @import("test.zig"); + +pub const Sha3_224 = Keccak(224, 0x06); +pub const Sha3_256 = Keccak(256, 0x06); +pub const Sha3_384 = Keccak(384, 0x06); +pub const Sha3_512 = Keccak(512, 0x06); + +fn Keccak(comptime bits: usize, comptime delim: u8) -> type { return struct { + const Self = this; + const block_size = 200; + const digest_size = bits / 8; + + s: [200]u8, + offset: usize, + rate: usize, + + pub fn init() -> Self { + var d: Self = undefined; + d.reset(); + return d; + } + + pub fn reset(d: &Self) { + mem.set(u8, d.s[0..], 0); + d.offset = 0; + d.rate = 200 - (bits / 4); + } + + pub fn hash(b: []const u8, out: []u8) { + var d = Self.init(); + d.update(b); + d.final(out); + } + + pub fn update(d: &Self, b: []const u8) { + var ip: usize = 0; + var len = b.len; + var rate = d.rate - d.offset; + var offset = d.offset; + + // absorb + while (len >= rate) { + for (d.s[offset .. offset + rate]) |*r, i| + *r ^= b[ip..][i]; + + keccak_f(1600, d.s[0..]); + + ip += rate; + len -= rate; + rate = d.rate; + offset = 0; + } + + for (d.s[offset .. offset + len]) |*r, i| + *r ^= b[ip..][i]; + + d.offset = offset + len; + } + + pub fn final(d: &Self, out: []u8) { + // padding + d.s[d.offset] ^= delim; + d.s[d.rate - 1] ^= 0x80; + + keccak_f(1600, d.s[0..]); + + // squeeze + var op: usize = 0; + var len: usize = bits / 8; + + while (len >= d.rate) { + mem.copy(u8, out[op..], d.s[0..d.rate]); + keccak_f(1600, d.s[0..]); + op += d.rate; + len -= d.rate; + } + + mem.copy(u8, out[op..], d.s[0..len]); + } +};} + +const RC = []const u64 { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, + 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, + 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, + 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, + 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +}; + +const ROTC = []const usize { + 1, 3, 6, 10, 15, 21, 28, 36, + 45, 55, 2, 14, 27, 41, 56, 8, + 25, 43, 62, 18, 39, 61, 20, 44 +}; + +const PIL = []const usize { + 10, 7, 11, 17, 18, 3, 5, 16, + 8, 21, 24, 4, 15, 23, 19, 13, + 12, 2, 20, 14, 22, 9, 6, 1 +}; + +const M5 = []const usize { + 0, 1, 2, 3, 4, 0, 1, 2, 3, 4 +}; + +fn keccak_f(comptime F: usize, d: []u8) { + debug.assert(d.len == F / 8); + + const B = F / 25; + const no_rounds = comptime x: { break :x 12 + 2 * math.log2(B); }; + + var s = []const u64 {0} ** 25; + var t = []const u64 {0} ** 1; + var c = []const u64 {0} ** 5; + + for (s) |*r, i| { + *r = mem.readIntLE(u64, d[8*i .. 8*i + 8]); + } + + var x: usize = 0; + var y: usize = 0; + // TODO: Cannot unroll all loops here due to comptime differences. + inline for (RC[0..no_rounds]) |round| { + // theta + x = 0; while (x < 5) : (x += 1) { + c[x] = s[x] ^ s[x+5] ^ s[x+10] ^ s[x+15] ^ s[x+20]; + } + x = 0; while (x < 5) : (x += 1) { + t[0] = c[M5[x+4]] ^ math.rotl(u64, c[M5[x+1]], usize(1)); + y = 0; while (y < 5) : (y += 1) { + s[x + y*5] ^= t[0]; + } + } + + // rho+pi + t[0] = s[1]; + x = 0; while (x < 24) : (x += 1) { + c[0] = s[PIL[x]]; + s[PIL[x]] = math.rotl(u64, t[0], ROTC[x]); + t[0] = c[0]; + } + + // chi + y = 0; while (y < 5) : (y += 1) { + x = 0; while (x < 5) : (x += 1) { + c[x] = s[x + y*5]; + } + x = 0; while (x < 5) : (x += 1) { + s[x + y*5] = c[x] ^ (~c[M5[x+1]] & c[M5[x+2]]); + } + } + + // iota + s[0] ^= round; + } + + for (s) |r, i| { + mem.writeInt(d[8*i .. 8*i + 8], r, builtin.Endian.Little); + } +} + + +test "sha3-224 single" { + htest.assertEqualHash(Sha3_224, "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", ""); + htest.assertEqualHash(Sha3_224, "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc"); + htest.assertEqualHash(Sha3_224, "543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); +} + +test "sha3-224 streaming" { + var h = Sha3_224.init(); + var out: [28]u8 = undefined; + + h.final(out[0..]); + htest.assertEqual("6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", out[0..]); + + h.reset(); + h.update("abc"); + h.final(out[0..]); + htest.assertEqual("e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", out[0..]); + + h.reset(); + h.update("a"); + h.update("b"); + h.update("c"); + h.final(out[0..]); + htest.assertEqual("e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", out[0..]); +} + +test "sha3-256 single" { + htest.assertEqualHash(Sha3_256, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" , ""); + htest.assertEqualHash(Sha3_256, "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc"); + htest.assertEqualHash(Sha3_256, "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); +} + +test "sha3-256 streaming" { + var h = Sha3_256.init(); + var out: [32]u8 = undefined; + + h.final(out[0..]); + htest.assertEqual("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", out[0..]); + + h.reset(); + h.update("abc"); + h.final(out[0..]); + htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]); + + h.reset(); + h.update("a"); + h.update("b"); + h.update("c"); + h.final(out[0..]); + htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]); +} + +test "sha3-384 single" { + const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"; + htest.assertEqualHash(Sha3_384, h1 , ""); + const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"; + htest.assertEqualHash(Sha3_384, h2, "abc"); + const h3 = "79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7"; + htest.assertEqualHash(Sha3_384, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); +} + +test "sha3-384 streaming" { + var h = Sha3_384.init(); + var out: [48]u8 = undefined; + + const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"; + h.final(out[0..]); + htest.assertEqual(h1, out[0..]); + + const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"; + h.reset(); + h.update("abc"); + h.final(out[0..]); + htest.assertEqual(h2, out[0..]); + + h.reset(); + h.update("a"); + h.update("b"); + h.update("c"); + h.final(out[0..]); + htest.assertEqual(h2, out[0..]); +} + +test "sha3-512 single" { + const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"; + htest.assertEqualHash(Sha3_512, h1 , ""); + const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"; + htest.assertEqualHash(Sha3_512, h2, "abc"); + const h3 = "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185"; + htest.assertEqualHash(Sha3_512, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); +} + +test "sha3-512 streaming" { + var h = Sha3_512.init(); + var out: [64]u8 = undefined; + + const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"; + h.final(out[0..]); + htest.assertEqual(h1, out[0..]); + + const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"; + h.reset(); + h.update("abc"); + h.final(out[0..]); + htest.assertEqual(h2, out[0..]); + + h.reset(); + h.update("a"); + h.update("b"); + h.update("c"); + h.final(out[0..]); + htest.assertEqual(h2, out[0..]); +} diff --git a/std/crypto/throughput_test.zig b/std/crypto/throughput_test.zig new file mode 100644 index 0000000000..5285af3ed6 --- /dev/null +++ b/std/crypto/throughput_test.zig @@ -0,0 +1,43 @@ +// Modify the HashFunction variable to the one wanted to test. +// +// NOTE: The throughput measurement may be slightly lower than other measurements since we run +// through our block alignment functions as well. Be aware when comparing against other tests. +// +// ``` +// zig build-exe --release-fast --library c throughput_test.zig +// ./throughput_test +// ``` +const HashFunction = @import("md5.zig").Md5; +const BytesToHash = 1024 * Mb; + +const std = @import("std"); + +const c = @cImport({ + @cInclude("time.h"); +}); + +const Mb = 1024 * 1024; + +pub fn main() -> %void { + var stdout_file = try std.io.getStdOut(); + var stdout_out_stream = std.io.FileOutStream.init(&stdout_file); + const stdout = &stdout_out_stream.stream; + + var block: [HashFunction.block_size]u8 = undefined; + std.mem.set(u8, block[0..], 0); + + var h = HashFunction.init(); + var offset: usize = 0; + + const start = c.clock(); + while (offset < BytesToHash) : (offset += block.len) { + h.update(block[0..]); + } + const end = c.clock(); + + const elapsed_s = f64((end - start) * c.CLOCKS_PER_SEC) / 1000000; + const throughput = u64(BytesToHash / elapsed_s); + + try stdout.print("{}: ", @typeName(HashFunction)); + try stdout.print("{} Mb/s\n", throughput); +} diff --git a/std/hash_map.zig b/std/hash_map.zig index f91e4b31ba..2cd08d1280 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -62,8 +62,7 @@ pub fn HashMap(comptime K: type, comptime V: type, .allocator = allocator, .size = 0, .max_distance_from_start_index = 0, - // it doesn't actually matter what we set this to since we use wrapping integer arithmetic - .modification_count = undefined, + .modification_count = if (want_modification_safety) 0 else {}, }; } @@ -110,6 +109,10 @@ pub fn HashMap(comptime K: type, comptime V: type, return hm.internalGet(key); } + pub fn contains(hm: &Self, key: K) -> bool { + return hm.get(key) != null; + } + pub fn remove(hm: &Self, key: K) -> ?&Entry { hm.incrementModificationCount(); const start_index = hm.keyToIndex(key); diff --git a/std/mem.zig b/std/mem.zig index 2d5b6f7a25..5f6cc0c3e0 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -203,6 +203,20 @@ pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) -> %[]T { return new_buf; } +/// Remove values from the beginning and end of a slice. +pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) -> []const T { + var begin: usize = 0; + var end: usize = slice.len; + while (begin < end and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {} + while (end > begin and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {} + return slice[begin..end]; +} + +test "mem.trim" { + assert(eql(u8, trim(u8, " foo\n ", " \n"), "foo")); + assert(eql(u8, trim(u8, "foo", " \n"), "foo")); +} + /// Linear search for the index of a scalar value inside a slice. pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize { return indexOfScalarPos(T, slice, 0, value); diff --git a/test/cases/math.zig b/test/cases/math.zig index 090e2b9dfd..88f32a2839 100644 --- a/test/cases/math.zig +++ b/test/cases/math.zig @@ -349,6 +349,32 @@ test "big number shifting" { } } +test "xor" { + test_xor(); + comptime test_xor(); +} + +fn test_xor() { + assert(0xFF ^ 0x00 == 0xFF); + assert(0xF0 ^ 0x0F == 0xFF); + assert(0xFF ^ 0xF0 == 0x0F); + assert(0xFF ^ 0x0F == 0xF0); + assert(0xFF ^ 0xFF == 0x00); +} + +test "big number xor" { + comptime { + assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); + assert(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); + assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); + assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); + assert(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); + } +} + test "f128" { test_f128(); comptime test_f128(); @@ -368,4 +394,4 @@ fn test_f128() { fn should_not_be_zero(x: f128) { assert(x != 0.0); -} +}
\ No newline at end of file |
