diff --git a/README.md b/README.md index 716f96044c..f7ee9a48fc 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,7 @@ that counts as "freestanding" for the purposes of this table. |-------------|--------------|---------|---------|---------|---------| |i386 | OK | planned | OK | planned | planned | |x86_64 | OK | OK | OK | OK | planned | -|arm | OK | planned | planned | N/A | planned | -|aarch64 | OK | planned | N/A | planned | planned | +|arm | OK | planned | planned | planned | planned | |bpf | OK | planned | N/A | N/A | planned | |hexagon | OK | planned | N/A | N/A | planned | |mips | OK | planned | N/A | N/A | planned | @@ -64,20 +63,22 @@ that counts as "freestanding" for the purposes of this table. |amdgcn | OK | planned | N/A | N/A | planned | |sparc | OK | planned | N/A | N/A | planned | |s390x | OK | planned | N/A | N/A | planned | -|thumb | OK | planned | N/A | N/A | planned | |spir | OK | planned | N/A | N/A | planned | |lanai | OK | planned | N/A | N/A | planned | +|wasm32 | planned | N/A | N/A | N/A | N/A | +|wasm64 | planned | N/A | N/A | N/A | N/A | +|riscv32 | planned | planned | N/A | N/A | planned | +|riscv64 | planned | planned | N/A | N/A | planned | ## Community * IRC: `#zig` on Freenode ([Channel Logs](https://irclog.whitequark.org/zig/)). * Reddit: [/r/zig](https://www.reddit.com/r/zig) - * Email list: [ziglang@googlegroups.com](https://groups.google.com/forum/#!forum/ziglang) + * Email list: [~andrewrk/ziglang@lists.sr.ht](https://lists.sr.ht/%7Eandrewrk/ziglang) ## Building -[![Build Status](https://travis-ci.org/ziglang/zig.svg?branch=master)](https://travis-ci.org/ziglang/zig) -[![Build status](https://ci.appveyor.com/api/projects/status/4t80mk2dmucrc38i/branch/master?svg=true)](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master) +[![Build Status](https://dev.azure.com/ziglang/zig/_apis/build/status/ziglang.zig?branchName=master)](https://dev.azure.com/ziglang/zig/_build/latest?definitionId=1&branchName=master) Note that you can [download a binary of master branch](https://ziglang.org/download/#release-master). diff --git a/build.zig b/build.zig index c4a95bb0a9..bb4aa30f97 100644 --- a/build.zig +++ b/build.zig @@ -17,7 +17,7 @@ pub fn build(b: *Builder) !void { const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe); const langref_out_path = os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable; - var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8.{ + var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{ docgen_exe.getOutputPath(), rel_zig_exe, "doc" ++ os.path.sep_str ++ "langref.html.in", @@ -31,12 +31,12 @@ pub fn build(b: *Builder) !void { const test_step = b.step("test", "Run all the tests"); // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library - const build_info = try b.exec([][]const u8.{ + const build_info = try b.exec([][]const u8{ b.zig_exe, "BUILD_INFO", }); var index: usize = 0; - var ctx = Context.{ + var ctx = Context{ .cmake_binary_dir = nextValue(&index, build_info), .cxx_compiler = nextValue(&index, build_info), .llvm_config_exe = nextValue(&index, build_info), @@ -162,7 +162,7 @@ fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_na lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable); } -const LibraryDep = struct.{ +const LibraryDep = struct { prefix: []const u8, libdirs: ArrayList([]const u8), libs: ArrayList([]const u8), @@ -171,24 +171,24 @@ const LibraryDep = struct.{ }; fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { - const shared_mode = try b.exec([][]const u8.{ llvm_config_exe, "--shared-mode" }); + const shared_mode = try b.exec([][]const u8{ llvm_config_exe, "--shared-mode" }); const is_static = mem.startsWith(u8, shared_mode, "static"); const libs_output = if (is_static) - try b.exec([][]const u8.{ + try b.exec([][]const u8{ llvm_config_exe, "--libfiles", "--system-libs", }) else - try b.exec([][]const u8.{ + try b.exec([][]const u8{ llvm_config_exe, "--libs", }); - const includes_output = try b.exec([][]const u8.{ llvm_config_exe, "--includedir" }); - const libdir_output = try b.exec([][]const u8.{ llvm_config_exe, "--libdir" }); - const prefix_output = try b.exec([][]const u8.{ llvm_config_exe, "--prefix" }); + const includes_output = try b.exec([][]const u8{ llvm_config_exe, "--includedir" }); + const libdir_output = try b.exec([][]const u8{ llvm_config_exe, "--libdir" }); + const prefix_output = try b.exec([][]const u8{ llvm_config_exe, "--prefix" }); - var result = LibraryDep.{ + var result = LibraryDep{ .prefix = mem.split(prefix_output, " \r\n").next().?, .libs = ArrayList([]const u8).init(b.allocator), .system_libs = ArrayList([]const u8).init(b.allocator), @@ -328,7 +328,7 @@ fn addCxxKnownPath( objname: []const u8, errtxt: ?[]const u8, ) !void { - const path_padded = try b.exec([][]const u8.{ + const path_padded = try b.exec([][]const u8{ ctx.cxx_compiler, b.fmt("-print-file-name={}", objname), }); @@ -344,7 +344,7 @@ fn addCxxKnownPath( exe.addObjectFile(path_unpadded); } -const Context = struct.{ +const Context = struct { cmake_binary_dir: []const u8, cxx_compiler: []const u8, llvm_config_exe: []const u8, diff --git a/ci/azure/macos_script b/ci/azure/macos_script index 0f9549f46a..4bb2ae2c43 100755 --- a/ci/azure/macos_script +++ b/ci/azure/macos_script @@ -22,7 +22,7 @@ mkdir $TMPDIR cd $HOME HAVE_CACHE="true" -wget "https://ziglang.org/builds/$CACHE_BASENAME.tar.xz" || HAVE_CACHE="false" +wget -nv "https://ziglang.org/builds/$CACHE_BASENAME.tar.xz" || HAVE_CACHE="false" if [ "${HAVE_CACHE}" = "true" ]; then tar xf "$CACHE_BASENAME.tar.xz" else diff --git a/ci/azure/windows_install b/ci/azure/windows_install index 3f02b3d26d..846973a179 100755 --- a/ci/azure/windows_install +++ b/ci/azure/windows_install @@ -3,7 +3,7 @@ set -x set -e -pacman -S --needed --noconfirm wget zip python3-pip +pacman -S --needed --noconfirm wget p7zip python3-pip pip install s3cmd -wget "https://ziglang.org/deps/llvm%2bclang-8.0.0-win64-msvc-release.tar.xz" +wget -nv "https://ziglang.org/deps/llvm%2bclang-8.0.0-win64-msvc-release.tar.xz" tar xf llvm+clang-8.0.0-win64-msvc-release.tar.xz diff --git a/ci/azure/windows_upload b/ci/azure/windows_upload index 7546f43699..8d30980fea 100755 --- a/ci/azure/windows_upload +++ b/ci/azure/windows_upload @@ -6,6 +6,7 @@ set -e if [ "${BUILD_REASON}" != "PullRequest" ]; then cd "$ZIGBUILDDIR" + rm release/*.lib mv ../LICENSE release/ mv ../zig-cache/langref.html release/ mv release/bin/zig.exe release/ @@ -15,7 +16,7 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then DIRNAME="zig-windows-x86_64-$VERSION" TARBALL="$DIRNAME.zip" mv release "$DIRNAME" - zip -r "$TARBALL" "$DIRNAME" + 7z a "$TARBALL" "$DIRNAME" mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg" s3cmd put -P "$TARBALL" s3://ziglang.org/builds/ diff --git a/doc/docgen.zig b/doc/docgen.zig index 1589f29853..2489e034bc 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -58,12 +58,12 @@ pub fn main() !void { try buffered_out_stream.flush(); } -const Token = struct.{ +const Token = struct { id: Id, start: usize, end: usize, - const Id = enum.{ + const Id = enum { Invalid, Content, BracketOpen, @@ -74,14 +74,14 @@ const Token = struct.{ }; }; -const Tokenizer = struct.{ +const Tokenizer = struct { buffer: []const u8, index: usize, state: State, source_file_name: []const u8, code_node_count: usize, - const State = enum.{ + const State = enum { Start, LBracket, Hash, @@ -90,7 +90,7 @@ const Tokenizer = struct.{ }; fn init(source_file_name: []const u8, buffer: []const u8) Tokenizer { - return Tokenizer.{ + return Tokenizer{ .buffer = buffer, .index = 0, .state = State.Start, @@ -100,7 +100,7 @@ const Tokenizer = struct.{ } fn next(self: *Tokenizer) Token { - var result = Token.{ + var result = Token{ .id = Token.Id.Eof, .start = self.index, .end = undefined, @@ -184,7 +184,7 @@ const Tokenizer = struct.{ return result; } - const Location = struct.{ + const Location = struct { line: usize, column: usize, line_start: usize, @@ -192,7 +192,7 @@ const Tokenizer = struct.{ }; fn getTokenLocation(self: *Tokenizer, token: Token) Location { - var loc = Location.{ + var loc = Location{ .line = 0, .column = 0, .line_start = 0, @@ -216,7 +216,7 @@ const Tokenizer = struct.{ } }; -fn parseError(tokenizer: *Tokenizer, token: Token, comptime fmt: []const u8, args: ...) error { +fn parseError(tokenizer: *Tokenizer, token: Token, comptime fmt: []const u8, args: ...) anyerror { 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) { @@ -251,23 +251,23 @@ fn eatToken(tokenizer: *Tokenizer, id: Token.Id) !Token { return token; } -const HeaderOpen = struct.{ +const HeaderOpen = struct { name: []const u8, url: []const u8, n: usize, }; -const SeeAlsoItem = struct.{ +const SeeAlsoItem = struct { name: []const u8, token: Token, }; -const ExpectedOutcome = enum.{ +const ExpectedOutcome = enum { Succeed, Fail, }; -const Code = struct.{ +const Code = struct { id: Id, name: []const u8, source_token: Token, @@ -277,7 +277,7 @@ const Code = struct.{ target_windows: bool, link_libc: bool, - const Id = union(enum).{ + const Id = union(enum) { Test, TestError: []const u8, TestSafety: []const u8, @@ -286,13 +286,13 @@ const Code = struct.{ }; }; -const Link = struct.{ +const Link = struct { url: []const u8, name: []const u8, token: Token, }; -const Node = union(enum).{ +const Node = union(enum) { Content: []const u8, Nav, Builtin: Token, @@ -303,13 +303,13 @@ const Node = union(enum).{ Syntax: Token, }; -const Toc = struct.{ +const Toc = struct { nodes: []Node, toc: []u8, urls: std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8), }; -const Action = enum.{ +const Action = enum { Open, Close, }; @@ -343,7 +343,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { break; }, Token.Id.Content => { - try nodes.append(Node.{ .Content = tokenizer.buffer[token.start..token.end] }); + try nodes.append(Node{ .Content = tokenizer.buffer[token.start..token.end] }); }, Token.Id.BracketOpen => { const tag_token = try eatToken(tokenizer, Token.Id.TagContent); @@ -355,7 +355,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { try nodes.append(Node.Nav); } else if (mem.eql(u8, tag_name, "builtin")) { _ = try eatToken(tokenizer, Token.Id.BracketClose); - try nodes.append(Node.{ .Builtin = tag_token }); + try nodes.append(Node{ .Builtin = tag_token }); } else if (mem.eql(u8, tag_name, "header_open")) { _ = try eatToken(tokenizer, Token.Id.Separator); const content_token = try eatToken(tokenizer, Token.Id.TagContent); @@ -365,8 +365,8 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { header_stack_size += 1; const urlized = try urlize(allocator, content); - try nodes.append(Node.{ - .HeaderOpen = HeaderOpen.{ + try nodes.append(Node{ + .HeaderOpen = HeaderOpen{ .name = content, .url = urlized, .n = header_stack_size, @@ -409,14 +409,14 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { switch (see_also_tok.id) { Token.Id.TagContent => { const content = tokenizer.buffer[see_also_tok.start..see_also_tok.end]; - try list.append(SeeAlsoItem.{ + try list.append(SeeAlsoItem{ .name = content, .token = see_also_tok, }); }, Token.Id.Separator => {}, Token.Id.BracketClose => { - try nodes.append(Node.{ .SeeAlso = list.toOwnedSlice() }); + try nodes.append(Node{ .SeeAlso = list.toOwnedSlice() }); break; }, else => return parseError(tokenizer, see_also_tok, "invalid see_also token"), @@ -440,8 +440,8 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { } }; - try nodes.append(Node.{ - .Link = Link.{ + try nodes.append(Node{ + .Link = Link{ .url = try urlize(allocator, url_name), .name = name, .token = name_tok, @@ -465,24 +465,24 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { var code_kind_id: Code.Id = undefined; var is_inline = false; if (mem.eql(u8, code_kind_str, "exe")) { - code_kind_id = Code.Id.{ .Exe = ExpectedOutcome.Succeed }; + code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Succeed }; } else if (mem.eql(u8, code_kind_str, "exe_err")) { - code_kind_id = Code.Id.{ .Exe = ExpectedOutcome.Fail }; + code_kind_id = Code.Id{ .Exe = ExpectedOutcome.Fail }; } else if (mem.eql(u8, code_kind_str, "test")) { code_kind_id = Code.Id.Test; } else if (mem.eql(u8, code_kind_str, "test_err")) { - code_kind_id = Code.Id.{ .TestError = name }; + code_kind_id = Code.Id{ .TestError = name }; name = "test"; } else if (mem.eql(u8, code_kind_str, "test_safety")) { - code_kind_id = Code.Id.{ .TestSafety = name }; + code_kind_id = Code.Id{ .TestSafety = name }; name = "test"; } else if (mem.eql(u8, code_kind_str, "obj")) { - code_kind_id = Code.Id.{ .Obj = null }; + code_kind_id = Code.Id{ .Obj = null }; } else if (mem.eql(u8, code_kind_str, "obj_err")) { - code_kind_id = Code.Id.{ .Obj = name }; + code_kind_id = Code.Id{ .Obj = name }; name = "test"; } else if (mem.eql(u8, code_kind_str, "syntax")) { - code_kind_id = Code.Id.{ .Obj = null }; + code_kind_id = Code.Id{ .Obj = null }; is_inline = true; } else { return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", code_kind_str); @@ -518,8 +518,8 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { _ = try eatToken(tokenizer, Token.Id.BracketClose); } else unreachable; // TODO issue #707 - try nodes.append(Node.{ - .Code = Code.{ + try nodes.append(Node{ + .Code = Code{ .id = code_kind_id, .name = name, .source_token = source_token, @@ -541,7 +541,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { return parseError(tokenizer, end_syntax_tag, "invalid token inside syntax: {}", end_tag_name); } _ = try eatToken(tokenizer, Token.Id.BracketClose); - try nodes.append(Node.{ .Syntax = content_tok }); + try nodes.append(Node{ .Syntax = content_tok }); } else { return parseError(tokenizer, tag_token, "unrecognized tag name: {}", tag_name); } @@ -550,7 +550,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { } } - return Toc.{ + return Toc{ .nodes = nodes.toOwnedSlice(), .toc = toc_buf.toOwnedSlice(), .urls = urls, @@ -606,7 +606,7 @@ fn writeEscaped(out: var, input: []const u8) !void { //#define VT_BOLD "\x1b[0;1m" //#define VT_RESET "\x1b[0m" -const TermState = enum.{ +const TermState = enum { Start, Escape, LBracket, @@ -703,7 +703,7 @@ fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 { return buf.toOwnedSlice(); } -const builtin_types = [][]const u8.{ +const builtin_types = [][]const u8{ "f16", "f32", "f64", "f128", "c_longdouble", "c_short", "c_ushort", "c_int", "c_uint", "c_long", "c_ulong", "c_longlong", "c_ulonglong", "c_char", "c_void", "void", "bool", "isize", @@ -735,6 +735,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok std.zig.Token.Id.Keyword_align, std.zig.Token.Id.Keyword_and, + std.zig.Token.Id.Keyword_anyerror, std.zig.Token.Id.Keyword_asm, std.zig.Token.Id.Keyword_async, std.zig.Token.Id.Keyword_await, @@ -763,7 +764,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok std.zig.Token.Id.Keyword_pub, std.zig.Token.Id.Keyword_resume, std.zig.Token.Id.Keyword_return, - std.zig.Token.Id.Keyword_section, + std.zig.Token.Id.Keyword_linksection, std.zig.Token.Id.Keyword_stdcallcc, std.zig.Token.Id.Keyword_struct, std.zig.Token.Id.Keyword_suspend, @@ -998,7 +999,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext); var build_args = std.ArrayList([]const u8).init(allocator); defer build_args.deinit(); - try build_args.appendSlice([][]const u8.{ + try build_args.appendSlice([][]const u8{ zig_exe, "build-exe", tmp_source_file_name, @@ -1035,7 +1036,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var } _ = exec(allocator, &env_map, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile"); - const run_args = [][]const u8.{tmp_bin_file_name}; + const run_args = [][]const u8{tmp_bin_file_name}; const result = if (expected_outcome == ExpectedOutcome.Fail) blk: { const result = try os.ChildProcess.exec(allocator, run_args, null, &env_map, max_doc_file_size); @@ -1069,7 +1070,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var var test_args = std.ArrayList([]const u8).init(allocator); defer test_args.deinit(); - try test_args.appendSlice([][]const u8.{ + try test_args.appendSlice([][]const u8{ zig_exe, "test", tmp_source_file_name, @@ -1093,7 +1094,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var }, } if (code.target_windows) { - try test_args.appendSlice([][]const u8.{ + try test_args.appendSlice([][]const u8{ "--target-os", "windows", "--target-arch", @@ -1111,7 +1112,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var var test_args = std.ArrayList([]const u8).init(allocator); defer test_args.deinit(); - try test_args.appendSlice([][]const u8.{ + try test_args.appendSlice([][]const u8{ zig_exe, "test", "--color", @@ -1170,7 +1171,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var var test_args = std.ArrayList([]const u8).init(allocator); defer test_args.deinit(); - try test_args.appendSlice([][]const u8.{ + try test_args.appendSlice([][]const u8{ zig_exe, "test", tmp_source_file_name, @@ -1222,7 +1223,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name); const output_h_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_h_ext); - try build_args.appendSlice([][]const u8.{ + try build_args.appendSlice([][]const u8{ zig_exe, "build-obj", tmp_source_file_name, @@ -1332,7 +1333,7 @@ fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u } fn getBuiltinCode(allocator: *mem.Allocator, env_map: *std.BufMap, zig_exe: []const u8) ![]const u8 { - const result = try exec(allocator, env_map, []const []const u8.{ + const result = try exec(allocator, env_map, []const []const u8{ zig_exe, "builtin", }); diff --git a/doc/langref.html.in b/doc/langref.html.in index 0a5ff19389..a29b9be4c8 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -8,6 +8,7 @@ body{ background-color:#111; color: #bbb; + font-family: sans-serif; } a { color: #88f; @@ -211,7 +212,7 @@ test "comments" { {#code_begin|syntax|doc_comments#} /// A structure for storing a timestamp, with nanosecond precision (this is a /// multiline doc comment). -const Timestamp = struct.{ +const Timestamp = struct { /// The number of seconds since the epoch (this is also a doc comment). seconds: i64, // signed so we can represent pre-1970 (not a doc comment) /// The number of nanoseconds past the second (doc comment again). @@ -220,7 +221,7 @@ const Timestamp = struct.{ /// Returns a `Timestamp` struct representing the Unix epoch; that is, the /// moment of 1970 Jan 1 00:00:00 UTC (this is a doc comment too). pub fn unixEpoch() Timestamp { - return Timestamp.{ + return Timestamp{ .seconds = 0, .nanos = 0, }; @@ -270,7 +271,7 @@ pub fn main() void { @typeName(@typeOf(optional_value)), optional_value); // error union - var number_or_error: error!i32 = error.ArgNotFound; + var number_or_error: anyerror!i32 = error.ArgNotFound; warn("\nerror union 1\ntype: {}\nvalue: {}\n", @typeName(@typeOf(number_or_error)), number_or_error); @@ -448,7 +449,7 @@ pub fn main() void { the type of types - {#syntax#}error.{#endsyntax#} + {#syntax#}anyerror{#endsyntax#} (none) an error code @@ -467,9 +468,10 @@ pub fn main() void {

In addition to the integer types above, arbitrary bit-width integers can be referenced by using an identifier of i or u followed by digits. For example, the identifier - {#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. + {#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an + integer type is {#syntax#}65535{#endsyntax#}.

- {#see_also|Integers|Floats|void|Errors#} + {#see_also|Integers|Floats|void|Errors|@IntType#} {#header_close#} {#header_open|Primitive Values#}
@@ -952,7 +954,7 @@ a /= b{#endsyntax#}
  • {#link|Floats#}
  • - Divison. + Division. - If {#syntax#}a{#endsyntax#} is an {#syntax#}error.{#endsyntax#}, + If {#syntax#}a{#endsyntax#} is an {#syntax#}error{#endsyntax#}, returns {#syntax#}b{#endsyntax#} ("default value"), otherwise returns the unwrapped value of {#syntax#}a{#endsyntax#}. Note that {#syntax#}b{#endsyntax#} may be a value of type {#link|noreturn#}. - {#syntax#}err{#endsyntax#} is the {#syntax#}error.{#endsyntax#} and is in scope of the expression {#syntax#}b{#endsyntax#}. + {#syntax#}err{#endsyntax#} is the {#syntax#}error{#endsyntax#} and is in scope of the expression {#syntax#}b{#endsyntax#}. -
    {#syntax#}const value: error!u32 = error.Broken;
    +            
    {#syntax#}const value: anyerror!u32 = error.Broken;
     const unwrapped = value catch 1234;
     unwrapped == 1234{#endsyntax#}
    @@ -1389,9 +1391,9 @@ x.* == 1234{#endsyntax#}
    {#link|Merging Error Sets#} -
    {#syntax#}const A = error.{One};
    -const B = error.{Two};
    -(A || B) == error.{One, Two}{#endsyntax#}
    +
    {#syntax#}const A = error{One};
    +const B = error{Two};
    +(A || B) == error{One, Two}{#endsyntax#}
    @@ -1421,7 +1423,7 @@ const assert = @import("std").debug.assert; const mem = @import("std").mem; // array literal -const message = []u8.{ 'h', 'e', 'l', 'l', 'o' }; +const message = []u8{ 'h', 'e', 'l', 'l', 'o' }; // get the size of an array comptime { @@ -1457,11 +1459,11 @@ test "modify an array" { // array concatenation works if the values are known // at compile time -const part_one = []i32.{ 1, 2, 3, 4 }; -const part_two = []i32.{ 5, 6, 7, 8 }; +const part_one = []i32{ 1, 2, 3, 4 }; +const part_two = []i32{ 5, 6, 7, 8 }; const all_of_it = part_one ++ part_two; comptime { - assert(mem.eql(i32, all_of_it, []i32.{ 1, 2, 3, 4, 5, 6, 7, 8 })); + assert(mem.eql(i32, all_of_it, []i32{ 1, 2, 3, 4, 5, 6, 7, 8 })); } // remember that string literals are arrays @@ -1479,7 +1481,7 @@ comptime { } // initialize an array to zero -const all_zero = []u16.{0} ** 10; +const all_zero = []u16{0} ** 10; comptime { assert(all_zero.len == 10); @@ -1490,14 +1492,14 @@ comptime { var fancy_array = init: { var initial_value: [10]Point = undefined; for (initial_value) |*pt, i| { - pt.* = Point.{ + pt.* = Point{ .x = @intCast(i32, i), .y = @intCast(i32, i) * 2, }; } break :init initial_value; }; -const Point = struct.{ +const Point = struct { x: i32, y: i32, }; @@ -1508,9 +1510,9 @@ test "compile-time array initalization" { } // call a function to initialize an array -var more_points = []Point.{makePoint(3)} ** 10; +var more_points = []Point{makePoint(3)} ** 10; fn makePoint(x: i32) Point { - return Point.{ + return Point{ .x = x, .y = x * 2, }; @@ -1589,7 +1591,7 @@ test "pointer array access" { // Taking an address of an individual element gives a // pointer to a single item. This kind of pointer // does not support pointer arithmetic. - var array = []u8.{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; const ptr = &array[2]; assert(@typeOf(ptr) == *u8); @@ -1611,7 +1613,7 @@ test "pointer array access" { const assert = @import("std").debug.assert; test "pointer slicing" { - var array = []u8.{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; const slice = array[2..4]; assert(slice.len == 2); @@ -1692,7 +1694,7 @@ test "volatile" { const assert = @import("std").debug.assert; test "pointer casting" { - const bytes align(@alignOf(u32)) = []u8.{ 0x12, 0x12, 0x12, 0x12 }; + const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 }; const u32_ptr = @ptrCast(*const u32, &bytes); assert(u32_ptr.* == 0x12121212); @@ -1781,7 +1783,7 @@ test "function alignment" { const assert = @import("std").debug.assert; test "pointer alignment safety" { - var array align(4) = []u32.{ 0x11111111, 0x11111111 }; + var array align(4) = []u32{ 0x11111111, 0x11111111 }; const bytes = @sliceToBytes(array[0..]); assert(foo(bytes) == 0x11111111); } @@ -1798,7 +1800,7 @@ fn foo(bytes: []u8) u32 { const assert = @import("std").debug.assert; test "basic slices" { - var array = []i32.{ 1, 2, 3, 4 }; + var array = []i32{ 1, 2, 3, 4 }; // A slice is a pointer and a length. The difference between an array and // a slice is that the array's length is part of the type and known at // compile-time, whereas the slice's length is known at runtime. @@ -1866,7 +1868,7 @@ test "slice pointer" { test "slice widening" { // Zig supports slice widening and slice narrowing. Cast a slice of u8 // to a slice of anything else, and Zig will perform the length conversion. - const array align(@alignOf(u32)) = []u8.{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 }; + const array align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 }; const slice = @bytesToSlice(u32, array[0..]); assert(slice.len == 2); assert(slice[0] == 0x12121212); @@ -1880,27 +1882,27 @@ test "slice widening" { // Declare a struct. // Zig gives no guarantees about the order of fields and whether or // not there will be padding. -const Point = struct.{ +const Point = struct { x: f32, y: f32, }; // Maybe we want to pass it to OpenGL so we want to be particular about // how the bytes are arranged. -const Point2 = packed struct.{ +const Point2 = packed struct { x: f32, y: f32, }; // Declare an instance of a struct. -const p = Point.{ +const p = Point { .x = 0.12, .y = 0.34, }; // Maybe we're not ready to fill out some of the fields. -var p2 = Point.{ +var p2 = Point { .x = 0.12, .y = undefined, }; @@ -1908,13 +1910,13 @@ var p2 = Point.{ // Structs can have methods // Struct methods are not special, they are only namespaced // functions that you can call with dot syntax. -const Vec3 = struct.{ +const Vec3 = struct { x: f32, y: f32, z: f32, pub fn init(x: f32, y: f32, z: f32) Vec3 { - return Vec3.{ + return Vec3 { .x = x, .y = y, .z = z, @@ -1940,7 +1942,7 @@ test "dot product" { // Structs can have global declarations. // Structs can have 0 fields. -const Empty = struct.{ +const Empty = struct { pub const PI = 3.14; }; test "struct namespaced variable" { @@ -1948,7 +1950,7 @@ test "struct namespaced variable" { assert(@sizeOf(Empty) == 0); // you can still instantiate an empty struct - const does_nothing = Empty.{}; + const does_nothing = Empty {}; } // struct field order is determined by the compiler for optimal performance. @@ -1958,7 +1960,7 @@ fn setYBasedOnX(x: *f32, y: f32) void { point.y = y; } test "field parent pointer" { - var point = Point.{ + var point = Point { .x = 0.1234, .y = 0.5678, }; @@ -1969,8 +1971,8 @@ test "field parent pointer" { // You can return a struct from a function. This is how we do generics // in Zig: fn LinkedList(comptime T: type) type { - return struct.{ - pub const Node = struct.{ + return struct { + pub const Node = struct { prev: ?*Node, next: ?*Node, data: T, @@ -1987,7 +1989,7 @@ test "linked list" { // do this: assert(LinkedList(i32) == LinkedList(i32)); - var list = LinkedList(i32).{ + var list = LinkedList(i32) { .first = null, .last = null, .len = 0, @@ -1999,12 +2001,12 @@ test "linked list" { const ListOfInts = LinkedList(i32); assert(ListOfInts == LinkedList(i32)); - var node = ListOfInts.Node.{ + var node = ListOfInts.Node { .prev = null, .next = null, .data = 1234, }; - var list2 = LinkedList(i32).{ + var list2 = LinkedList(i32) { .first = &node, .last = &node, .len = 1, @@ -2034,14 +2036,14 @@ test "linked list" { const std = @import("std"); pub fn main() void { - const Foo = struct.{}; + const Foo = struct {}; std.debug.warn("variable: {}\n", @typeName(Foo)); - std.debug.warn("anonymous: {}\n", @typeName(struct.{})); + std.debug.warn("anonymous: {}\n", @typeName(struct {})); std.debug.warn("function: {}\n", @typeName(List(i32))); } fn List(comptime T: type) type { - return struct.{ + return struct { x: T, }; } @@ -2055,7 +2057,7 @@ const assert = @import("std").debug.assert; const mem = @import("std").mem; // Declare an enum. -const Type = enum.{ +const Type = enum { Ok, NotOk, }; @@ -2065,7 +2067,7 @@ const c = Type.Ok; // If you want access to the ordinal value of an enum, you // can specify the tag type. -const Value = enum(u2).{ +const Value = enum(u2) { Zero, One, Two, @@ -2080,7 +2082,7 @@ test "enum ordinal value" { } // You can override the ordinal value for an enum. -const Value2 = enum(u32).{ +const Value2 = enum(u32) { Hundred = 100, Thousand = 1000, Million = 1000000, @@ -2094,7 +2096,7 @@ test "set enum ordinal value" { // Enums can have methods, the same as structs and unions. // Enum methods are not special, they are only namespaced // functions that you can call with dot syntax. -const Suit = enum.{ +const Suit = enum { Clubs, Spades, Diamonds, @@ -2110,7 +2112,7 @@ test "enum method" { } // An enum variant of different types can be switched upon. -const Foo = enum.{ +const Foo = enum { String, Number, None, @@ -2126,7 +2128,7 @@ test "enum variant switch" { } // @TagType can be used to access the integer tag type of an enum. -const Small = enum.{ +const Small = enum { One, Two, Three, @@ -2156,14 +2158,14 @@ test "@tagName" { By default, enums are not guaranteed to be compatible with the C ABI:

    {#code_begin|obj_err|parameter of type 'Foo' not allowed in function with calling convention 'ccc'#} -const Foo = enum.{ A, B, C }; +const Foo = enum { A, B, C }; export fn entry(foo: Foo) void { } {#code_end#}

    For a C-ABI-compatible enum, use {#syntax#}extern enum{#endsyntax#}:

    {#code_begin|obj#} -const Foo = extern enum.{ A, B, C }; +const Foo = extern enum { A, B, C }; export fn entry(foo: Foo) void { } {#code_end#} {#header_close#} @@ -2175,7 +2177,7 @@ export fn entry(foo: Foo) void { } const std = @import("std"); test "packed enum" { - const Number = packed enum(u8).{ + const Number = packed enum(u8) { One, Two, Three, @@ -2192,30 +2194,30 @@ const assert = @import("std").debug.assert; const mem = @import("std").mem; // A union has only 1 active field at a time. -const Payload = union.{ +const Payload = union { Int: i64, Float: f64, Bool: bool, }; test "simple union" { - var payload = Payload.{.Int = 1234}; + var payload = Payload {.Int = 1234}; // payload.Float = 12.34; // ERROR! field not active assert(payload.Int == 1234); // You can activate another field by assigning the entire union. - payload = Payload.{.Float = 12.34}; + payload = Payload {.Float = 12.34}; assert(payload.Float == 12.34); } // Unions can be given an enum tag type: -const ComplexTypeTag = enum.{ Ok, NotOk }; -const ComplexType = union(ComplexTypeTag).{ +const ComplexTypeTag = enum { Ok, NotOk }; +const ComplexType = union(ComplexTypeTag) { Ok: u8, NotOk: void, }; // Declare a specific instance of the union variant. test "declare union value" { - const c = ComplexType.{ .Ok = 0 }; + const c = ComplexType { .Ok = 0 }; assert(ComplexTypeTag(c) == ComplexTypeTag.Ok); } @@ -2225,7 +2227,7 @@ test "@TagType" { } // Unions can be made to infer the enum tag type. -const Foo = union(enum).{ +const Foo = union(enum) { String: []const u8, Number: u64, @@ -2233,7 +2235,7 @@ const Foo = union(enum).{ None, }; test "union variant switch" { - const p = Foo.{ .Number = 54 }; + const p = Foo { .Number = 54 }; const what_is_it = switch (p) { // Capture by reference Foo.String => |*x| blk: { @@ -2255,7 +2257,7 @@ test "union variant switch" { // Unions can have methods just like structs and enums: -const Variant = union(enum).{ +const Variant = union(enum) { Int: i32, Bool: bool, @@ -2268,15 +2270,15 @@ const Variant = union(enum).{ }; test "union method" { - var v1 = Variant.{ .Int = 1 }; - var v2 = Variant.{ .Bool = false }; + var v1 = Variant { .Int = 1 }; + var v2 = Variant { .Bool = false }; assert(v1.truthy()); assert(!v2.truthy()); } -const Small = union.{ +const Small = union { A: i32, B: bool, C: u8, @@ -2294,7 +2296,7 @@ test "@memberName" { // @tagName gives a []const u8 representation of an enum value, // but only if the union has an enum tag type. -const Small2 = union(enum).{ +const Small2 = union(enum) { A: i32, B: bool, C: u8, @@ -2388,13 +2390,13 @@ test "switch simple" { } test "switch enum" { - const Item = union(enum).{ + const Item = union(enum) { A: u32, - C: struct.{ x: u8, y: u8 }, + C: struct { x: u8, y: u8 }, D, }; - var a = Item.{ .A = 3 }; + var a = Item { .A = 3 }; // Switching on more complex enums is allowed. const b = switch (a) { @@ -2629,7 +2631,7 @@ test "while error union capture" { var numbers_left: u32 = undefined; -fn eventuallyErrorSequence() error!u32 { +fn eventuallyErrorSequence() anyerror!u32 { return if (numbers_left == 0) error.ReachedZero else blk: { numbers_left -= 1; break :blk numbers_left; @@ -2683,7 +2685,7 @@ fn typeNameLength(comptime T: type) usize { const assert = @import("std").debug.assert; test "for basics" { - const items = []i32.{ 4, 5, 3, 4, 0 }; + const items = []i32 { 4, 5, 3, 4, 0 }; var sum: i32 = 0; // For loops iterate over slices and arrays. @@ -2713,7 +2715,7 @@ test "for basics" { } test "for reference" { - var items = []i32.{ 3, 4, 2 }; + var items = []i32 { 3, 4, 2 }; // Iterate over the slice by reference by // specifying that the capture value is a pointer. @@ -2728,7 +2730,7 @@ test "for reference" { test "for else" { // For allows an else attached to it, the same as a while loop. - var items = []?i32.{ 3, 4, null, 5 }; + var items = []?i32 { 3, 4, null, 5 }; // For loops can also be used as expressions. var sum: i32 = 0; @@ -2753,8 +2755,8 @@ const assert = std.debug.assert; test "nested break" { var count: usize = 0; - outer: for ([]i32.{ 1, 2, 3, 4, 5 }) |_| { - for ([]i32.{ 1, 2, 3, 4, 5 }) |_| { + outer: for ([]i32{ 1, 2, 3, 4, 5 }) |_| { + for ([]i32{ 1, 2, 3, 4, 5 }) |_| { count += 1; break :outer; } @@ -2764,8 +2766,8 @@ test "nested break" { test "nested continue" { var count: usize = 0; - outer: for ([]i32.{ 1, 2, 3, 4, 5, 6, 7, 8 }) |_| { - for ([]i32.{ 1, 2, 3, 4, 5 }) |_| { + outer: for ([]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }) |_| { + for ([]i32{ 1, 2, 3, 4, 5 }) |_| { count += 1; continue :outer; } @@ -2787,7 +2789,7 @@ test "nested continue" { const assert = @import("std").debug.assert; test "inline for loop" { - const nums = []i32.{2, 4, 6}; + const nums = []i32{2, 4, 6}; var sum: usize = 0; inline for (nums) |i| { const T = switch (i) { @@ -2822,7 +2824,7 @@ fn typeNameLength(comptime T: type) usize { // If expressions have three uses, corresponding to the three types: // * bool // * ?T -// * error!T +// * anyerror!T const assert = @import("std").debug.assert; @@ -2887,14 +2889,14 @@ test "if error union" { // If expressions test for errors. // Note the |err| capture on the else. - const a: error!u32 = 0; + const a: anyerror!u32 = 0; if (a) |value| { assert(value == 0); } else |err| { unreachable; } - const b: error!u32 = error.BadValue; + const b: anyerror!u32 = error.BadValue; if (b) |value| { unreachable; } else |err| { @@ -2912,7 +2914,7 @@ test "if error union" { } // Access the value by reference using a pointer capture. - var c: error!u32 = 3; + var c: anyerror!u32 = 3; if (c) |*value| { value.* = 9; } else |err| { @@ -3089,7 +3091,7 @@ test "foo" { assert(value == 1234); } -fn bar() error!u32 { +fn bar() anyerror!u32 { return 1234; } @@ -3164,7 +3166,7 @@ fn foo() void { } In Zig, structs, unions, and enums with payloads can be passed directly to a function:

    {#code_begin|test#} -const Point = struct.{ +const Point = struct { x: i32, y: i32, }; @@ -3176,7 +3178,7 @@ fn foo(point: Point) i32 { const assert = @import("std").debug.assert; test "pass aggregate type by non-copy value to function" { - assert(foo(Point.{ .x = 1, .y = 2 }) == 3); + assert(foo(Point{ .x = 1, .y = 2 }) == 3); } {#code_end#}

    @@ -3216,13 +3218,13 @@ test "fn reflection" { {#code_begin|test#} const std = @import("std"); -const FileOpenError = error.{ +const FileOpenError = error { AccessDenied, OutOfMemory, FileNotFound, }; -const AllocationError = error.{ +const AllocationError = error { OutOfMemory, }; @@ -3239,13 +3241,13 @@ fn foo(err: AllocationError) FileOpenError { But you cannot implicitly cast an error from a superset to a subset:

    {#code_begin|test_err|not a member of destination error set#} -const FileOpenError = error.{ +const FileOpenError = error { AccessDenied, OutOfMemory, FileNotFound, }; -const AllocationError = error.{ +const AllocationError = error { OutOfMemory, }; @@ -3265,13 +3267,13 @@ const err = error.FileNotFound; {#code_end#}

    This is equivalent to:

    {#code_begin|syntax#} -const err = (error.{FileNotFound}).FileNotFound; +const err = (error {FileNotFound}).FileNotFound; {#code_end#}

    This becomes useful when using {#link|Inferred Error Sets#}.

    {#header_open|The Global Error Set#} -

    {#syntax#}error.{#endsyntax#} refers to the global error set. +

    {#syntax#}error{#endsyntax#} refers to the global error set. This is the error set that contains all errors in the entire compilation unit. It is a superset of all other error sets and a subset of none of them.

    @@ -3347,7 +3349,7 @@ test "parse u64" {

    Within the function definition, you can see some return statements that return an error, and at the bottom a return statement that returns a {#syntax#}u64{#endsyntax#}. - Both types {#link|implicitly cast|Implicit Casts#} to {#syntax#}error!u64{#endsyntax#}. + Both types {#link|implicitly cast|Implicit Casts#} to {#syntax#}anyerror!u64{#endsyntax#}.

    What it looks like to use this function varies depending on what you're @@ -3472,7 +3474,7 @@ fn createFoo(param: i32) !Foo {

  • Since Zig understands error types, it can pre-weight branches in favor of - errors not occuring. Just a small optimization benefit that is not available + errors not occurring. Just a small optimization benefit that is not available in other languages.
  • @@ -3484,7 +3486,7 @@ fn createFoo(param: i32) !Foo { const assert = @import("std").debug.assert; test "error union" { - var foo: error!i32 = undefined; + var foo: anyerror!i32 = undefined; // Implicitly cast from child type of an error union: foo = 1234; @@ -3496,7 +3498,7 @@ test "error union" { comptime assert(@typeOf(foo).Payload == i32); // Use compile-time reflection to access the error set type of an error union: - comptime assert(@typeOf(foo).ErrorSet == error); + comptime assert(@typeOf(foo).ErrorSet == anyerror); } {#code_end#} {#header_open|Merging Error Sets#} @@ -3513,13 +3515,13 @@ test "error union" { files.

    {#code_begin|test#} -const A = error.{ +const A = error{ NotDir, /// A doc comment PathNotFound, }; -const B = error.{ +const B = error{ OutOfMemory, /// B doc comment @@ -3561,7 +3563,7 @@ pub fn add_explicit(comptime T: type, a: T, b: T) Error!T { return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer; } -const Error = error.{ +const Error = error { Overflow, }; @@ -3720,11 +3722,11 @@ fn bang2() void {
  • when returning errors
  • - For the case when no errors are returned, the cost is a single memory write operation, only in the first non-failable function in the call graph that calls a failable function, i.e. when a function returning {#syntax#}void{#endsyntax#} calls a function returning {#syntax#}error.{#endsyntax#}. + For the case when no errors are returned, the cost is a single memory write operation, only in the first non-failable function in the call graph that calls a failable function, i.e. when a function returning {#syntax#}void{#endsyntax#} calls a function returning {#syntax#}error{#endsyntax#}. This is to initialize this struct in the stack memory:

    {#code_begin|syntax#} -pub const StackTrace = struct.{ +pub const StackTrace = struct { index: usize, instruction_addresses: [N]usize, }; @@ -3754,7 +3756,7 @@ fn __zig_return_error(stack_trace: *StackTrace) void {

    As for code size cost, 1 function call before a return statement is no big deal. Even so, I have a plan to make the call to - {#syntax#}__zig_return_error.{#endsyntax#} a tail call, which brings the code size cost down to actually zero. What is a return statement in code without error return tracing can become a jump instruction in code with error return tracing. + {#syntax#}__zig_return_error{#endsyntax#} a tail call, which brings the code size cost down to actually zero. What is a return statement in code without error return tracing can become a jump instruction in code with error return tracing.

    {#header_close#} {#header_close#} @@ -3975,7 +3977,7 @@ const assert = std.debug.assert; const mem = std.mem; test "cast *[1][*]const u8 to [*]const ?[*]const u8" { - const window_name = [1][*]const u8.{c"window name"}; + const window_name = [1][*]const u8{c"window name"}; const x: [*]const ?[*]const u8 = &window_name; assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); } @@ -4158,12 +4160,12 @@ test "peer type resolution: [0]u8 and []const u8" { } fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { if (a) { - return []const u8.{}; + return []const u8{}; } return slice[0..1]; } -test "peer type resolution: [0]u8, []const u8, and error![]u8" { +test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { { var data = "hi"; const slice = data[0..]; @@ -4177,9 +4179,9 @@ test "peer type resolution: [0]u8, []const u8, and error![]u8" { assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); } } -fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) error![]u8 { +fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { if (a) { - return []u8.{}; + return []u8{}; } return slice[0..1]; @@ -4402,15 +4404,15 @@ fn max(a: bool, b: bool) bool { {#code_begin|test|comptime_vars#} const assert = @import("std").debug.assert; -const CmdFn = struct.{ +const CmdFn = struct { name: []const u8, func: fn(i32) i32, }; -const cmd_fns = []CmdFn.{ - CmdFn.{.name = "one", .func = one}, - CmdFn.{.name = "two", .func = two}, - CmdFn.{.name = "three", .func = three}, +const cmd_fns = []CmdFn{ + CmdFn {.name = "one", .func = one}, + CmdFn {.name = "two", .func = two}, + CmdFn {.name = "three", .func = three}, }; fn one(value: i32) i32 { return value + 1; } fn two(value: i32) i32 { return value + 2; } @@ -4668,7 +4670,7 @@ test "variable values" {

    {#code_begin|syntax#} fn List(comptime T: type) type { - return struct.{ + return struct { items: []T, len: usize, }; @@ -4684,7 +4686,7 @@ fn List(comptime T: type) type { a name, we assign it to a constant:

    {#code_begin|syntax#} -const Node = struct.{ +const Node = struct { next: *Node, name: []u8, }; @@ -4717,8 +4719,8 @@ pub fn main() void { {#code_begin|syntax#} /// Calls print and then flushes the buffer. -pub fn printf(self: *OutStream, comptime format: []const u8, args: ...) error!void { - const State = enum.{ +pub fn printf(self: *OutStream, comptime format: []const u8, args: ...) anyerror!void { + const State = enum { Start, OpenBrace, CloseBrace, @@ -4963,7 +4965,7 @@ async fn testAsyncSeq() void { suspend; seq('d'); } -var points = []u8.{0} ** "abcdefg".len; +var points = []u8{0} ** "abcdefg".len; var index: usize = 0; fn seq(c: u8) void { @@ -5101,7 +5103,7 @@ async fn another() i32 { return 1234; } -var seq_points = []u8.{0} ** "abcdefghi".len; +var seq_points = []u8{0} ** "abcdefghi".len; var seq_index: usize = 0; fn seq(c: u8) void { @@ -5784,7 +5786,7 @@ fn add(a: i32, b: i32) i32 { return a + b; } {#header_close#} {#header_open|@intToError#} -
    {#syntax#}@intToError(value: @IntType(false, @sizeOf(error) * 8)) error.{#endsyntax#}
    +
    {#syntax#}@intToError(value: @IntType(false, @sizeOf(anyerror) * 8)) anyerror{#endsyntax#}

    Converts from the integer representation of an error into the global error set type.

    @@ -5814,9 +5816,10 @@ fn add(a: i32, b: i32) i32 { return a + b; } {#header_close#} {#header_open|@IntType#} -
    {#syntax#}@IntType(comptime is_signed: bool, comptime bit_count: u32) type{#endsyntax#}
    +
    {#syntax#}@IntType(comptime is_signed: bool, comptime bit_count: u16) type{#endsyntax#}

    - This function returns an integer type with the given signness and bit count. + This function returns an integer type with the given signness and bit count. The maximum + bit count for an integer type is {#syntax#}65535{#endsyntax#}.

    {#header_close#} {#header_open|@memberCount#} @@ -6114,7 +6117,7 @@ test "foo" { Sets the floating point mode of the current scope. Possible values are:

    {#code_begin|syntax#} -pub const FloatMode = enum.{ +pub const FloatMode = enum { Strict, Optimized, }; @@ -6249,13 +6252,13 @@ const std = @import("std"); const assert = std.debug.assert; test "@This()" { - var items = []i32.{ 1, 2, 3, 4 }; - const list = List(i32).{ .items = items[0..] }; + var items = []i32{ 1, 2, 3, 4 }; + const list = List(i32){ .items = items[0..] }; assert(list.length() == 4); } fn List(comptime T: type) type { - return struct.{ + return struct { const Self = @This(); items: []T, @@ -6303,7 +6306,7 @@ const b: u8 = @truncate(u8, a); Returns which kind of type something is. Possible values:

    {#code_begin|syntax#} -pub const TypeId = enum.{ +pub const TypeId = enum { Type, Void, Bool, @@ -6337,7 +6340,7 @@ pub const TypeId = enum.{ Returns information on the type. Returns a value of the following union:

    {#code_begin|syntax#} -pub const TypeInfo = union(TypeId).{ +pub const TypeInfo = union(TypeId) { Type: void, Void: void, Bool: void, @@ -6364,96 +6367,96 @@ pub const TypeInfo = union(TypeId).{ Promise: Promise, - pub const Int = struct.{ + pub const Int = struct { is_signed: bool, bits: u8, }; - pub const Float = struct.{ + pub const Float = struct { bits: u8, }; - pub const Pointer = struct.{ + pub const Pointer = struct { size: Size, is_const: bool, is_volatile: bool, alignment: u32, child: type, - pub const Size = enum.{ + pub const Size = enum { One, Many, Slice, }; }; - pub const Array = struct.{ + pub const Array = struct { len: usize, child: type, }; - pub const ContainerLayout = enum.{ + pub const ContainerLayout = enum { Auto, Extern, Packed, }; - pub const StructField = struct.{ + pub const StructField = struct { name: []const u8, offset: ?usize, field_type: type, }; - pub const Struct = struct.{ + pub const Struct = struct { layout: ContainerLayout, fields: []StructField, defs: []Definition, }; - pub const Optional = struct.{ + pub const Optional = struct { child: type, }; - pub const ErrorUnion = struct.{ + pub const ErrorUnion = struct { error_set: type, payload: type, }; - pub const Error = struct.{ + pub const Error = struct { name: []const u8, value: usize, }; - pub const ErrorSet = struct.{ + pub const ErrorSet = struct { errors: []Error, }; - pub const EnumField = struct.{ + pub const EnumField = struct { name: []const u8, value: usize, }; - pub const Enum = struct.{ + pub const Enum = struct { layout: ContainerLayout, tag_type: type, fields: []EnumField, defs: []Definition, }; - pub const UnionField = struct.{ + pub const UnionField = struct { name: []const u8, enum_field: ?EnumField, field_type: type, }; - pub const Union = struct.{ + pub const Union = struct { layout: ContainerLayout, tag_type: ?type, fields: []UnionField, defs: []Definition, }; - pub const CallingConvention = enum.{ + pub const CallingConvention = enum { Unspecified, C, Cold, @@ -6462,13 +6465,13 @@ pub const TypeInfo = union(TypeId).{ Async, }; - pub const FnArg = struct.{ + pub const FnArg = struct { is_generic: bool, is_noalias: bool, arg_type: ?type, }; - pub const Fn = struct.{ + pub const Fn = struct { calling_convention: CallingConvention, is_generic: bool, is_var_args: bool, @@ -6477,21 +6480,21 @@ pub const TypeInfo = union(TypeId).{ args: []FnArg, }; - pub const Promise = struct.{ + pub const Promise = struct { child: ?type, }; - pub const Definition = struct.{ + pub const Definition = struct { name: []const u8, is_pub: bool, data: Data, - pub const Data = union(enum).{ + pub const Data = union(enum) { Type: type, Var: type, Fn: FnDef, - pub const FnDef = struct.{ + pub const FnDef = struct { fn_type: type, inline_type: Inline, calling_convention: CallingConvention, @@ -6502,7 +6505,7 @@ pub const TypeInfo = union(TypeId).{ return_type: type, arg_names: [][] const u8, - pub const Inline = enum.{ + pub const Inline = enum { Auto, Always, Never, @@ -6913,7 +6916,7 @@ pub fn main() void {

    At compile-time:

    {#code_begin|test_err|unable to convert#} comptime { - var bytes = [5]u8.{ 1, 2, 3, 4, 5 }; + var bytes = [5]u8{ 1, 2, 3, 4, 5 }; var slice = @bytesToSlice(u32, bytes); } {#code_end#} @@ -6922,7 +6925,7 @@ comptime { const std = @import("std"); pub fn main() void { - var bytes = [5]u8.{ 1, 2, 3, 4, 5 }; + var bytes = [5]u8{ 1, 2, 3, 4, 5 }; var slice = @bytesToSlice(u32, bytes[0..]); std.debug.warn("value: {}\n", slice[0]); } @@ -7031,7 +7034,7 @@ pub fn main() void { {#header_open|Invalid Enum Cast#}

    At compile-time:

    {#code_begin|test_err|has no tag matching integer value 3#} -const Foo = enum.{ +const Foo = enum { A, B, C, @@ -7045,7 +7048,7 @@ comptime { {#code_begin|exe_err#} const std = @import("std"); -const Foo = enum.{ +const Foo = enum { A, B, C, @@ -7062,11 +7065,11 @@ pub fn main() void { {#header_open|Invalid Error Set Cast#}

    At compile-time:

    {#code_begin|test_err|error.B not a member of error set 'Set2'#} -const Set1 = error.{ +const Set1 = error{ A, B, }; -const Set2 = error.{ +const Set2 = error{ A, C, }; @@ -7078,11 +7081,11 @@ comptime { {#code_begin|exe_err#} const std = @import("std"); -const Set1 = error.{ +const Set1 = error{ A, B, }; -const Set2 = error.{ +const Set2 = error{ A, C, }; @@ -7107,7 +7110,7 @@ comptime {

    At runtime:

    {#code_begin|exe_err#} pub fn main() !void { - var array align(4) = []u32.{ 0x11111111, 0x11111111 }; + var array align(4) = []u32{ 0x11111111, 0x11111111 }; const bytes = @sliceToBytes(array[0..]); if (foo(bytes) != 0x11111111) return error.Wrong; } @@ -7122,11 +7125,11 @@ fn foo(bytes: []u8) u32 {

    At compile-time:

    {#code_begin|test_err|accessing union field 'float' while field 'int' is set#} comptime { - var f = Foo.{ .int = 42 }; + var f = Foo{ .int = 42 }; f.float = 12.34; } -const Foo = union.{ +const Foo = union { float: f32, int: u32, }; @@ -7135,13 +7138,13 @@ const Foo = union.{ {#code_begin|exe_err#} const std = @import("std"); -const Foo = union.{ +const Foo = union { float: f32, int: u32, }; pub fn main() void { - var f = Foo.{ .int = 42 }; + var f = Foo{ .int = 42 }; bar(&f); } @@ -7159,18 +7162,18 @@ fn bar(f: *Foo) void { {#code_begin|exe#} const std = @import("std"); -const Foo = union.{ +const Foo = union { float: f32, int: u32, }; pub fn main() void { - var f = Foo.{ .int = 42 }; + var f = Foo{ .int = 42 }; bar(&f); } fn bar(f: *Foo) void { - f.* = Foo.{ .float = 12.34 }; + f.* = Foo{ .float = 12.34 }; std.debug.warn("value: {}\n", f.float); } {#code_end#} @@ -7181,14 +7184,14 @@ fn bar(f: *Foo) void { {#code_begin|exe#} const std = @import("std"); -const Foo = union.{ +const Foo = union { float: f32, int: u32, }; pub fn main() void { - var f = Foo.{ .int = 42 }; - f = Foo.{ .float = undefined }; + var f = Foo{ .int = 42 }; + f = Foo{ .float = undefined }; bar(&f); std.debug.warn("value: {}\n", f.float); } @@ -7367,13 +7370,13 @@ pub fn build(b: *Builder) void { const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); const exe = b.addCExecutable("test"); - exe.addCompileFlags([][]const u8.{"-std=c99"}); + exe.addCompileFlags([][]const u8{"-std=c99"}); exe.addSourceFile("test.c"); exe.linkLibrary(lib); b.default_step.dependOn(&exe.step); - const run_cmd = b.addCommand(".", b.env_map, [][]const u8.{exe.getOutputPath()}); + const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()}); run_cmd.step.dependOn(&exe.step); const test_step = b.step("test", "Test the program"); @@ -7433,7 +7436,7 @@ pub fn build(b: *Builder) void { const obj = b.addObject("base64", "base64.zig"); const exe = b.addCExecutable("test"); - exe.addCompileFlags([][]const u8.{ + exe.addCompileFlags([][]const u8 { "-std=c99", }); exe.addSourceFile("test.c"); @@ -7611,7 +7614,7 @@ coding style. Open braces on same line, unless you need to wrap.
  • If a list of things is longer than 2, put each item on its own line and - exercise the abilty to put an extra comma at the end. + exercise the ability to put an extra comma at the end.
  • Line length: aim for 100; use common sense. @@ -7661,7 +7664,7 @@ const const_name = 42; const primitive_type_alias = f32; const string_alias = []u8; -const StructName = struct.{}; +const StructName = struct {}; const StructAlias = StructName; fn functionName(param_name: TypeName) void { @@ -7677,7 +7680,7 @@ fn ListTemplateFunction(comptime ChildType: type, comptime fixed_size: usize) ty } fn ShortList(comptime T: type, comptime n: usize) type { - return struct.{ + return struct { field_name: [n]T, fn methodName() void {} }; @@ -7689,7 +7692,7 @@ const xml_document = \\ \\ ; -const XmlParser = struct.{}; +const XmlParser = struct {}; // The initials BE (Big Endian) are just another word in Zig identifier names. fn readU32Be() u32 {} @@ -7710,167 +7713,506 @@ fn readU32Be() u32 {}

    For some discussion on the rationale behind these design decisions, see issue #663

    {#header_close#} {#header_open|Grammar#} -
    Root = many(TopLevelItem) EOF
    +      
    Root <- skip ContainerMembers eof
     
    -TopLevelItem = CompTimeExpression(Block) | TopLevelDecl | TestDecl
    +# *** Top level ***
    +ContainerMembers
    +    <- TestDecl ContainerMembers
    +     / TopLevelComptime ContainerMembers
    +     / KEYWORD_pub? TopLevelDecl ContainerMembers
    +     / KEYWORD_pub? ContainerField COMMA ContainerMembers
    +     / KEYWORD_pub? ContainerField
    +     /
     
    -TestDecl = "test" String Block
    +TestDecl <- KEYWORD_test STRINGLITERAL Block
     
    -TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
    +TopLevelComptime <- KEYWORD_comptime BlockExpr
     
    -GlobalVarDecl = option("export") VariableDeclaration ";"
    +TopLevelDecl
    +    <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block)
    +     / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? VarDecl
    +     / KEYWORD_use Expr SEMICOLON
     
    -LocalVarDecl = option("comptime") VariableDeclaration
    +FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
     
    -VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression
    +VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
     
    -ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
    +ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)?
     
    -ContainerField = Symbol option(":" PrefixOpExpression) option("=" PrefixOpExpression) ","
    +# *** Block Level ***
    +Statement
    +    <- KEYWORD_comptime? VarDecl
    +     / KEYWORD_comptime BlockExprStatement
    +     / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
    +     / KEYWORD_defer BlockExprStatement
    +     / KEYWORD_errdefer BlockExprStatement
    +     / IfStatement
    +     / LabeledStatement
    +     / SwitchExpr
    +     / AssignExpr SEMICOLON
     
    -UseDecl = "use" Expression ";"
    +IfStatement
    +    <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
    +     / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
     
    -ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
    +LabeledStatement <- BlockLabel? (Block / LoopStatement)
     
    -FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("<" Expression ">"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var")
    +LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
     
    -FnDef = option("inline" | "export") FnProto Block
    +ForStatement
    +    <- ForPrefix BlockExpr ( KEYWORD_else Statement )?
    +     / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )
     
    -ParamDeclList = "(" list(ParamDecl, ",") ")"
    +WhileStatement
    +    <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
    +     / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
     
    -ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "var" | "...")
    +BlockExprStatement
    +    <- BlockExpr
    +     / AssignExpr SEMICOLON
     
    -Block = option(Symbol ":") "{" many(Statement) "}"
    +BlockExpr <- BlockLabel? Block
     
    -Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
    +# *** Expression Level ***
    +AssignExpr <- Expr (AssignOp Expr)?
     
    -TypeExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
    +Expr <- KEYWORD_try* BoolOrExpr
     
    -BlockOrExpression = Block | Expression
    +BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
     
    -Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression
    +BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
     
    -AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"
    +CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
     
    -AsmOutput = ":" list(AsmOutputItem, ",") option(AsmInput)
    +BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
     
    -AsmInput = ":" list(AsmInputItem, ",") option(AsmClobbers)
    +BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
     
    -AsmOutputItem = "[" Symbol "]" String "(" (Symbol | "->" TypeExpr) ")"
    +AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
     
    -AsmInputItem = "[" Symbol "]" String "(" Expression ")"
    +MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
     
    -AsmClobbers= ":" list(String, ",")
    +PrefixExpr <- PrefixOp* PrimaryExpr
     
    -UnwrapExpression = BoolOrExpression (UnwrapOptional | UnwrapError) | BoolOrExpression
    +PrimaryExpr
    +    <- AsmExpr
    +     / IfExpr
    +     / KEYWORD_break BreakLabel? Expr?
    +     / KEYWORD_cancel Expr
    +     / KEYWORD_comptime Expr
    +     / KEYWORD_continue BreakLabel?
    +     / KEYWORD_resume Expr
    +     / KEYWORD_return Expr?
    +     / LabeledExpr
    +     / CurlySuffixExpr
     
    -UnwrapOptional = "orelse" Expression
    +IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?
     
    -UnwrapError = "catch" option("|" Symbol "|") Expression
    +LabeledExpr <- BlockLabel? (Block / LoopExpr)
     
    -AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression
    +Block <- LBRACE Statement* RBRACE
     
    -AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "*%=" | "+%=" | "-%="
    +LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
     
    -BlockExpression(body) = Block | IfExpression(body) | IfErrorExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) | SuspendExpression(body)
    +ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?
     
    -CompTimeExpression(body) = "comptime" body
    +WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
     
    -SwitchExpression = "switch" "(" Expression ")" "{" many(SwitchProng) "}"
    +CurlySuffixExpr <- TypeExpr InitList?
     
    -SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbol "|") Expression ","
    +InitList
    +    <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
    +     / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
    +     / LBRACE RBRACE
     
    -SwitchItem = Expression | (Expression "..." Expression)
    +TypeExpr <- PrefixTypeOp* ErrorUnionExpr
     
    -ForExpression(body) = option(Symbol ":") option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body))
    +ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
     
    -BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
    +SuffixExpr
    +    <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArgumnets
    +     / PrimaryTypeExpr (SuffixOp / FnCallArgumnets)*
     
    -ReturnExpression = "return" option(Expression)
    +PrimaryTypeExpr
    +    <- BUILTININDENTIFIER FnCallArgumnets
    +     / CHAR_LITERAL
    +     / ContainerDecl
    +     / ErrorSetDecl
    +     / FLOAT
    +     / FnProto
    +     / GroupedExpr
    +     / LabeledTypeExpr
    +     / IDENTIFIER
    +     / IfTypeExpr
    +     / INTEGER
    +     / KEYWORD_anyerror
    +     / KEYWORD_comptime TypeExpr
    +     / KEYWORD_error DOT IDENTIFIER
    +     / KEYWORD_false
    +     / KEYWORD_null
    +     / KEYWORD_promise
    +     / KEYWORD_true
    +     / KEYWORD_undefined
    +     / KEYWORD_unreachable
    +     / STRINGLITERAL
    +     / SwitchExpr
     
    -TryExpression = "try" Expression
    +ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
     
    -AwaitExpression = "await" Expression
    +ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
     
    -BreakExpression = "break" option(":" Symbol) option(Expression)
    +GroupedExpr <- LPAREN Expr RPAREN
     
    -CancelExpression = "cancel" Expression;
    +IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
     
    -ResumeExpression = "resume" Expression;
    +LabeledTypeExpr
    +    <- BlockLabel Block
    +     / BlockLabel? LoopTypeExpr
     
    -Defer(body) = ("defer" | "errdefer") body
    +LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
     
    -IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
    +ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?
     
    -SuspendExpression(body) = "suspend" option( body )
    +WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
     
    -IfErrorExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body "else" "|" Symbol "|" BlockExpression(body)
    +SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
     
    -TestExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body option("else" BlockExpression(body))
    +# *** Assembly ***
    +AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN STRINGLITERAL AsmOutput? RPAREN
     
    -WhileExpression(body) = option(Symbol ":") option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body))
    +AsmOutput <- COLON AsmOutputList AsmInput?
     
    -BoolAndExpression = ComparisonExpression "and" BoolAndExpression | ComparisonExpression
    +AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
     
    -ComparisonExpression = BinaryOrExpression ComparisonOperator BinaryOrExpression | BinaryOrExpression
    +AsmInput <- COLON AsmInputList AsmCloppers?
     
    -ComparisonOperator = "==" | "!=" | "<" | ">" | "<=" | ">="
    +AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
     
    -BinaryOrExpression = BinaryXorExpression "|" BinaryOrExpression | BinaryXorExpression
    +AsmCloppers <- COLON StringList
     
    -BinaryXorExpression = BinaryAndExpression "^" BinaryXorExpression | BinaryAndExpression
    +# *** Helper grammar ***
    +BreakLabel <- COLON IDENTIFIER
     
    -BinaryAndExpression = BitShiftExpression "&" BinaryAndExpression | BitShiftExpression
    +BlockLabel <- IDENTIFIER COLON
     
    -BitShiftExpression = AdditionExpression BitShiftOperator BitShiftExpression | AdditionExpression
    +FieldInit <- DOT IDENTIFIER EQUAL Expr
     
    -BitShiftOperator = "<<" | ">>"
    +WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
     
    -AdditionExpression = MultiplyExpression AdditionOperator AdditionExpression | MultiplyExpression
    +LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
     
    -AdditionOperator = "+" | "-" | "++" | "+%" | "-%"
    +# Fn specific
    +FnCC
    +    <- KEYWORD_nakedcc
    +     / KEYWORD_stdcallcc
    +     / KEYWORD_extern
    +     / KEYWORD_async (LARROW TypeExpr RARROW)?
     
    -MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | CurlySuffixExpression
    +ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
     
    -CurlySuffixExpression = TypeExpr option(ContainerInitExpression)
    +ParamType
    +    <- KEYWORD_var
    +     / DOT3
    +     / TypeExpr
     
    -MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
    +# Control flow prefixes
    +IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
     
    -PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
    +WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
     
    -SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ".*" | ".?")
    +ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
     
    -FieldAccessExpression = "." Symbol
    +# Payloads
    +Payload <- PIPE IDENTIFIER PIPE
     
    -FnCallExpression = "(" list(Expression, ",") ")"
    +PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
     
    -ArrayAccessExpression = "[" Expression "]"
    +PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
     
    -SliceExpression = "[" Expression ".." option(Expression) "]"
     
    -ContainerInitExpression = "." "{" ContainerInitBody "}"
    +# Switch specific
    +SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr
     
    -ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
    +SwitchCase
    +    <- SwitchItem (COMMA SwitchItem)* COMMA?
    +     / KEYWORD_else
     
    -StructLiteralField = "." Symbol "=" Expression
    +SwitchItem <- Expr (DOT3 Expr)?
     
    -PrefixOp = "!" | "-" | "~" | (("*" | "[*]") option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "-%" | "try" | "await"
    +# Operators
    +AssignOp
    +    <- ASTERISKEQUAL
    +     / SLASHEQUAL
    +     / PERCENTEQUAL
    +     / PLUSEQUAL
    +     / MINUSEQUAL
    +     / LARROW2EQUAL
    +     / RARROW2EQUAL
    +     / AMPERSANDEQUAL
    +     / CARETEQUAL
    +     / PIPEEQUAL
    +     / ASTERISKPERCENTEQUAL
    +     / PLUSPERCENTEQUAL
    +     / MINUSPERCENTEQUAL
    +     / EQUAL
     
    -PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
    +CompareOp
    +    <- EQUALEQUAL
    +     / EXCLAMATIONMARKEQUAL
    +     / LARROW
    +     / RARROW
    +     / LARROWEQUAL
    +     / RARROWEQUAL
     
    -PromiseType = "promise" option("->" TypeExpr)
    +BitwiseOp
    +    <- AMPERSAND
    +     / CARET
    +     / PIPE
    +     / KEYWORD_orelse
    +     / KEYWORD_catch Payload?
     
    -ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr
    +BitShiftOp
    +    <- LARROW2
    +     / RARROW2
     
    -GroupedExpression = "(" Expression ")"
    -
    -KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "unreachable" | "suspend"
    -
    -ErrorSetDecl = "error" "." "{" list(Symbol, ",") "}"
    -
    -ContainerDecl = option("extern" | "packed")
    -  ("struct" "." option(GroupedExpression) | "union" "." option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" "." option(GroupedExpression)))
    -  "{" many(ContainerMember) "}"
    +AdditionOp + <- PLUS + / MINUS + / PLUS2 + / PLUSPERCENT + / MINUSPERCENT + +MultiplyOp + <- PIPE2 + / ASTERISK + / SLASH + / PERCENT + / ASTERISK2 + / ASTERISKPERCENT + +PrefixOp + <- EXCLAMATIONMARK + / MINUS + / TILDE + / MINUSPERCENT + / AMPERSAND + / KEYWORD_try + / KEYWORD_await + +PrefixTypeOp + <- QUESTIONMARK + / KEYWORD_promise MINUSRARROW + / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)* + / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)* + +SuffixOp + <- LBRACKET Expr (DOT2 Expr?)? RBRACKET + / DOT IDENTIFIER + / DOTASTERISK + / DOTQUESTIONMARK + +AsyncPrefix <- KEYWORD_async (LARROW PrefixExpr RARROW)? + +FnCallArgumnets <- LPAREN ExprList RPAREN + +# Ptr specific +ArrayTypeStart <- LBRACKET Expr? RBRACKET + +PtrTypeStart + <- ASTERISK + / ASTERISK2 + / LBRACKET ASTERISK RBRACKET + +# ContainerDecl specific +ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE + +ContainerDeclType + <- (KEYWORD_struct / KEYWORD_enum) (LPAREN Expr RPAREN)? + / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? + +# Alignment +ByteAlign <- KEYWORD_align LPAREN Expr RPAREN + +# Lists +IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER? + +SwitchProngList <- (SwitchProng COMMA)* SwitchProng? + +AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem? + +AsmInputList <- (AsmInputItem COMMA)* AsmInputItem? + +StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL? + +ParamDeclList <- (ParamDecl COMMA)* ParamDecl? + +ExprList <- (Expr COMMA)* Expr? + +# *** Tokens *** +eof <- !. +hex <- [0-9a-fA-F] +char_escape + <- "\\x" hex hex + / "\\u" hex hex hex hex + / "\\U" hex hex hex hex hex hex + / "\\" [nr\\t'"] +char_char + <- char_escape + / [^\\'\n] +string_char + <- char_escape + / [^\\"\n] + +line_comment <- '//'[^\n]* +line_string <- ("\\\\" [^\n]* [ \n]*)+ +line_cstring <- ("c\\\\" [^\n]* [ \n]*)+ +skip <- ([ \n] / line_comment)* + +CHAR_LITERAL <- "'" char_char "'" skip +FLOAT + <- "0b" [01]+ "." [01]+ ([eE] [-+]? [01]+)? skip + / "0o" [0-7]+ "." [0-7]+ ([eE] [-+]? [0-7]+)? skip + / "0x" hex+ "." hex+ ([pP] [-+]? hex+)? skip + / [0-9]+ "." [0-9]+ ([eE] [-+]? [0-9]+)? skip + / "0b" [01]+ "."? [eE] [-+]? [01]+ skip + / "0o" [0-7]+ "."? [eE] [-+]? [0-7]+ skip + / "0x" hex+ "."? [pP] [-+]? hex+ skip + / [0-9]+ "."? [eE] [-+]? [0-9]+ skip +INTEGER + <- "0b" [01]+ skip + / "0o" [0-7]+ skip + / "0x" hex+ skip + / [0-9]+ skip +STRINGLITERAL + <- "c"? "\"" string_char* "\"" skip + / line_string skip + / line_cstring skip +IDENTIFIER + <- !keyword ("c" !["\\] / [A-Zabd-z_]) [A-Za-z0-9_]* skip + / "@\"" string_char* "\"" skip +BUILTININDENTIFIER <- "@"[A-Za-z_][A-Za-z0-9_]* skip + + +AMPERSAND <- '&' ![=] skip +AMPERSANDEQUAL <- '&=' skip +ASTERISK <- '*' ![*%=] skip +ASTERISK2 <- '**' skip +ASTERISKEQUAL <- '*=' skip +ASTERISKPERCENT <- '*%' ![=] skip +ASTERISKPERCENTEQUAL <- '*%=' skip +CARET <- '^' ![=] skip +CARETEQUAL <- '^=' skip +COLON <- ':' skip +COMMA <- ',' skip +DOT <- '.' ![*.?] skip +DOT2 <- '..' ![.] skip +DOT3 <- '...' skip +DOTASTERISK <- '.*' skip +DOTQUESTIONMARK <- '.?' skip +EQUAL <- '=' ![>=] skip +EQUALEQUAL <- '==' skip +EQUALRARROW <- '=>' skip +EXCLAMATIONMARK <- '!' ![=] skip +EXCLAMATIONMARKEQUAL <- '!=' skip +LARROW <- '<' ![<=] skip +LARROW2 <- '<<' ![=] skip +LARROW2EQUAL <- '<<=' skip +LARROWEQUAL <- '<=' skip +LBRACE <- '{' skip +LBRACKET <- '[' skip +LPAREN <- '(' skip +MINUS <- '-' ![%=>] skip +MINUSEQUAL <- '-=' skip +MINUSPERCENT <- '-%' ![=] skip +MINUSPERCENTEQUAL <- '-%=' skip +MINUSRARROW <- '->' skip +PERCENT <- '%' ![=] skip +PERCENTEQUAL <- '%=' skip +PIPE <- '|' ![|=] skip +PIPE2 <- '||' skip +PIPEEQUAL <- '|=' skip +PLUS <- '+' ![%+=] skip +PLUS2 <- '++' skip +PLUSEQUAL <- '+=' skip +PLUSPERCENT <- '+%' ![=] skip +PLUSPERCENTEQUAL <- '+%=' skip +QUESTIONMARK <- '?' skip +RARROW <- '>' ![>=] skip +RARROW2 <- '>>' ![=] skip +RARROW2EQUAL <- '>>=' skip +RARROWEQUAL <- '>=' skip +RBRACE <- '}' skip +RBRACKET <- ']' skip +RPAREN <- ')' skip +SEMICOLON <- ';' skip +SLASH <- '/' ![=] skip +SLASHEQUAL <- '/=' skip +TILDE <- '~' skip + +end_of_word <- ![a-zA-Z0-9_] skip +KEYWORD_align <- 'align' end_of_word +KEYWORD_and <- 'and' end_of_word +KEYWORD_anyerror <- 'anyerror' end_of_word +KEYWORD_asm <- 'asm' end_of_word +KEYWORD_async <- 'async' end_of_word +KEYWORD_await <- 'await' end_of_word +KEYWORD_break <- 'break' end_of_word +KEYWORD_cancel <- 'cancel' end_of_word +KEYWORD_catch <- 'catch' end_of_word +KEYWORD_comptime <- 'comptime' end_of_word +KEYWORD_const <- 'const' end_of_word +KEYWORD_continue <- 'continue' end_of_word +KEYWORD_defer <- 'defer' end_of_word +KEYWORD_else <- 'else' end_of_word +KEYWORD_enum <- 'enum' end_of_word +KEYWORD_errdefer <- 'errdefer' end_of_word +KEYWORD_error <- 'error' end_of_word +KEYWORD_export <- 'export' end_of_word +KEYWORD_extern <- 'extern' end_of_word +KEYWORD_false <- 'false' end_of_word +KEYWORD_fn <- 'fn' end_of_word +KEYWORD_for <- 'for' end_of_word +KEYWORD_if <- 'if' end_of_word +KEYWORD_inline <- 'inline' end_of_word +KEYWORD_nakedcc <- 'nakedcc' end_of_word +KEYWORD_noalias <- 'noalias' end_of_word +KEYWORD_null <- 'null' end_of_word +KEYWORD_or <- 'or' end_of_word +KEYWORD_orelse <- 'orelse' end_of_word +KEYWORD_packed <- 'packed' end_of_word +KEYWORD_promise <- 'promise' end_of_word +KEYWORD_pub <- 'pub' end_of_word +KEYWORD_resume <- 'resume' end_of_word +KEYWORD_return <- 'return' end_of_word +KEYWORD_linksection <- 'linksection' end_of_word +KEYWORD_stdcallcc <- 'stdcallcc' end_of_word +KEYWORD_struct <- 'struct' end_of_word +KEYWORD_suspend <- 'suspend' end_of_word +KEYWORD_switch <- 'switch' end_of_word +KEYWORD_test <- 'test' end_of_word +KEYWORD_true <- 'true' end_of_word +KEYWORD_try <- 'try' end_of_word +KEYWORD_undefined <- 'undefined' end_of_word +KEYWORD_union <- 'union' end_of_word +KEYWORD_unreachable <- 'unreachable' end_of_word +KEYWORD_use <- 'use' end_of_word +KEYWORD_var <- 'var' end_of_word +KEYWORD_volatile <- 'volatile' end_of_word +KEYWORD_while <- 'while' end_of_word + +keyword <- KEYWORD_align / KEYWORD_and / KEYWORD_anyerror / KEYWORD_asm + / KEYWORD_async / KEYWORD_await / KEYWORD_break / KEYWORD_cancel + / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue + / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer + / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false + / KEYWORD_fn / KEYWORD_for / KEYWORD_if / KEYWORD_inline + / KEYWORD_nakedcc / KEYWORD_noalias / KEYWORD_null / KEYWORD_or + / KEYWORD_orelse / KEYWORD_packed / KEYWORD_promise / KEYWORD_pub + / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection + / KEYWORD_stdcallcc / KEYWORD_struct / KEYWORD_suspend + / KEYWORD_switch / KEYWORD_test / KEYWORD_true / KEYWORD_try + / KEYWORD_undefined / KEYWORD_union / KEYWORD_unreachable + / KEYWORD_use / KEYWORD_var / KEYWORD_volatile / KEYWORD_while
    {#header_close#} {#header_open|Zen#}