diff --git a/doc/docgen.zig b/doc/docgen.zig index 0143de5b8b..2ee53bbb99 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -300,6 +300,7 @@ const Node = union(enum) { SeeAlso: []const SeeAlsoItem, Code: Code, Link: Link, + Syntax: Token, }; const Toc = struct { @@ -530,6 +531,17 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { }, }); tokenizer.code_node_count += 1; + } else if (mem.eql(u8, tag_name, "syntax")) { + _ = try eatToken(tokenizer, Token.Id.BracketClose); + const content_tok = try eatToken(tokenizer, Token.Id.Content); + _ = try eatToken(tokenizer, Token.Id.BracketOpen); + const end_syntax_tag = try eatToken(tokenizer, Token.Id.TagContent); + const end_tag_name = tokenizer.buffer[end_syntax_tag.start..end_syntax_tag.end]; + if (!mem.eql(u8, end_tag_name, "endsyntax")) { + 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 }); } else { return parseError(tokenizer, tag_token, "unrecognized tag name: {}", tag_name); } @@ -706,8 +718,10 @@ fn isType(name: []const u8) bool { return false; } -fn tokenizeAndPrint(allocator: *mem.Allocator, out: var, src: []const u8) !void { - try out.write("
");
+fn tokenizeAndPrint(allocator: *mem.Allocator, docgen_tokenizer: *Tokenizer, out: var, source_token: Token) !void {
+ const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end];
+ const src = mem.trim(u8, raw_src, " \n");
+ try out.write("");
var tokenizer = std.zig.Tokenizer.init(src);
var index: usize = 0;
var next_tok_is_fn = false;
@@ -900,12 +914,17 @@ fn tokenizeAndPrint(allocator: *mem.Allocator, out: var, src: []const u8) !void
std.zig.Token.Id.AngleBracketAngleBracketRightEqual,
std.zig.Token.Id.Tilde,
std.zig.Token.Id.BracketStarBracket,
- std.zig.Token.Id.Invalid,
=> try writeEscaped(out, src[token.start..token.end]),
+
+ std.zig.Token.Id.Invalid => return parseError(
+ docgen_tokenizer,
+ source_token,
+ "syntax error",
+ ),
}
index = token.end;
}
- try out.write("");
+ try out.write("");
}
fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void {
@@ -947,6 +966,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
}
try out.write("\n");
},
+ Node.Syntax => |content_tok| {
+ try tokenizeAndPrint(allocator, tokenizer, out, content_tok);
+ },
Node.Code => |code| {
code_progress_index += 1;
warn("docgen example code {}/{}...", code_progress_index, tokenizer.code_node_count);
@@ -956,7 +978,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
if (!code.is_inline) {
try out.print("{}.zig
", code.name); } - try tokenizeAndPrint(allocator, out, trimmed_raw_source); + try out.write("");
+ try tokenizeAndPrint(allocator, tokenizer, out, code.source_token);
+ try out.write("");
const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);
try io.writeFile(tmp_source_file_name, trimmed_raw_source);
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 3f2e741e36..4e39787ede 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -161,8 +161,8 @@ pub fn main() void {
}
{#code_end#}
- Note that we also left off the ! from the return type.
- In Zig, if your main function cannot fail, you must use the void return type.
+ Note that we also left off the {#syntax#}!{#endsyntax#} from the return type.
+ In Zig, if your main function cannot fail, you must use the {#syntax#}void{#endsyntax#} return type.
- There are no multiline comments in Zig (e.g. like /* */
+ There are no multiline comments in Zig (e.g. like /* */
comments in C). This helps allow Zig to have the property that each line
of code can be tokenized out of context.
A doc comment is one that begins with exactly three slashes (i.e.
- /// but not ////);
+ {#syntax#}///{#endsyntax#} but not {#syntax#}////{#endsyntax#});
multiple doc comments in a row are merged together to form a multiline
doc comment. The doc comment documents whatever immediately follows it.
i8int8_tint8_tu8uint8_tuint8_ti16int16_tint16_tu16uint16_tuint16_ti32int32_tint32_tu32uint32_tuint32_ti64int64_tint64_tu64uint64_tuint64_ti128__int128__int128u128unsigned __int128unsigned __int128isizeintptr_tintptr_tusizeuintptr_tuintptr_tc_shortshortshortc_ushortunsigned shortunsigned shortc_intintintc_uintunsigned intunsigned intc_longlonglongc_ulongunsigned longunsigned longc_longlonglong longlong longc_ulonglongunsigned long longunsigned long longc_longdoublelong doublelong doublec_voidvoidvoidf16floatfloatf32floatfloatf64doubledoublef128boolbooltrue or falseboolvoidnoreturnbreak, continue, return, unreachable, and while (true) {}typeerrorcomptime_intcomptime_float
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
- i7 refers to a signed 7-bit integer.
+ {#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer.
true and falsebool valuesnullnullundefined\n\n\r\r\t\t\\\\\'\'\"\"\xNN\xNN\uNNNN\uNNNN\UNNNNNN\UNNNNNNNote that the maximum valid Unicode point is 0x10ffff.
Note that the maximum valid Unicode point is {#syntax#}0x10ffff{#endsyntax#}.
{#header_close#} {#header_open|Multiline String Literals#}
Multiline string literals have no escapes and can span across multiple lines.
- To start a multiline string literal, use the \\ token. Just like a comment,
+ To start a multiline string literal, use the {#syntax#}\\{#endsyntax#} token. Just like a comment,
the string literal goes until the end of the line. The end of the line is
not included in the string literal.
- However, if the next line begins with \\ then a newline is appended and
+ However, if the next line begins with {#syntax#}\\{#endsyntax#} then a newline is appended and
the string literal continues.
- For a multiline C string literal, prepend c to each \\:
+ For a multiline C string literal, prepend c to each {#syntax#}\\{#endsyntax#}:
- In this example the variable c_string_literal has type [*]const char and
+ In this example the variable {#syntax#}c_string_literal{#endsyntax#} has type {#syntax#}[*]const char{#endsyntax#} and
has a terminating null byte.
Use the const keyword to assign a value to an identifier:
Use the {#syntax#}const{#endsyntax#} keyword to assign a value to an identifier:
{#code_begin|test_err|cannot assign to constant#} const x = 1234; @@ -610,8 +610,8 @@ test "assignment" { foo(); } {#code_end#} -const applies to all of the bytes that the identifier immediately addresses. {#link|Pointers#} have their own const-ness.
If you need a variable that you can modify, use the var keyword:
{#syntax#}const{#endsyntax#} applies to all of the bytes that the identifier immediately addresses. {#link|Pointers#} have their own const-ness.
+If you need a variable that you can modify, use the {#syntax#}var{#endsyntax#} keyword:
{#code_begin|test#} const assert = @import("std").debug.assert; @@ -632,7 +632,7 @@ test "initialization" { } {#code_end#} {#header_open|undefined#} -Use undefined to leave variables uninitialized:
Use {#syntax#}undefined{#endsyntax#} to leave variables uninitialized:
{#code_begin|test#} const assert = @import("std").debug.assert; @@ -643,14 +643,14 @@ test "init with undefined" { } {#code_end#}
- undefined can be {#link|implicitly cast|Implicit Casts#} to any type.
- Once this happens, it is no longer possible to detect that the value is undefined.
- undefined means the value could be anything, even something that is nonsense
- according to the type. Translated into English, undefined means "Not a meaningful
+ {#syntax#}undefined{#endsyntax#} can be {#link|implicitly cast|Implicit Casts#} to any type.
+ Once this happens, it is no longer possible to detect that the value is {#syntax#}undefined{#endsyntax#}.
+ {#syntax#}undefined{#endsyntax#} means the value could be anything, even something that is nonsense
+ according to the type. Translated into English, {#syntax#}undefined{#endsyntax#} means "Not a meaningful
value. Using this value would be a bug. The value will be unused, or overwritten before being used."
- In {#link|Debug#} mode, Zig writes 0xaa bytes to undefined memory. This is to catch
+ In {#link|Debug#} mode, Zig writes {#syntax#}0xaa{#endsyntax#} bytes to undefined memory. This is to catch
bugs early, and to help detect use of undefined memory in a debugger.
- In this function, values a and b are known only at runtime,
+ In this function, values {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} are known only at runtime,
and thus this division operation is vulnerable to both integer overflow and
division by zero.
- Operators such as + and - cause undefined behavior on
- integer overflow. Also available are operations such as +% and
- -% which are defined to have wrapping arithmetic on all targets.
+ Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on
+ integer overflow. Also available are operations such as {#syntax#}+%{#endsyntax#} and
+ {#syntax#}-%{#endsyntax#} which are defined to have wrapping arithmetic on all targets.
Zig has the following floating point types:
f16 - IEEE-754-2008 binary16f32 - IEEE-754-2008 binary32f64 - IEEE-754-2008 binary64f128 - IEEE-754-2008 binary128c_longdouble - matches long double for the target C ABIlong double for the target C ABI
- Float literals have type comptime_float which is guaranteed to hold at least all possible values
+ Float literals have type {#syntax#}comptime_float{#endsyntax#} which is guaranteed to hold at least all possible values
that the largest other floating point type can hold. Float literals {#link|implicitly cast|Implicit Casts#} to any other type.
By default floating point operations use Strict mode,
- but you can switch to Optimized mode on a per-block basis:
By default floating point operations use {#syntax#}Strict{#endsyntax#} mode, + but you can switch to {#syntax#}Optimized{#endsyntax#} mode on a per-block basis:
{#code_begin|obj|foo#} {#code_release_fast#} const builtin = @import("builtin"); @@ -772,8 +772,8 @@ pub fn main() void {a + b
-a += b{#syntax#}a + b
+a += b{#endsyntax#}2 + 5 == 7
+ {#syntax#}2 + 5 == 7{#endsyntax#}
a +% b
-a +%= b{#syntax#}a +% b
+a +%= b{#endsyntax#}u32(@maxValue(u32)) +% 1 == 0
+ {#syntax#}u32(@maxValue(u32)) +% 1 == 0{#endsyntax#}
a - b
-a -= b{#syntax#}a - b
+a -= b{#endsyntax#}2 - 5 == -3
+ {#syntax#}2 - 5 == -3{#endsyntax#}
a -% b
-a -%= b{#syntax#}a -% b
+a -%= b{#endsyntax#}u32(0) -% 1 == @maxValue(u32)
+ {#syntax#}u32(0) -% 1 == @maxValue(u32){#endsyntax#}
-a{#syntax#}-a{#endsyntax#}-1 == 0 - 1
+ {#syntax#}-1 == 0 - 1{#endsyntax#}
-%a{#syntax#}-%a{#endsyntax#}-%i32(@minValue(i32)) == @minValue(i32)
+ {#syntax#}-%i32(@minValue(i32)) == @minValue(i32){#endsyntax#}
a * b
-a *= b{#syntax#}a * b
+a *= b{#endsyntax#}2 * 5 == 10
+ {#syntax#}2 * 5 == 10{#endsyntax#}
a *% b
-a *%= b{#syntax#}a *% b
+a *%= b{#endsyntax#}u8(200) *% 2 == 144
+ {#syntax#}u8(200) *% 2 == 144{#endsyntax#}
a / b
-a /= b{#syntax#}a / b
+a /= b{#endsyntax#}/.
+ {#link|@divExact#} instead of {#syntax#}/{#endsyntax#}.
10 / 5 == 2
+ {#syntax#}10 / 5 == 2{#endsyntax#}
a % b
-a %= b{#syntax#}a % b
+a %= b{#endsyntax#}%.
+ {#link|@mod#} instead of {#syntax#}%{#endsyntax#}.
10 % 3 == 1
+ {#syntax#}10 % 3 == 1{#endsyntax#}
a << b
-a <<= b{#syntax#}a << b
+a <<= b{#endsyntax#}b must be {#link|comptime-known|comptime#} or have a type with log2 number of bits as a.1 << 8 == 256
+ {#syntax#}1 << 8 == 256{#endsyntax#}
a >> b
-a >>= b{#syntax#}a >> b
+a >>= b{#endsyntax#}b must be {#link|comptime-known|comptime#} or have a type with log2 number of bits as a.10 >> 1 == 5
+ {#syntax#}10 >> 1 == 5{#endsyntax#}
a & b
-a &= b{#syntax#}a & b
+a &= b{#endsyntax#}0b011 & 0b101 == 0b001
+ {#syntax#}0b011 & 0b101 == 0b001{#endsyntax#}
a | b
-a |= b{#syntax#}a | b
+a |= b{#endsyntax#}0b010 | 0b100 == 0b110
+ {#syntax#}0b010 | 0b100 == 0b110{#endsyntax#}
a ^ b
-a ^= b{#syntax#}a ^ b
+a ^= b{#endsyntax#}0b011 ^ 0b101 == 0b110
+ {#syntax#}0b011 ^ 0b101 == 0b110{#endsyntax#}
~a{#syntax#}~a{#endsyntax#}~u8(0b0101111) == 0b1010000
+ {#syntax#}~u8(0b0101111) == 0b1010000{#endsyntax#}
a orelse b{#syntax#}a orelse b{#endsyntax#}a is null,
- returns b ("default value"),
- otherwise returns the unwrapped value of a.
- Note that b may be a value of type {#link|noreturn#}.
+ const value: ?u32 = null;
+ {#syntax#}const value: ?u32 = null;
const unwrapped = value orelse 1234;
-unwrapped == 1234
+unwrapped == 1234{#endsyntax#}
a.?{#syntax#}a.?{#endsyntax#}a orelse unreachable
+ {#syntax#}a orelse unreachable{#endsyntax#}
const value: ?u32 = 5678;
-value.? == 5678
+ {#syntax#}const value: ?u32 = 5678;
+value.? == 5678{#endsyntax#}
a catch b
-a catch |err| b{#syntax#}a catch b
+a catch |err| b{#endsyntax#}a is an error,
- returns b ("default value"),
- otherwise returns the unwrapped value of a.
- Note that b may be a value of type {#link|noreturn#}.
- err is the error and is in scope of the expression b.
+ const value: error!u32 = error.Broken;
+ {#syntax#}const value: error!u32 = error.Broken;
const unwrapped = value catch 1234;
-unwrapped == 1234
+unwrapped == 1234{#endsyntax#}
a and b{#syntax#}a and b{#endsyntax#}a is false, returns false
- without evaluating b. Otherwise, returns b.
+ If {#syntax#}a{#endsyntax#} is {#syntax#}false{#endsyntax#}, returns {#syntax#}false{#endsyntax#}
+ without evaluating {#syntax#}b{#endsyntax#}. Otherwise, returns {#syntax#}b{#endsyntax#}.
false and true == false
+ {#syntax#}false and true == false{#endsyntax#}
a or b{#syntax#}a or b{#endsyntax#}a is true, returns true
- without evaluating b. Otherwise, returns b.
+ If {#syntax#}a{#endsyntax#} is {#syntax#}true{#endsyntax#}, returns {#syntax#}true{#endsyntax#}
+ without evaluating {#syntax#}b{#endsyntax#}. Otherwise, returns {#syntax#}b{#endsyntax#}.
false or true == true
+ {#syntax#}false or true == true{#endsyntax#}
!a{#syntax#}!a{#endsyntax#}!false == true
+ {#syntax#}!false == true{#endsyntax#}
a == b{#syntax#}a == b{#endsyntax#}true if a and b are equal, otherwise returns false.
+ Returns {#syntax#}true{#endsyntax#} if a and b are equal, otherwise returns {#syntax#}false{#endsyntax#}.
Invokes {#link|Peer Type Resolution#} for the operands.
(1 == 1) == true
+ {#syntax#}(1 == 1) == true{#endsyntax#}
a == null{#syntax#}a == null{#endsyntax#}true if a is null, otherwise returns false.
+ Returns {#syntax#}true{#endsyntax#} if a is {#syntax#}null{#endsyntax#}, otherwise returns {#syntax#}false{#endsyntax#}.
const value: ?u32 = null;
-value == null
+ {#syntax#}const value: ?u32 = null;
+value == null{#endsyntax#}
a != b{#syntax#}a != b{#endsyntax#}false if a and b are equal, otherwise returns true.
+ Returns {#syntax#}false{#endsyntax#} if a and b are equal, otherwise returns {#syntax#}true{#endsyntax#}.
Invokes {#link|Peer Type Resolution#} for the operands.
(1 != 1) == false
+ {#syntax#}(1 != 1) == false{#endsyntax#}
a > b{#syntax#}a > b{#endsyntax#}true if a is greater than b, otherwise returns false.
+ Returns {#syntax#}true{#endsyntax#} if a is greater than b, otherwise returns {#syntax#}false{#endsyntax#}.
Invokes {#link|Peer Type Resolution#} for the operands.
(2 > 1) == true
+ {#syntax#}(2 > 1) == true{#endsyntax#}
a >= b{#syntax#}a >= b{#endsyntax#}true if a is greater than or equal to b, otherwise returns false.
+ Returns {#syntax#}true{#endsyntax#} if a is greater than or equal to b, otherwise returns {#syntax#}false{#endsyntax#}.
Invokes {#link|Peer Type Resolution#} for the operands.
(2 >= 1) == true
+ {#syntax#}(2 >= 1) == true{#endsyntax#}
a < b{#syntax#}a < b{#endsyntax#}true if a is less than b, otherwise returns false.
+ Returns {#syntax#}true{#endsyntax#} if a is less than b, otherwise returns {#syntax#}false{#endsyntax#}.
Invokes {#link|Peer Type Resolution#} for the operands.
(1 < 2) == true
+ {#syntax#}(1 < 2) == true{#endsyntax#}>
a <= b{#syntax#}a <= b{#endsyntax#}true if a is less than or equal to b, otherwise returns false.
+ Returns {#syntax#}true{#endsyntax#} if a is less than or equal to b, otherwise returns {#syntax#}false{#endsyntax#}.
Invokes {#link|Peer Type Resolution#} for the operands.
(1 <= 2) == true
+ {#syntax#}(1 <= 2) == true{#endsyntax#}
a ++ b{#syntax#}a ++ b{#endsyntax#}a and b are {#link|compile-time known|comptime#}.
+ const mem = @import("std").mem;
+ {#syntax#}const mem = @import("std").mem;
const array1 = []u32{1,2};
const array2 = []u32{3,4};
const together = array1 ++ array2;
-mem.eql(u32, together, []u32{1,2,3,4})
+mem.eql(u32, together, []u32{1,2,3,4}){#endsyntax#}
a ** b{#syntax#}a ** b{#endsyntax#}a and b are {#link|compile-time known|comptime#}.
+ const mem = @import("std").mem;
+ {#syntax#}const mem = @import("std").mem;
const pattern = "ab" ** 3;
-mem.eql(u8, pattern, "ababab")
+mem.eql(u8, pattern, "ababab"){#endsyntax#}
a.*{#syntax#}a.*{#endsyntax#}const x: u32 = 1234;
-const ptr = &x;
-x.* == 1234
+ {#syntax#}const x: u32 = 1234;
+const ptr = &x;
+x.* == 1234{#endsyntax#}
&a{#syntax#}&a{#endsyntax#}const x: u32 = 1234;
-const ptr = &x;
-x.* == 1234
+ {#syntax#}const x: u32 = 1234;
+const ptr = &x;
+x.* == 1234{#endsyntax#}
a || b{#syntax#}a || b{#endsyntax#}const A = error{One};
+ {#syntax#}const A = error{One};
const B = error{Two};
-(A || B) == error{One, Two}
+(A || B) == error{One, Two}{#endsyntax#}
x() x[] x.y
+ {#syntax#}x() x[] x.y
a!b
-!x -x -%x ~x &x ?x
+!x -x -%x ~x &x ?x
x{} x.* x.?
! * / % ** *% ||
+ - ++ +% -%
-<< >>
-&
+<< >>
+&
^
|
-== != < > <= >=
+== != < > <= >=
and
or
orelse catch
-= *= /= %= += -= <<= >>= &= ^= |=
+= *= /= %= += -= <<= >>= &= ^= |={#endsyntax#}
{#header_close#}
{#header_close#}
{#header_open|Arrays#}
@@ -1641,7 +1641,7 @@ test "pointer child type" {
Alignment depends on the CPU architecture, but is always a power of two, and
- less than 1 << 29.
+ less than {#syntax#}1 << 29{#endsyntax#}.
In Zig, a pointer type has an alignment value. If the value is equal to the @@ -1661,8 +1661,8 @@ test "variable alignment" { } } {#code_end#} -
In the same way that a *i32 can be {#link|implicitly cast|Implicit Casts#} to a
- *const i32, a pointer with a larger alignment can be implicitly
+
In the same way that a {#syntax#}*i32{#endsyntax#} can be {#link|implicitly cast|Implicit Casts#} to a + {#syntax#}*const i32{#endsyntax#}, a pointer with a larger alignment can be implicitly cast to a pointer with a smaller alignment, but not vice versa.
@@ -1717,14 +1717,14 @@ fn foo(bytes: []u8) u32 { {#header_open|Type Based Alias Analysis#}
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 u8. Pointers to
- u8 can alias any memory.
+ not alias the same memory, with the exception of {#syntax#}u8{#endsyntax#}. Pointers to
+ {#syntax#}u8{#endsyntax#} can alias any memory.
As an example, this code produces undefined behavior:
-@ptrCast(*u32, f32(12.34)).*
+ {#syntax#}@ptrCast(*u32, f32(12.34)).*{#endsyntax#}
Instead, use {#link|@bitCast#}: -
@bitCast(u32, f32(12.34))
- As an added benefit, the @bitCast version works at compile-time.
{#syntax#}@bitCast(u32, f32(12.34)){#endsyntax#}
+ As an added benefit, the {#syntax#}@bitCast{#endsyntax#} version works at compile-time.
{#see_also|Slices|Memory#} {#header_close#} {#header_close#} @@ -1952,9 +1952,9 @@ test "linked list" {return expression, it gets named after
+ (anonymous struct at file.zig:7:38).
- For a C-ABI-compatible enum, use extern enum:
+ For a C-ABI-compatible enum, use {#syntax#}extern enum{#endsyntax#}:
By default, the size of enums is not guaranteed.
-packed enum causes the size of the enum to be the same as the size of the integer tag type
+
{#syntax#}packed enum{#endsyntax#} causes the size of the enum to be the same as the size of the integer tag type of the enum:
{#code_begin|test#} const std = @import("std"); @@ -2246,7 +2246,7 @@ test "access variable after block scope" { x += 1; } {#code_end#} -Blocks are expressions. When labeled, break can be used
+
Blocks are expressions. When labeled, {#syntax#}break{#endsyntax#} can be used to return a value from the block:
{#code_begin|test#} @@ -2264,7 +2264,7 @@ test "labeled break from labeled block expression" { assert(y == 124); } {#code_end#} -Here, blk can be any name.
Here, {#syntax#}blk{#endsyntax#} can be any name.
{#see_also|Labeled while|Labeled for#} {#header_close#} {#header_open|switch#} @@ -2380,7 +2380,7 @@ test "while basic" { } {#code_end#}
- Use break to exit a while loop early.
+ Use {#syntax#}break{#endsyntax#} to exit a while loop early.
- Use continue to jump back to the beginning of the loop.
+ Use {#syntax#}continue{#endsyntax#} to jump back to the beginning of the loop.
While loops support a continue expression which is executed when the loop
- is continued. The continue keyword respects this expression.
+ is continued. The {#syntax#}continue{#endsyntax#} keyword respects this expression.
While loops are expressions. The result of the expression is the
- result of the else clause of a while loop, which is executed when
+ result of the {#syntax#}else{#endsyntax#} clause of a while loop, which is executed when
the condition of the while loop is tested as false.
- break, like return, accepts a value
- parameter. This is the result of the while expression.
- When you break from a while loop, the else branch is not
+ {#syntax#}break{#endsyntax#}, like {#syntax#}return{#endsyntax#}, accepts a value
+ parameter. This is the result of the {#syntax#}while{#endsyntax#} expression.
+ When you {#syntax#}break{#endsyntax#} from a while loop, the {#syntax#}else{#endsyntax#} branch is not
evaluated.
When a while loop is labeled, it can be referenced from a break
- or continue from within a nested loop:
When a {#syntax#}while{#endsyntax#} loop is labeled, it can be referenced from a {#syntax#}break{#endsyntax#} + or {#syntax#}continue{#endsyntax#} from within a nested loop:
{#code_begin|test#} test "nested break" { outer: while (true) { @@ -2491,11 +2491,11 @@ test "nested continue" { exits.
- When the |x| syntax is present on a while expression,
+ When the {#syntax#}|x|{#endsyntax#} syntax is present on a {#syntax#}while{#endsyntax#} expression,
the while condition must have an {#link|Optional Type#}.
- The else branch is allowed on optional iteration. In this case, it will
+ The {#syntax#}else{#endsyntax#} branch is allowed on optional iteration. In this case, it will
be executed on the first null value encountered.
- When the else |x| syntax is present on a while expression,
+ When the {#syntax#}else |x|{#endsyntax#} syntax is present on a {#syntax#}while{#endsyntax#} expression,
the while condition must have an {#link|Error Union Type#}.
- It is recommended to use inline loops only for one of these reasons:
+ It is recommended to use {#syntax#}inline{#endsyntax#} loops only for one of these reasons:
When a for loop is labeled, it can be referenced from a break
- or continue from within a nested loop:
When a {#syntax#}for{#endsyntax#} loop is labeled, it can be referenced from a {#syntax#}break{#endsyntax#} + or {#syntax#}continue{#endsyntax#} from within a nested loop:
{#code_begin|test#} const std = @import("std"); const assert = std.debug.assert; @@ -2732,7 +2732,7 @@ fn typeNameLength(comptime T: type) usize { } {#code_end#}
- It is recommended to use inline loops only for one of these reasons:
+ It is recommended to use {#syntax#}inline{#endsyntax#} loops only for one of these reasons:
- In Debug and ReleaseSafe mode, and when using zig test,
- unreachable emits a call to panic with the message reached unreachable code.
+ In {#syntax#}Debug{#endsyntax#} and {#syntax#}ReleaseSafe{#endsyntax#} mode, and when using zig test,
+ {#syntax#}unreachable{#endsyntax#} emits a call to {#syntax#}panic{#endsyntax#} with the message reached unreachable code.
- In ReleaseFast mode, the optimizer uses the assumption that unreachable code
- will never be hit to perform optimizations. However, zig test even in ReleaseFast mode
- still emits unreachable as calls to panic.
+ In {#syntax#}ReleaseFast{#endsyntax#} mode, the optimizer uses the assumption that {#syntax#}unreachable{#endsyntax#} code
+ will never be hit to perform optimizations. However, zig test even in {#syntax#}ReleaseFast{#endsyntax#} mode
+ still emits {#syntax#}unreachable{#endsyntax#} as calls to {#syntax#}panic{#endsyntax#}.
- noreturn is the type of:
+ {#syntax#}noreturn{#endsyntax#} is the type of:
breakcontinuereturnunreachablewhile (true) {}When resolving types together, such as if clauses or switch prongs,
- the noreturn type is compatible with every other type. Consider:
+
When resolving types together, such as {#syntax#}if{#endsyntax#} clauses or {#syntax#}switch{#endsyntax#} prongs, + the {#syntax#}noreturn{#endsyntax#} type is compatible with every other type. Consider:
{#code_begin|test#} fn foo(condition: bool, b: u32) void { @@ -3005,7 +3005,7 @@ test "noreturn" { foo(false, 1); } {#code_end#} -Another use case for noreturn is the exit function:
Another use case for {#syntax#}noreturn{#endsyntax#} is the {#syntax#}exit{#endsyntax#} function:
{#code_begin|test#} {#target_windows#} pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: c_uint) noreturn; @@ -3134,7 +3134,7 @@ test "fn reflection" {
The number of unique error values across the entire compilation should determine the size of the error set type.
- However right now it is hard coded to be a u16. See #768.
+ However right now it is hard coded to be a {#syntax#}u16{#endsyntax#}. See #768.
You can {#link|implicitly cast|Implicit Casts#} an error from a subset to its superset: @@ -3197,7 +3197,7 @@ const err = (error {FileNotFound}).FileNotFound; This becomes useful when using {#link|Inferred Error Sets#}.
{#header_open|The Global Error Set#} -error 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.
@@ -3216,7 +3216,7 @@ const err = (error {FileNotFound}).FileNotFound; {#header_close#} {#header_open|Error Union Type#}
- An error set type and normal type can be combined with the !
+ An error set type and normal type can be combined with the {#syntax#}!{#endsyntax#}
binary operator to form an error union type. You are likely to use an
error union type more often than an error set type by itself.
- Notice the return type is !u64. This means that the function
+ Notice the return type is {#syntax#}!u64{#endsyntax#}. This means that the function
either returns an unsigned 64 bit integer, or an error. We left off the error set
- to the left of the !, so the error set is inferred.
+ to the left of the {#syntax#}!{#endsyntax#}, so the error set is inferred.
Within the function definition, you can see some return statements that return
- an error, and at the bottom a return statement that returns a u64.
- Both types {#link|implicitly cast|Implicit Casts#} to error!u64.
+ 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#}.
What it looks like to use this function varies depending on what you're @@ -3283,7 +3283,7 @@ test "parse u64" {
If you want to provide a default value, you can use the catch binary operator:
If you want to provide a default value, you can use the {#syntax#}catch{#endsyntax#} binary operator:
{#code_begin|syntax#} fn doAThing(str: []u8) void { const number = parseU64(str, 10) catch 13; @@ -3291,9 +3291,9 @@ fn doAThing(str: []u8) void { } {#code_end#}
- In this code, number will be equal to the successfully parsed string, or
- a default value of 13. The type of the right hand side of the binary catch operator must
- match the unwrapped error union type, or be of type noreturn.
+ In this code, {#syntax#}number{#endsyntax#} will be equal to the successfully parsed string, or
+ a default value of 13. The type of the right hand side of the binary {#syntax#}catch{#endsyntax#} operator must
+ match the unwrapped error union type, or be of type {#syntax#}noreturn{#endsyntax#}.
- There is a shortcut for this. The try expression:
+ There is a shortcut for this. The {#syntax#}try{#endsyntax#} expression:
- try evaluates an error union expression. If it is an error, it returns
+ {#syntax#}try{#endsyntax#} evaluates an error union expression. If it is an error, it returns
from the current function with the same error. Otherwise, the expression results in
the unwrapped value.
Here we know for sure that "1234" will parse successfully. So we put the
- unreachable value on the right hand side. unreachable generates
+ {#syntax#}unreachable{#endsyntax#} value on the right hand side. {#syntax#}unreachable{#endsyntax#} generates
a panic in Debug and ReleaseSafe modes and undefined behavior in ReleaseFast mode. So, while we're debugging the
application, if there was a surprise error here, the application would crash
appropriately.
@@ -3352,7 +3352,7 @@ fn doAThing(str: []u8) void {
{#header_open|errdefer#}
The other component to error handling is defer statements.
- In addition to an unconditional {#link|defer#}, Zig has errdefer,
+ In addition to an unconditional {#link|defer#}, Zig has {#syntax#}errdefer{#endsyntax#},
which evaluates the deferred expression on block exit path if and only if
the function returned with an error from the block.
catch unreachable and
+ to ignore the error, you can add {#syntax#}catch unreachable{#endsyntax#} and
get the added benefit of crashing in Debug and ReleaseSafe modes if your assumption was wrong.
An error union is created with the ! binary operator.
+
An error union is created with the {#syntax#}!{#endsyntax#} binary operator. You can use compile-time reflection to access the child type of an error union:
{#code_begin|test#} const assert = @import("std").debug.assert; @@ -3424,15 +3424,15 @@ test "error union" { {#code_end#} {#header_open|Merging Error Sets#}
- Use the || operator to merge two error sets together. The resulting
+ Use the {#syntax#}||{#endsyntax#} operator to merge two error sets together. The resulting
error set contains the errors of both error sets. Doc comments from the left-hand
side override doc comments from the right-hand side. In this example, the doc
- comments for C.PathNotFound is A doc comment.
+ comments for {#syntax#}C.PathNotFound{#endsyntax#} is A doc comment.
This is especially useful for functions which return different error sets depending
on {#link|comptime#} branches. For example, the Zig standard library uses
- LinuxFileOpenError || WindowsFileOpenError for the error set of opening
+ {#syntax#}LinuxFileOpenError || WindowsFileOpenError{#endsyntax#} for the error set of opening
files.
- You can see that the final error bubbled up was PermissionDenied,
- but the original error that started this whole thing was FileNotFound. In the bar function, the code handles the original error code,
+ You can see that the final error bubbled up was {#syntax#}PermissionDenied{#endsyntax#},
+ but the original error that started this whole thing was {#syntax#}FileNotFound{#endsyntax#}. In the {#syntax#}bar{#endsyntax#} function, the code handles the original error code,
and then returns another one, from the switch statement. Error Return Traces make this clear, whereas a stack trace would look like this:
Here, the stack trace does not explain how the control
- flow in bar got to the hello() call.
+ flow in {#syntax#}bar{#endsyntax#} got to the {#syntax#}hello(){#endsyntax#} call.
One would have to open a debugger or further instrument the application
in order to find out. The error return trace, on the other hand,
shows exactly how the error bubbled up.
@@ -3631,8 +3631,8 @@ fn bang2() void {
catch unreachable and you have not overridden the default panic handlerstd.debug.dumpStackTrace to print it. This function returns comptime-known {#link|null#} when building without error return tracing support.@@ -3643,7 +3643,7 @@ fn bang2() void {
- 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 void calls a function returning error.
+ 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:
- A pointer to StackTrace is passed as a secret parameter to every function that can return an error, but it's always the first parameter, so it can likely sit in a register and stay there.
+ A pointer to {#syntax#}StackTrace{#endsyntax#} is passed as a secret parameter to every function that can return an error, but it's always the first parameter, so it can likely sit in a register and stay there.
That's it for the path when no errors occur. It's practically free in terms of performance.
- When generating the code for a function that returns an error, just before the return statement (only for the return statements that return errors), Zig generates a call to this function:
+ When generating the code for a function that returns an error, just before the {#syntax#}return{#endsyntax#} statement (only for the {#syntax#}return{#endsyntax#} statements that return errors), Zig generates a call to this function:
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
- __zig_return_error 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.
- Now the variable optional_int could be an i32, or null.
+ Now the variable {#syntax#}optional_int{#endsyntax#} could be an {#syntax#}i32{#endsyntax#}, or {#syntax#}null{#endsyntax#}.
Instead of integers, let's talk about pointers. Null references are the source of many runtime @@ -3740,8 +3740,8 @@ fn doAThing() ?*Foo { {#code_end#}
Here, Zig is at least as convenient, if not more, than C. And, the type of "ptr"
- is *u8 not ?*u8. The orelse keyword
- unwrapped the optional type and therefore ptr is guaranteed to be non-null everywhere
+ is {#syntax#}*u8{#endsyntax#} not {#syntax#}?*u8{#endsyntax#}. The {#syntax#}orelse{#endsyntax#} keyword
+ unwrapped the optional type and therefore {#syntax#}ptr{#endsyntax#} is guaranteed to be non-null everywhere
it is used in the function.
@@ -3772,7 +3772,7 @@ fn doAThing(optional_foo: ?*Foo) void { {#code_end#}
Once again, the notable thing here is that inside the if block,
- foo is no longer an optional pointer, it is a pointer, which
+ {#syntax#}foo{#endsyntax#} is no longer an optional pointer, it is a pointer, which
cannot be null.
@@ -3783,7 +3783,7 @@ fn doAThing(optional_foo: ?*Foo) void { cannot be null.
{#header_open|Optional Type#} -An optional is created by putting ? in front of a type. You can use compile-time
+
An optional is created by putting {#syntax#}?{#endsyntax#} in front of a type. You can use compile-time reflection to access the child type of an optional:
{#code_begin|test#} const assert = @import("std").debug.assert; @@ -3802,7 +3802,7 @@ test "optional type" { {#header_close#} {#header_open|null#}
- Just like {#link|undefined#}, null has its own type, and the only way to use it is to
+ Just like {#link|undefined#}, {#syntax#}null{#endsyntax#} has its own type, and the only way to use it is to
cast it to a different type:
const - non-const to const is allowedvolatile - non-volatile to volatile is allowedalign - bigger to smaller alignment is allowed @@ -4100,7 +4100,7 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) error![]u8 { {#header_open|void#}
- void represents a type that has no value. Code that makes use of void values is
+ {#syntax#}void{#endsyntax#} represents a type that has no value. Code that makes use of void values is
not included in the final generated code:
When this turns into LLVM IR, there is no code generated in the body of entry,
+
When this turns into LLVM IR, there is no code generated in the body of {#syntax#}entry{#endsyntax#}, even in debug mode. For example, on x86_64:
0000000000000010 <entry>:
10: 55 push %rbp
@@ -4120,9 +4120,9 @@ export fn entry() void {
These assembly instructions do not have any code associated with the void values -
they only perform the function call prologue and epilog.
- void can be useful for instantiating generic types. For example, given a
- Map(Key, Value), one can pass void for the Value
- type to make it into a Set:
+ {#syntax#}void{#endsyntax#} can be useful for instantiating generic types. For example, given a
+ {#syntax#}Map(Key, Value){#endsyntax#}, one can pass {#syntax#}void{#endsyntax#} for the {#syntax#}Value{#endsyntax#}
+ type to make it into a {#syntax#}Set{#endsyntax#}:
{#code_begin|test#}
const std = @import("std");
@@ -4151,17 +4151,17 @@ fn eql_i32(a: i32, b: i32) bool {
}
{#code_end#}
Note that this is different than using a dummy value for the hash map value.
- By using void as the type of the value, the hash map entry type has no value field, and
+ By using {#syntax#}void{#endsyntax#} as the type of the value, the hash map entry type has no value field, and
thus the hash map takes up less space. Further, all the code that deals with storing and loading the
value is deleted, as seen above.
- void is distinct from c_void, which is defined like this:
- pub const c_void = @OpaqueType();.
- void has a known size of 0 bytes, and c_void has an unknown, but non-zero, size.
+ {#syntax#}void{#endsyntax#} is distinct from {#syntax#}c_void{#endsyntax#}, which is defined like this:
+ {#syntax#}pub const c_void = @OpaqueType();{#endsyntax#}.
+ {#syntax#}void{#endsyntax#} has a known size of 0 bytes, and {#syntax#}c_void{#endsyntax#} has an unknown, but non-zero, size.
- Expressions of type void are the only ones whose value can be ignored. For example:
+ Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example:
{#code_begin|test_err|expression value is ignored#}
test "ignoring expression value" {
@@ -4172,7 +4172,7 @@ fn foo() i32 {
return 1234;
}
{#code_end#}
- However, if the expression has type void:
+ However, if the expression has type {#syntax#}void{#endsyntax#}:
{#code_begin|test#}
test "ignoring expression value" {
foo();
@@ -4207,10 +4207,10 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {
In Zig, types are first-class citizens. They can be assigned to variables, passed as parameters to functions,
and returned from functions. However, they can only be used in expressions which are known at compile-time,
- which is why the parameter T in the above snippet must be marked with comptime.
+ which is why the parameter {#syntax#}T{#endsyntax#} in the above snippet must be marked with {#syntax#}comptime{#endsyntax#}.
- A comptime parameter means that:
+ A {#syntax#}comptime{#endsyntax#} parameter means that:
- At the callsite, the value must be known at compile-time, or it is a compile error.
@@ -4255,7 +4255,7 @@ test "try to compare bools" {
}
{#code_end#}
- On the flip side, inside the function definition with the comptime parameter, the
+ On the flip side, inside the function definition with the {#syntax#}comptime{#endsyntax#} parameter, the
value is known at compile-time. This means that we actually could make this work for the bool type
if we wanted to:
@@ -4274,12 +4274,12 @@ test "try to compare bools" {
}
{#code_end#}
- This works because Zig implicitly inlines if expressions when the condition
+ This works because Zig implicitly inlines {#syntax#}if{#endsyntax#} expressions when the condition
is known at compile-time, and the compiler guarantees that it will skip analysis of
the branch not taken.
- This means that the actual function generated for max in this situation looks like
+ This means that the actual function generated for {#syntax#}max{#endsyntax#} in this situation looks like
this:
{#code_begin|syntax#}
@@ -4292,18 +4292,18 @@ fn max(a: bool, b: bool) bool {
the necessary run-time code to accomplish the task.
- This works the same way for switch expressions - they are implicitly inlined
+ This works the same way for {#syntax#}switch{#endsyntax#} expressions - they are implicitly inlined
when the target expression is compile-time known.
{#header_close#}
{#header_open|Compile-Time Variables#}
- In Zig, the programmer can label variables as comptime. This guarantees to the compiler
+ In Zig, the programmer can label variables as {#syntax#}comptime{#endsyntax#}. 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
compile error.
- This combined with the fact that we can inline loops allows us to write
+ This combined with the fact that we can {#syntax#}inline{#endsyntax#} loops allows us to write
a function which is partially evaluated at compile-time and partially at run-time.
@@ -4346,8 +4346,8 @@ test "perform fn" {
This example is a bit contrived, because the compile-time evaluation component is unnecessary;
this code would work fine if it was all done at run-time. But it does end up generating
- different code. In this example, the function performFn is generated three different times,
- for the different values of prefix_char provided:
+ different code. In this example, the function {#syntax#}performFn{#endsyntax#} is generated three different times,
+ for the different values of {#syntax#}prefix_char{#endsyntax#} provided:
{#code_begin|syntax#}
// From the line:
@@ -4388,7 +4388,7 @@ fn performFn(start_value: i32) i32 {
{#header_open|Compile-Time Expressions#}
In Zig, it matters whether a given expression is known at compile-time or run-time. A programmer can
- use a comptime expression to guarantee that the expression will be evaluated at compile-time.
+ use a {#syntax#}comptime{#endsyntax#} expression to guarantee that the expression will be evaluated at compile-time.
If this cannot be accomplished, the compiler will emit an error. For example:
{#code_begin|test_err|unable to evaluate constant expression#}
@@ -4401,16 +4401,16 @@ test "foo" {
}
{#code_end#}
- It doesn't make sense that a program could call exit() (or any other external function)
- at compile-time, so this is a compile error. However, a comptime expression does much
+ It doesn't make sense that a program could call {#syntax#}exit(){#endsyntax#} (or any other external function)
+ at compile-time, so this is a compile error. However, a {#syntax#}comptime{#endsyntax#} expression does much
more than sometimes cause a compile error.
- Within a comptime expression:
+ Within a {#syntax#}comptime{#endsyntax#} expression:
- - All variables are
comptime variables.
- - All
if, while, for, and switch
+ - All variables are {#syntax#}comptime{#endsyntax#} variables.
+ - All {#syntax#}if{#endsyntax#}, {#syntax#}while{#endsyntax#}, {#syntax#}for{#endsyntax#}, and {#syntax#}switch{#endsyntax#}
expressions are evaluated at compile-time, or emit a compile error if this is not possible.
- All function calls cause the compiler to interpret the function at compile-time, emitting a
compile error if the function tries to do something that has global run-time side effects.
@@ -4487,7 +4487,7 @@ test "fibonacci" {
{#link|@setEvalBranchQuota#} to change the default number 1000 to something else.
- What if we fix the base case, but put the wrong value in the assert line?
+ What if we fix the base case, but put the wrong value in the {#syntax#}assert{#endsyntax#} line?
{#code_begin|test_err|encountered @panic at compile-time#}
const assert = @import("std").debug.assert;
@@ -4504,16 +4504,16 @@ test "fibonacci" {
}
{#code_end#}
- What happened is Zig started interpreting the assert function with the
- parameter ok set to false. When the interpreter hit
- unreachable it emitted a compile error, because reaching unreachable
+ What happened is Zig started interpreting the {#syntax#}assert{#endsyntax#} function with the
+ parameter {#syntax#}ok{#endsyntax#} set to {#syntax#}false{#endsyntax#}. When the interpreter hit
+ {#syntax#}unreachable{#endsyntax#} it emitted a compile error, because reaching unreachable
code is undefined behavior, and undefined behavior causes a compile error if it is detected
at compile-time.
In the global scope (outside of any function), all expressions are implicitly
- comptime expressions. This means that we can use functions to
+ {#syntax#}comptime{#endsyntax#} expressions. This means that we can use functions to
initialize complex static data. For example:
{#code_begin|test#}
@@ -4561,7 +4561,7 @@ test "variable values" {
@1 = internal unnamed_addr constant i32 1060
Note that we did not have to do anything special with the syntax of these functions. For example,
- we could call the sum function as is with a slice of numbers whose length and values were
+ we could call the {#syntax#}sum{#endsyntax#} function as is with a slice of numbers whose length and values were
only known at run-time.
- Here is an example of a generic List data structure, that we will instantiate with
- the type i32. In Zig we refer to the type as List(i32).
+ Here is an example of a generic {#syntax#}List{#endsyntax#} data structure, that we will instantiate with
+ the type {#syntax#}i32{#endsyntax#}. In Zig we refer to the type as {#syntax#}List(i32){#endsyntax#}.
- That's it. It's a function that returns an anonymous struct. For the purposes of error messages
- and debugging, Zig infers the name "List(i32)" from the function name and parameters invoked when creating
+ That's it. It's a function that returns an anonymous {#syntax#}struct{#endsyntax#}. For the purposes of error messages
+ and debugging, Zig infers the name {#syntax#}"List(i32)"{#endsyntax#} from the function name and parameters invoked when creating
the anonymous struct.
@@ -4602,13 +4602,13 @@ const Node = struct {
This works because all top level declarations are order-independent, and as long as there isn't
an actual infinite regression, values can refer to themselves, directly or indirectly. In this case,
- Node refers to itself as a pointer, which is not actually an infinite regression, so
+ {#syntax#}Node{#endsyntax#} refers to itself as a pointer, which is not actually an infinite regression, so
it works fine.
- Putting all of this together, let's see how printf works in Zig.
+ Putting all of this together, let's see how {#syntax#}printf{#endsyntax#} works in Zig.
- printValue is a function that takes a parameter of any type, and does different things depending
+ {#syntax#}printValue{#endsyntax#} is a function that takes a parameter of any type, and does different things depending
on the type:
- And now, what happens if we give too many arguments to printf?
+ And now, what happens if we give too many arguments to {#syntax#}printf{#endsyntax#}?
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 []const u8:
+ only that it is a compile-time known value that is implicitly castable to a {#syntax#}[]const u8{#endsyntax#}:
- Declare a coroutine with the async keyword.
+ Declare a coroutine with the {#syntax#}async{#endsyntax#} keyword.
The expression in angle brackets must evaluate to a struct
which has these fields:
allocFn: fn (self: *Allocator, byte_count: usize, alignment: u29) Error![]u8 - where Error can be any error set.freeFn: fn (self: *Allocator, old_mem: []u8) void
- You may notice that this corresponds to the std.mem.Allocator interface.
+ You may notice that this corresponds to the {#syntax#}std.mem.Allocator{#endsyntax#} interface.
This makes it convenient to integrate with existing allocators. Note, however,
that the language feature does not depend on the standard library, and any struct which
has these fields is allowed.
@@ -4816,13 +4816,13 @@ pub fn main() void {
the function generic. Zig will infer the allocator type when the async function is called.
- Call a coroutine with the async keyword. Here, the expression in angle brackets
+ Call a coroutine with the {#syntax#}async{#endsyntax#} keyword. Here, the expression in angle brackets
is a pointer to the allocator struct that the coroutine expects.
- The result of an async function call is a promise->T type, where T
+ The result of an async function call is a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#}
is the return type of the async function. Once a promise has been created, it must be
- consumed, either with cancel or await:
+ consumed, either with {#syntax#}cancel{#endsyntax#} or {#syntax#}await{#endsyntax#}:
Async functions start executing when created, so in the following example, the entire @@ -4911,18 +4911,18 @@ async fn testSuspendBlock() void { {#code_end#}
Every suspend point in an async function represents a point at which the coroutine
- could be destroyed. If that happens, defer expressions that are in
- scope are run, as well as errdefer expressions.
+ could be destroyed. If that happens, {#syntax#}defer{#endsyntax#} expressions that are in
+ scope are run, as well as {#syntax#}errdefer{#endsyntax#} expressions.
{#link|Await#} counts as a suspend point.
{#header_open|Resuming from Suspend Blocks#}
- Upon entering a suspend block, the coroutine is already considered
+ Upon entering a {#syntax#}suspend{#endsyntax#} block, the coroutine is already considered
suspended, and can be resumed. For example, if you started another kernel thread,
- and had that thread call resume on the promise handle provided by the
- suspend block, the new thread would begin executing after the suspend
+ and had that thread call {#syntax#}resume{#endsyntax#} on the promise handle provided by the
+ {#syntax#}suspend{#endsyntax#} block, the new thread would begin executing after the suspend
block, while the old thread continued executing the suspend block.
@@ -4957,26 +4957,26 @@ async fn testResumeFromSuspend(my_result: *i32) void { {#header_close#} {#header_open|Await#}
- The await keyword is used to coordinate with an async function's
- return statement.
+ The {#syntax#}await{#endsyntax#} keyword is used to coordinate with an async function's
+ {#syntax#}return{#endsyntax#} statement.
- await is valid only in an async function, and it takes
+ {#syntax#}await{#endsyntax#} is valid only in an {#syntax#}async{#endsyntax#} function, and it takes
as an operand a promise handle.
If the async function associated with the promise handle has already returned,
- then await destroys the target async function, and gives the return value.
- Otherwise, await suspends the current async function, registering its
+ then {#syntax#}await{#endsyntax#} destroys the target async function, and gives the return value.
+ Otherwise, {#syntax#}await{#endsyntax#} suspends the current async function, registering its
promise handle with the target coroutine. It becomes the target coroutine's responsibility
to have ensured that it will be resumed or destroyed. When the target coroutine reaches
its return statement, it gives the return value to the awaiter, destroys itself, and then
resumes the awaiter.
- A promise handle must be consumed exactly once after it is created, either by cancel or await.
+ A promise handle must be consumed exactly once after it is created, either by {#syntax#}cancel{#endsyntax#} or {#syntax#}await{#endsyntax#}.
- await counts as a suspend point, and therefore at every await,
- a coroutine can be potentially destroyed, which would run defer and errdefer expressions.
+ {#syntax#}await{#endsyntax#} counts as a suspend point, and therefore at every {#syntax#}await{#endsyntax#},
+ a coroutine can be potentially destroyed, which would run {#syntax#}defer{#endsyntax#} and {#syntax#}errdefer{#endsyntax#} expressions.
- In general, suspend is lower level than await. Most application
- code will use only async and await, but event loop
- implementations will make use of suspend internally.
+ In general, {#syntax#}suspend{#endsyntax#} is lower level than {#syntax#}await{#endsyntax#}. Most application
+ code will use only {#syntax#}async{#endsyntax#} and {#syntax#}await{#endsyntax#}, but event loop
+ implementations will make use of {#syntax#}suspend{#endsyntax#} internally.
Builtin functions are provided by the compiler and are prefixed with @.
- The comptime keyword on a parameter means that the parameter must be known
+ The {#syntax#}comptime{#endsyntax#} keyword on a parameter means that the parameter must be known
at compile time.
@addWithOverflow(comptime T: type, a: T, b: T, result: *T) bool
+ {#syntax#}@addWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}
- Performs result.* = a + b. If overflow or underflow occurs,
- stores the overflowed bits in result and returns true.
- If no overflow or underflow occurs, returns false.
+ Performs {#syntax#}result.* = a + b{#endsyntax#}. If overflow or underflow occurs,
+ stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
+ If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
@ArgType(comptime T: type, comptime n: usize) type
+ {#syntax#}@ArgType(comptime T: type, comptime n: usize) type{#endsyntax#}
- This builtin function takes a function type and returns the type of the parameter at index n.
+ This builtin function takes a function type and returns the type of the parameter at index {#syntax#}n{#endsyntax#}.
- T must be a function type.
+ {#syntax#}T{#endsyntax#} must be a function type.
Note: This function is deprecated. Use {#link|@typeInfo#} instead.
{#header_close#} {#header_open|@atomicLoad#} -@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T
+ {#syntax#}@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}
This builtin function atomically dereferences a pointer and returns the value.
- T must be a pointer type, a bool,
+ {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#},
or an integer whose bit count meets these requirements:
@atomicRmw(comptime T: type, ptr: *T, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T
+ {#syntax#}@atomicRmw(comptime T: type, ptr: *T, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}
This builtin function atomically modifies memory and then returns the previous value.
- T must be a pointer type, a bool,
+ {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#},
or an integer whose bit count meets these requirements:
@bitCast(comptime DestType: type, value: var) DestType
+ {#syntax#}@bitCast(comptime DestType: type, value: var) DestType{#endsyntax#}
Converts a value of one type to another type.
- Asserts that @sizeOf(@typeOf(value)) == @sizeOf(DestType).
+ Asserts that {#syntax#}@sizeOf(@typeOf(value)) == @sizeOf(DestType){#endsyntax#}.
- Asserts that @typeId(DestType) != @import("builtin").TypeId.Pointer. Use @ptrCast or @intToPtr if you need this.
+ Asserts that {#syntax#}@typeId(DestType) != @import("builtin").TypeId.Pointer{#endsyntax#}. Use {#syntax#}@ptrCast{#endsyntax#} or {#syntax#}@intToPtr{#endsyntax#} if you need this.
Can be used for these things for example:
f32 to u32 bitsi32 to u32 preserving twos complement
- Works at compile-time if value 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.
+ Works at compile-time if {#syntax#}value{#endsyntax#} 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.
@breakpoint()
+ {#syntax#}@breakpoint(){#endsyntax#}
This function inserts a platform-specific debug trap instruction which causes debuggers to break there. @@ -5147,10 +5147,10 @@ fn seq(c: u8) void { {#header_close#} {#header_open|@alignCast#} -
@alignCast(comptime alignment: u29, ptr: var) var
+ {#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}
- ptr can be *T, fn(), ?*T,
- ?fn(), or []T. It returns the same type as ptr
+ {#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}fn(){#endsyntax#}, {#syntax#}?*T{#endsyntax#},
+ {#syntax#}?fn(){#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. It returns the same type as {#syntax#}ptr{#endsyntax#}
except with the alignment adjusted to the new value.
A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added @@ -5158,16 +5158,16 @@ fn seq(c: u8) void { {#header_close#} {#header_open|@alignOf#} -
@alignOf(comptime T: type) comptime_int
+ {#syntax#}@alignOf(comptime T: type) comptime_int{#endsyntax#}
This function returns the number of bytes that this type should be aligned to for the current target to match the C ABI. When the child type of a pointer has this alignment, the alignment can be omitted from the type.
-const assert = @import("std").debug.assert;
+ {#syntax#}const assert = @import("std").debug.assert;
comptime {
assert(*u32 == *align(@alignOf(u32)) u32);
-}
+}{#endsyntax#}
The result is a target-specific compile time constant. It is guaranteed to be less than or equal to {#link|@sizeOf(T)|@sizeOf#}. @@ -5176,21 +5176,21 @@ comptime { {#header_close#} {#header_open|@boolToInt#} -
@boolToInt(value: bool) u1
+ {#syntax#}@boolToInt(value: bool) u1{#endsyntax#}
- Converts true to u1(1) and false to
- u1(0).
+ Converts {#syntax#}true{#endsyntax#} to {#syntax#}u1(1){#endsyntax#} and {#syntax#}false{#endsyntax#} to
+ {#syntax#}u1(0){#endsyntax#}.
- If the value is known at compile-time, the return type is comptime_int
- instead of u1.
+ If the value is known at compile-time, the return type is {#syntax#}comptime_int{#endsyntax#}
+ instead of {#syntax#}u1{#endsyntax#}.
@bytesToSlice(comptime Element: type, bytes: []u8) []Element
+ {#syntax#}@bytesToSlice(comptime Element: type, bytes: []u8) []Element{#endsyntax#}
- Converts a slice of bytes or array of bytes into a slice of Element.
+ Converts a slice of bytes or array of bytes into a slice of {#syntax#}Element{#endsyntax#}.
The resulting slice has the same {#link|pointer|Pointers#} properties as the parameter.
@@ -5200,12 +5200,12 @@ comptime { {#header_close#} {#header_open|@cDefine#} -
@cDefine(comptime name: []u8, value)
+ {#syntax#}@cDefine(comptime name: []u8, value){#endsyntax#}
- This function can only occur inside @cImport.
+ This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
- This appends #define $name $value to the @cImport
+ This appends #define $name $value to the {#syntax#}@cImport{#endsyntax#}
temporary buffer.
@@ -5215,72 +5215,72 @@ comptime {
Use the void value, like this:
-@cDefine("_GNU_SOURCE", {})
+ {#syntax#}@cDefine("_GNU_SOURCE", {}){#endsyntax#}
{#see_also|Import from C Header File|@cInclude|@cImport|@cUndef|void#}
{#header_close#}
{#header_open|@cImport#}
- @cImport(expression) (namespace)
+ {#syntax#}@cImport(expression) (namespace){#endsyntax#}
This function parses C code and imports the functions, types, variables, and compatible macro definitions into the result namespace.
- expression is interpreted at compile time. The builtin functions
- @cInclude, @cDefine, and @cUndef work
+ {#syntax#}expression{#endsyntax#} is interpreted at compile time. The builtin functions
+ {#syntax#}@cInclude{#endsyntax#}, {#syntax#}@cDefine{#endsyntax#}, and {#syntax#}@cUndef{#endsyntax#} work
within this expression, appending to a temporary buffer which is then parsed as C code.
- Usually you should only have one @cImport in your entire application, because it saves the compiler
+ Usually you should only have one {#syntax#}@cImport{#endsyntax#} in your entire application, because it saves the compiler
from invoking clang multiple times, and prevents inline functions from being duplicated.
- Reasons for having multiple @cImport expressions would be:
+ Reasons for having multiple {#syntax#}@cImport{#endsyntax#} expressions would be:
#define CONNECTION_COUNT#define CONNECTION_COUNT@cInclude(comptime path: []u8)
+ {#syntax#}@cInclude(comptime path: []u8){#endsyntax#}
- This function can only occur inside @cImport.
+ This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
- This appends #include <$path>\n to the c_import
+ This appends #include <$path>\n to the {#syntax#}c_import{#endsyntax#}
temporary buffer.
@cUndef(comptime name: []u8)
+ {#syntax#}@cUndef(comptime name: []u8){#endsyntax#}
- This function can only occur inside @cImport.
+ This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
- This appends #undef $name to the @cImport
+ This appends #undef $name to the {#syntax#}@cImport{#endsyntax#}
temporary buffer.
@clz(x: T) U
+ {#syntax#}@clz(x: T) U{#endsyntax#}
- This function counts the number of leading zeroes in x which is an integer
- type T.
+ This function counts the number of leading zeroes in {#syntax#}x{#endsyntax#} which is an integer
+ type {#syntax#}T{#endsyntax#}.
- The return type U is an unsigned integer with the minimum number
- of bits that can represent the value T.bit_count.
+ The return type {#syntax#}U{#endsyntax#} is an unsigned integer with the minimum number
+ of bits that can represent the value {#syntax#}T.bit_count{#endsyntax#}.
- If x is zero, @clz returns T.bit_count.
+ If {#syntax#}x{#endsyntax#} is zero, {#syntax#}@clz{#endsyntax#} returns {#syntax#}T.bit_count{#endsyntax#}.
@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T
+ {#syntax#}@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T{#endsyntax#}
This function performs a strong atomic compare exchange operation. It's the equivalent of this code, except atomic: @@ -5301,13 +5301,13 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_v more efficiently in machine instructions.
- AtomicOrder can be found with @import("builtin").AtomicOrder.
+ {#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("builtin").AtomicOrder{#endsyntax#}.
@typeOf(ptr).alignment must be >= @sizeOf(T).
{#syntax#}@typeOf(ptr).alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#see_also|Compile Variables|cmpxchgWeak#} {#header_close#} {#header_open|@cmpxchgWeak#} -@cmpxchgWeak(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T
+ {#syntax#}@cmpxchgWeak(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T{#endsyntax#}
This function performs a weak atomic compare exchange operation. It's the equivalent of this code, except atomic: @@ -5324,30 +5324,30 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val } {#code_end#}
- If you are using cmpxchg in a loop, the sporadic failure will be no problem, and cmpxchgWeak
+ If you are using cmpxchg in a loop, the sporadic failure will be no problem, and {#syntax#}cmpxchgWeak{#endsyntax#}
is the better choice, because it can be implemented more efficiently in machine instructions.
However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
- AtomicOrder can be found with @import("builtin").AtomicOrder.
+ {#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("builtin").AtomicOrder{#endsyntax#}.
@typeOf(ptr).alignment must be >= @sizeOf(T).
{#syntax#}@typeOf(ptr).alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#see_also|Compile Variables|cmpxchgStrong#} {#header_close#} {#header_open|@compileError#} -@compileError(comptime msg: []u8)
+ {#syntax#}@compileError(comptime msg: []u8){#endsyntax#}
This function, when semantically analyzed, causes a compile error with the
- message msg.
+ message {#syntax#}msg{#endsyntax#}.
There are several ways that code avoids being semantically checked, such as
- using if or switch with compile time constants,
- and comptime functions.
+ using {#syntax#}if{#endsyntax#} or {#syntax#}switch{#endsyntax#} with compile time constants,
+ and {#syntax#}comptime{#endsyntax#} functions.
@compileLog(args: ...)
+ {#syntax#}@compileLog(args: ...){#endsyntax#}
This function prints the arguments passed to it at compile-time.
@@ -5382,7 +5382,7 @@ test "main" { will ouput:
- If all @compileLog calls are removed or
+ If all {#syntax#}@compileLog{#endsyntax#} calls are removed or
not encountered by analysis, the
program compiles successfully and the generated executable prints:
@ctz(x: T) U
+ {#syntax#}@ctz(x: T) U{#endsyntax#}
- This function counts the number of trailing zeroes in x which is an integer
- type T.
+ This function counts the number of trailing zeroes in {#syntax#}x{#endsyntax#} which is an integer
+ type {#syntax#}T{#endsyntax#}.
- The return type U is an unsigned integer with the minimum number
- of bits that can represent the value T.bit_count.
+ The return type {#syntax#}U{#endsyntax#} is an unsigned integer with the minimum number
+ of bits that can represent the value {#syntax#}T.bit_count{#endsyntax#}.
- If x is zero, @ctz returns T.bit_count.
+ If {#syntax#}x{#endsyntax#} is zero, {#syntax#}@ctz{#endsyntax#} returns {#syntax#}T.bit_count{#endsyntax#}.
@divExact(numerator: T, denominator: T) T
+ {#syntax#}@divExact(numerator: T, denominator: T) T{#endsyntax#}
- Exact division. Caller guarantees denominator != 0 and
- @divTrunc(numerator, denominator) * denominator == numerator.
+ Exact division. Caller guarantees {#syntax#}denominator != 0{#endsyntax#} and
+ {#syntax#}@divTrunc(numerator, denominator) * denominator == numerator{#endsyntax#}.
@divExact(6, 3) == 2@divExact(a, b) * b == aFor a function that returns a possible error code, use @import("std").math.divExact.
For a function that returns a possible error code, use {#syntax#}@import("std").math.divExact{#endsyntax#}.
{#see_also|@divTrunc|@divFloor#} {#header_close#} {#header_open|@divFloor#} -@divFloor(numerator: T, denominator: T) T
+ {#syntax#}@divFloor(numerator: T, denominator: T) T{#endsyntax#}
Floored division. Rounds toward negative infinity. For unsigned integers it is
- the same as numerator / denominator. Caller guarantees denominator != 0 and
- !(@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1).
+ the same as {#syntax#}numerator / denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#} and
+ {#syntax#}!(@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1){#endsyntax#}.
@divFloor(-5, 3) == -2@divFloor(a, b) + @mod(a, b) == aFor a function that returns a possible error code, use @import("std").math.divFloor.
For a function that returns a possible error code, use {#syntax#}@import("std").math.divFloor{#endsyntax#}.
{#see_also|@divTrunc|@divExact#} {#header_close#} {#header_open|@divTrunc#} -@divTrunc(numerator: T, denominator: T) T
+ {#syntax#}@divTrunc(numerator: T, denominator: T) T{#endsyntax#}
Truncated division. Rounds toward zero. For unsigned integers it is
- the same as numerator / denominator. Caller guarantees denominator != 0 and
- !(@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1).
+ the same as {#syntax#}numerator / denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#} and
+ {#syntax#}!(@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1){#endsyntax#}.
@divTrunc(-5, 3) == -1@divTrunc(a, b) + @rem(a, b) == aFor a function that returns a possible error code, use @import("std").math.divTrunc.
For a function that returns a possible error code, use {#syntax#}@import("std").math.divTrunc{#endsyntax#}.
{#see_also|@divFloor|@divExact#} {#header_close#} {#header_open|@embedFile#} -@embedFile(comptime path: []const u8) [X]u8
+ {#syntax#}@embedFile(comptime path: []const u8) [X]u8{#endsyntax#}
This function returns a compile time constant fixed-size array with length
- equal to the byte count of the file given by path. The contents of the array
+ equal to the byte count of the file given by {#syntax#}path{#endsyntax#}. The contents of the array
are the contents of the file.
- path is absolute or relative to the current file, just like @import.
+ {#syntax#}path{#endsyntax#} is absolute or relative to the current file, just like {#syntax#}@import{#endsyntax#}.
@enumToInt(enum_value: var) var
+ {#syntax#}@enumToInt(enum_value: var) var{#endsyntax#}
Converts an enumeration value into its integer tag type.
- If the enum has only 1 possible value, the resut is a comptime_int
+ If the enum has only 1 possible value, the resut is a {#syntax#}comptime_int{#endsyntax#}
known at {#link|comptime#}.
@errSetCast(comptime T: DestType, value: var) DestType
+ {#syntax#}@errSetCast(comptime T: DestType, value: var) DestType{#endsyntax#}
Converts an error value from one error set to another error set. Attempting to convert an error which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}. @@ -5490,24 +5490,24 @@ test "main" { {#header_close#} {#header_open|@errorName#} -
@errorName(err: error) []u8
+ {#syntax#}@errorName(err: error) []u8{#endsyntax#}
This function returns the string representation of an error. If an error declaration is:
-error OutOfMem
+ {#syntax#}error OutOfMem{#endsyntax#}
- Then the string representation is "OutOfMem".
+ Then the string representation is {#syntax#}"OutOfMem"{#endsyntax#}.
- If there are no calls to @errorName in an entire application,
- or all calls have a compile-time known value for err, then no
+ If there are no calls to {#syntax#}@errorName{#endsyntax#} in an entire application,
+ or all calls have a compile-time known value for {#syntax#}err{#endsyntax#}, then no
error name table will be generated.
@errorReturnTrace() ?*builtin.StackTrace
+ {#syntax#}@errorReturnTrace() ?*builtin.StackTrace{#endsyntax#}
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 @@ -5516,13 +5516,13 @@ test "main" { {#header_close#} {#header_open|@errorToInt#} -
@errorToInt(err: var) @IntType(false, @sizeOf(error) * 8)
+ {#syntax#}@errorToInt(err: var) @IntType(false, @sizeOf(error) * 8){#endsyntax#}
Supports the following types:
E!voidConverts an error to the integer representation of an error. @@ -5535,38 +5535,41 @@ test "main" { {#header_close#} {#header_open|@export#} -
@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8
+ {#syntax#}@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8{#endsyntax#}
Creates a symbol in the output object file.
{#header_close#} {#header_open|@fence#} -@fence(order: AtomicOrder)
+ {#syntax#}@fence(order: AtomicOrder){#endsyntax#}
- The fence function is used to introduce happens-before edges between operations.
+ The {#syntax#}fence{#endsyntax#} function is used to introduce happens-before edges between operations.
- AtomicOrder can be found with @import("builtin").AtomicOrder.
+ {#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("builtin").AtomicOrder{#endsyntax#}.
@field(lhs: var, comptime field_name: []const u8) (field)
- Preforms field access equivalent to lhs.->field_name-<.
{#syntax#}@field(lhs: var, comptime field_name: []const u8) (field){#endsyntax#}
+ Preforms field access equivalent to {#syntax#}lhs.field_name{#endsyntax#}, except instead + of the field {#syntax#}"field_name"{#endsyntax#}, it accesses the field named by the string + value of {#syntax#}field_name{#endsyntax#}. +
{#header_close#} {#header_open|@fieldParentPtr#} -@fieldParentPtr(comptime ParentType: type, comptime field_name: []const u8,
- field_ptr: *T) *ParentType
+ {#syntax#}@fieldParentPtr(comptime ParentType: type, comptime field_name: []const u8,
+ field_ptr: *T) *ParentType{#endsyntax#}
Given a pointer to a field, returns the base pointer of a struct.
{#header_close#} {#header_open|@floatCast#} -@floatCast(comptime DestType: type, value: var) DestType
+ {#syntax#}@floatCast(comptime DestType: type, value: var) DestType{#endsyntax#}
Convert from one float type to another. This cast is safe, but may cause the numeric value to lose precision. @@ -5574,7 +5577,7 @@ test "main" { {#header_close#} {#header_open|@floatToInt#} -
@floatToInt(comptime DestType: type, float: var) DestType
+ {#syntax#}@floatToInt(comptime DestType: type, float: var) DestType{#endsyntax#}
Converts the integer part of a floating point number to the destination type.
@@ -5586,7 +5589,7 @@ test "main" { {#header_close#} {#header_open|@frameAddress#} -@frameAddress()
+ {#syntax#}@frameAddress(){#endsyntax#}
This function returns the base pointer of the current stack frame.
@@ -5600,9 +5603,9 @@ test "main" { {#header_close#} {#header_open|@handle#} -@handle()
+ {#syntax#}@handle(){#endsyntax#}
- This function returns a promise->T type, where T
+ This function returns a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#}
is the return type of the async function in scope.
@@ -5610,27 +5613,27 @@ test "main" {
{#header_close#} {#header_open|@import#} -@import(comptime path: []u8) (namespace)
+ {#syntax#}@import(comptime path: []u8) (namespace){#endsyntax#}
- This function finds a zig file corresponding to path and imports all the
+ This function finds a zig file corresponding to {#syntax#}path{#endsyntax#} and imports all the
public top level declarations into the resulting namespace.
- path can be a relative or absolute path, or it can be the name of a package.
- If it is a relative path, it is relative to the file that contains the @import
+ {#syntax#}path{#endsyntax#} can be a relative or absolute path, or it can be the name of a package.
+ If it is a relative path, it is relative to the file that contains the {#syntax#}@import{#endsyntax#}
function call.
The following packages are always available:
@import("std") - Zig Standard Library@import("builtin") - Compiler-provided types and variables@inlineCall(function: X, args: ...) Y
+ {#syntax#}@inlineCall(function: X, args: ...) Y{#endsyntax#}
This calls a function, in the same way that invoking an expression with parentheses does:
@@ -5644,14 +5647,14 @@ test "inline function call" { fn add(a: i32, b: i32) i32 { return a + b; } {#code_end#}
- Unlike a normal function call, however, @inlineCall guarantees that the call
+ Unlike a normal function call, however, {#syntax#}@inlineCall{#endsyntax#} guarantees that the call
will be inlined. If the call cannot be inlined, a compile error is emitted.
@intCast(comptime DestType: type, int: var) DestType
+ {#syntax#}@intCast(comptime DestType: type, int: var) DestType{#endsyntax#}
Converts an integer to another integer while keeping the same numerical value. Attempting to convert a number which is out of range of the destination type results in @@ -5660,7 +5663,7 @@ fn add(a: i32, b: i32) i32 { return a + b; } {#header_close#} {#header_open|@intToEnum#} -
@intToEnum(comptime DestType: type, int_value: @TagType(DestType)) DestType
+ {#syntax#}@intToEnum(comptime DestType: type, int_value: @TagType(DestType)) DestType{#endsyntax#}
Converts an integer into an {#link|enum#} value.
@@ -5672,7 +5675,7 @@ fn add(a: i32, b: i32) i32 { return a + b; } {#header_close#} {#header_open|@intToError#} -@intToError(value: @IntType(false, @sizeOf(error) * 8)) error
+ {#syntax#}@intToError(value: @IntType(false, @sizeOf(error) * 8)) error{#endsyntax#}
Converts from the integer representation of an error into the global error set type.
@@ -5688,36 +5691,36 @@ fn add(a: i32, b: i32) i32 { return a + b; } {#header_close#} {#header_open|@intToFloat#} -@intToFloat(comptime DestType: type, int: var) DestType
+ {#syntax#}@intToFloat(comptime DestType: type, int: var) DestType{#endsyntax#}
Converts an integer to the closest floating point representation. To convert the other way, use {#link|@floatToInt#}. This cast is always safe.
{#header_close#} {#header_open|@intToPtr#} -@intToPtr(comptime DestType: type, int: usize) DestType
+ {#syntax#}@intToPtr(comptime DestType: type, int: usize) DestType{#endsyntax#}
Converts an integer to a pointer. To convert the other way, use {#link|@ptrToInt#}.
{#header_close#} {#header_open|@IntType#} -@IntType(comptime is_signed: bool, comptime bit_count: u32) type
+ {#syntax#}@IntType(comptime is_signed: bool, comptime bit_count: u32) type{#endsyntax#}
This function returns an integer type with the given signness and bit count.
{#header_close#} {#header_open|@maxValue#} -@maxValue(comptime T: type) comptime_int
+ {#syntax#}@maxValue(comptime T: type) comptime_int{#endsyntax#}
- This function returns the maximum value of the integer type T.
+ This function returns the maximum value of the integer type {#syntax#}T{#endsyntax#}.
The result is a compile time constant.
{#header_close#} {#header_open|@memberCount#} -@memberCount(comptime T: type) comptime_int
+ {#syntax#}@memberCount(comptime T: type) comptime_int{#endsyntax#}
This function returns the number of members in a struct, enum, or union type.
@@ -5729,7 +5732,7 @@ fn add(a: i32, b: i32) i32 { return a + b; } {#header_close#} {#header_open|@memberName#} -@memberName(comptime T: type, comptime index: usize) [N]u8
+ {#syntax#}@memberName(comptime T: type, comptime index: usize) [N]u8{#endsyntax#}
Returns the field name of a struct, union, or enum.
The result is a compile time constant. @@ -5739,46 +5742,46 @@ fn add(a: i32, b: i32) i32 { return a + b; }
{#header_close#} {#header_open|@memberType#} -@memberType(comptime T: type, comptime index: usize) type
+ {#syntax#}@memberType(comptime T: type, comptime index: usize) type{#endsyntax#}
Returns the field type of a struct or union.
{#header_close#} {#header_open|@memcpy#} -@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize)
+ {#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}
- This function copies bytes from one region of memory to another. dest and
- source are both pointers and must not overlap.
+ This function copies bytes from one region of memory to another. {#syntax#}dest{#endsyntax#} and
+ {#syntax#}source{#endsyntax#} are both pointers and must not overlap.
This function is a low level intrinsic with no safety mechanisms. Most code should not use this function, instead using something like this:
-for (source[0...byte_count]) |b, i| dest[i] = b;
+ {#syntax#}for (source[0...byte_count]) |b, i| dest[i] = b;{#endsyntax#}
The optimizer is intelligent enough to turn the above snippet into a memcpy.
There is also a standard library function for this:
-const mem = @import("std").mem;
-mem.copy(u8, dest[0...byte_count], source[0...byte_count]);
+ {#syntax#}const mem = @import("std").mem;
+mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
{#header_close#}
{#header_open|@memset#}
- @memset(dest: [*]u8, c: u8, byte_count: usize)
+ {#syntax#}@memset(dest: [*]u8, c: u8, byte_count: usize){#endsyntax#}
- This function sets a region of memory to c. dest is a pointer.
+ This function sets a region of memory to {#syntax#}c{#endsyntax#}. {#syntax#}dest{#endsyntax#} is a pointer.
This function is a low level intrinsic with no safety mechanisms. Most code should not use this function, instead using something like this:
-for (dest[0...byte_count]) |*b| b.* = c;
+ {#syntax#}for (dest[0...byte_count]) |*b| b.* = c;{#endsyntax#}
The optimizer is intelligent enough to turn the above snippet into a memset.
There is also a standard library function for this:
-const mem = @import("std").mem;
-mem.set(u8, dest, c);
+ {#syntax#}const mem = @import("std").mem;
+mem.set(u8, dest, c);{#endsyntax#}
{#header_close#}
{#header_open|@minValue#}
- @minValue(comptime T: type) comptime_int
+ {#syntax#}@minValue(comptime T: type) comptime_int{#endsyntax#}
This function returns the minimum value of the integer type T.
@@ -5787,31 +5790,31 @@ mem.set(u8, dest, c); {#header_close#} {#header_open|@mod#} -@mod(numerator: T, denominator: T) T
+ {#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}
Modulus division. For unsigned integers this is the same as
- numerator % denominator. Caller guarantees denominator > 0.
+ {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}.
@mod(-5, 3) == 1@divFloor(a, b) + @mod(a, b) == aFor a function that returns an error code, see @import("std").math.mod.
For a function that returns an error code, see {#syntax#}@import("std").math.mod{#endsyntax#}.
{#see_also|@rem#} {#header_close#} {#header_open|@mulWithOverflow#} -@mulWithOverflow(comptime T: type, a: T, b: T, result: *T) bool
+ {#syntax#}@mulWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}
- Performs result.* = a * b. If overflow or underflow occurs,
- stores the overflowed bits in result and returns true.
- If no overflow or underflow occurs, returns false.
+ Performs {#syntax#}result.* = a * b{#endsyntax#}. If overflow or underflow occurs,
+ stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
+ If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
@newStackCall(new_stack: []u8, function: var, args: ...) var
+ {#syntax#}@newStackCall(new_stack: []u8, function: var, args: ...) var{#endsyntax#}
This calls a function, in the same way that invoking an expression with parentheses does. However,
- instead of using the same stack as the caller, the function uses the stack provided in the new_stack
+ instead of using the same stack as the caller, the function uses the stack provided in the {#syntax#}new_stack{#endsyntax#}
parameter.
@noInlineCall(function: var, args: ...) var
+ {#syntax#}@noInlineCall(function: var, args: ...) var{#endsyntax#}
This calls a function, in the same way that invoking an expression with parentheses does:
@@ -5860,19 +5863,19 @@ fn add(a: i32, b: i32) i32 { } {#code_end#}
- Unlike a normal function call, however, @noInlineCall guarantees that the call
+ Unlike a normal function call, however, {#syntax#}@noInlineCall{#endsyntax#} guarantees that the call
will not be inlined. If the call must be inlined, a compile error is emitted.
@offsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int
+ {#syntax#}@offsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}
This function returns the byte offset of a field relative to its containing struct.
{#header_close#} {#header_open|@OpaqueType#} -@OpaqueType() type
+ {#syntax#}@OpaqueType() type{#endsyntax#}
Creates a new type with an unknown size and alignment.
@@ -5895,14 +5898,14 @@ test "call foo" { {#code_end#} {#header_close#} {#header_open|@panic#} -@panic(message: []const u8) noreturn
+ {#syntax#}@panic(message: []const u8) noreturn{#endsyntax#}
Invokes the panic handler function. By default the panic handler function
- calls the public panic function exposed in the root source file, or
- if there is not one specified, invokes the one provided in std/special/panic.zig.
+ calls the public {#syntax#}panic{#endsyntax#} function exposed in the root source file, or
+ if there is not one specified, invokes the one provided in {#syntax#}std/special/panic.zig{#endsyntax#}.
Generally it is better to use @import("std").debug.panic.
- However, @panic can be useful for 2 scenarios:
+
Generally it is better to use {#syntax#}@import("std").debug.panic{#endsyntax#}. + However, {#syntax#}@panic{#endsyntax#} can be useful for 2 scenarios:
@popCount(integer: var) var
+ {#syntax#}@popCount(integer: var) var{#endsyntax#}
Counts the number of bits set in an integer.
- If integer is known at {#link|comptime#}, the return type is comptime_int.
+ If {#syntax#}integer{#endsyntax#} is known at {#link|comptime#}, the return type is {#syntax#}comptime_int{#endsyntax#}.
Otherwise, the return type is an unsigned integer with the minimum number
of bits that can represent the bit count of the integer type.
@ptrCast(comptime DestType: type, value: var) DestType
+ {#syntax#}@ptrCast(comptime DestType: type, value: var) DestType{#endsyntax#}
Converts a pointer of one type to a pointer of another type.
{#header_close#} {#header_open|@ptrToInt#} -@ptrToInt(value: var) usize
+ {#syntax#}@ptrToInt(value: var) usize{#endsyntax#}
- Converts value to a usize which is the address of the pointer. value can be one of these types:
+ Converts {#syntax#}value{#endsyntax#} to a {#syntax#}usize{#endsyntax#} which is the address of the pointer. {#syntax#}value{#endsyntax#} can be one of these types:
*T?*Tfn()?fn()To convert the other way, use {#link|@intToPtr#}
{#header_close#} {#header_open|@rem#} -@rem(numerator: T, denominator: T) T
+ {#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}
Remainder division. For unsigned integers this is the same as
- numerator % denominator. Caller guarantees denominator > 0.
+ {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}.
@rem(-5, 3) == -2@divTrunc(a, b) + @rem(a, b) == aFor a function that returns an error code, see @import("std").math.rem.
For a function that returns an error code, see {#syntax#}@import("std").math.rem{#endsyntax#}.
{#see_also|@mod#} {#header_close#} {#header_open|@returnAddress#} -@returnAddress()
+ {#syntax#}@returnAddress(){#endsyntax#}
This function returns a pointer to the return address of the current stack frame. @@ -5968,32 +5971,32 @@ test "call foo" {
{#header_close#} {#header_open|@setAlignStack#} -@setAlignStack(comptime alignment: u29)
+ {#syntax#}@setAlignStack(comptime alignment: u29){#endsyntax#}
- Ensures that a function will have a stack alignment of at least alignment bytes.
+ Ensures that a function will have a stack alignment of at least {#syntax#}alignment{#endsyntax#} bytes.
@setCold(is_cold: bool)
+ {#syntax#}@setCold(is_cold: bool){#endsyntax#}
Tells the optimizer that a function is rarely called.
{#header_close#} {#header_open|@setRuntimeSafety#} -@setRuntimeSafety(safety_on: bool)
+ {#syntax#}@setRuntimeSafety(safety_on: bool){#endsyntax#}
Sets whether runtime safety checks are on for the scope that contains the function call.
{#header_close#} {#header_open|@setEvalBranchQuota#} -@setEvalBranchQuota(new_quota: usize)
+ {#syntax#}@setEvalBranchQuota(new_quota: usize){#endsyntax#}
Changes the maximum number of backwards branches that compile-time code execution can use before giving up and making a compile error.
- If the new_quota is smaller than the default quota (1000) or
+ If the {#syntax#}new_quota{#endsyntax#} is smaller than the default quota ({#syntax#}1000{#endsyntax#}) or
a previously explicitly set quota, it is ignored.
@@ -6007,7 +6010,7 @@ test "foo" { } } {#code_end#} -
Now we use @setEvalBranchQuota:
Now we use {#syntax#}@setEvalBranchQuota{#endsyntax#}:
{#code_begin|test#} test "foo" { comptime { @@ -6021,7 +6024,7 @@ test "foo" { {#see_also|comptime#} {#header_close#} {#header_open|@setFloatMode#} -@setFloatMode(mode: @import("builtin").FloatMode)
+ {#syntax#}@setFloatMode(mode: @import("builtin").FloatMode){#endsyntax#}
Sets the floating point mode of the current scope. Possible values are:
@@ -6033,10 +6036,10 @@ pub const FloatMode = enum { {#code_end#}Strict (default) - Floating point operations follow strict IEEE compliance.
+ {#syntax#}Strict{#endsyntax#} (default) - Floating point operations follow strict IEEE compliance.
Optimized - Floating point operations may do all of the following:
+ {#syntax#}Optimized{#endsyntax#} - Floating point operations may do all of the following:
@setGlobalLinkage(global_variable_name, comptime linkage: GlobalLinkage)
+ {#syntax#}@setGlobalLinkage(global_variable_name, comptime linkage: GlobalLinkage){#endsyntax#}
- GlobalLinkage can be found with @import("builtin").GlobalLinkage.
+ {#syntax#}GlobalLinkage{#endsyntax#} can be found with {#syntax#}@import("builtin").GlobalLinkage{#endsyntax#}.
@shlExact(value: T, shift_amt: Log2T) T
+ {#syntax#}@shlExact(value: T, shift_amt: Log2T) T{#endsyntax#}
- Performs the left shift operation (<<). Caller guarantees
+ Performs the left shift operation ({#syntax#}<<{#endsyntax#}). Caller guarantees
that the shift will not shift any 1 bits out.
- The type of shift_amt is an unsigned integer with log2(T.bit_count) bits.
- This is because shift_amt >= T.bit_count is undefined behavior.
+ The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(T.bit_count){#endsyntax#} bits.
+ This is because {#syntax#}shift_amt >= T.bit_count{#endsyntax#} is undefined behavior.
@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: *T) bool
+ {#syntax#}@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: *T) bool{#endsyntax#}
- Performs result.* = a << b. If overflow or underflow occurs,
- stores the overflowed bits in result and returns true.
- If no overflow or underflow occurs, returns false.
+ Performs {#syntax#}result.* = a << b{#endsyntax#}. If overflow or underflow occurs,
+ stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
+ If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
- The type of shift_amt is an unsigned integer with log2(T.bit_count) bits.
- This is because shift_amt >= T.bit_count is undefined behavior.
+ The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(T.bit_count){#endsyntax#} bits.
+ This is because {#syntax#}shift_amt >= T.bit_count{#endsyntax#} is undefined behavior.
@shrExact(value: T, shift_amt: Log2T) T
+ {#syntax#}@shrExact(value: T, shift_amt: Log2T) T{#endsyntax#}
- Performs the right shift operation (>>). Caller guarantees
+ Performs the right shift operation ({#syntax#}>>{#endsyntax#}). Caller guarantees
that the shift will not shift any 1 bits out.
- The type of shift_amt is an unsigned integer with log2(T.bit_count) bits.
- This is because shift_amt >= T.bit_count is undefined behavior.
+ The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(T.bit_count){#endsyntax#} bits.
+ This is because {#syntax#}shift_amt >= T.bit_count{#endsyntax#} is undefined behavior.
@sizeOf(comptime T: type) comptime_int
+ {#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}
- This function returns the number of bytes it takes to store T in memory.
+ This function returns the number of bytes it takes to store {#syntax#}T{#endsyntax#} in memory.
The result is a target-specific compile time constant. @@ -6110,39 +6113,39 @@ pub const FloatMode = enum { {#header_close#} {#header_open|@sliceToBytes#} -
@sliceToBytes(value: var) []u8
+ {#syntax#}@sliceToBytes(value: var) []u8{#endsyntax#}
- Converts a slice or array to a slice of u8. The resulting slice has the same
+ Converts a slice or array to a slice of {#syntax#}u8{#endsyntax#}. The resulting slice has the same
{#link|pointer|Pointers#} properties as the parameter.
@sqrt(comptime T: type, value: T) T
+ {#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}
Performs the square root of a floating point number. Uses a dedicated hardware instruction when available. Currently only supports f32 and f64 at runtime. f128 at runtime is TODO.
- This is a low-level intrinsic. Most code can use std.math.sqrt instead.
+ This is a low-level intrinsic. Most code can use {#syntax#}std.math.sqrt{#endsyntax#} instead.
@subWithOverflow(comptime T: type, a: T, b: T, result: *T) bool
+ {#syntax#}@subWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}
- Performs result.* = a - b. If overflow or underflow occurs,
- stores the overflowed bits in result and returns true.
- If no overflow or underflow occurs, returns false.
+ Performs {#syntax#}result.* = a - b{#endsyntax#}. If overflow or underflow occurs,
+ stores the overflowed bits in {#syntax#}result{#endsyntax#} and returns {#syntax#}true{#endsyntax#}.
+ If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
@tagName(value: var) []const u8
+ {#syntax#}@tagName(value: var) []const u8{#endsyntax#}
Converts an enum value or union value to a slice of bytes representing the name.
{#header_close#} {#header_open|@TagType#} -@TagType(T: type) type
+ {#syntax#}@TagType(T: type) type{#endsyntax#}
For an enum, returns the integer type that is used to store the enumeration value.
@@ -6151,7 +6154,7 @@ pub const FloatMode = enum { {#header_close#} {#header_open|@truncate#} -@truncate(comptime T: type, integer) T
+ {#syntax#}@truncate(comptime T: type, integer) T{#endsyntax#}
This function truncates bits from an integer type, resulting in a smaller integer type. @@ -6160,14 +6163,14 @@ pub const FloatMode = enum { The following produces a crash in debug mode and undefined behavior in release mode:
-const a: u16 = 0xabcd;
-const b: u8 = u8(a);
+ {#syntax#}const a: u16 = 0xabcd;
+const b: u8 = u8(a);{#endsyntax#}
However this is well defined and working code:
-const a: u16 = 0xabcd;
+ {#syntax#}const a: u16 = 0xabcd;
const b: u8 = @truncate(u8, a);
-// b is now 0xcd
+// b is now 0xcd{#endsyntax#}
This function always truncates the significant bits of the integer, regardless of endianness on the target platform. @@ -6175,7 +6178,7 @@ const b: u8 = @truncate(u8, a); {#header_close#} {#header_open|@typeId#} -
@typeId(comptime T: type) @import("builtin").TypeId
+ {#syntax#}@typeId(comptime T: type) @import("builtin").TypeId{#endsyntax#}
Returns which kind of type something is. Possible values:
@@ -6209,7 +6212,7 @@ pub const TypeId = enum { {#code_end#} {#header_close#} {#header_open|@typeInfo#} -@typeInfo(comptime T: type) @import("builtin").TypeInfo
+ {#syntax#}@typeInfo(comptime T: type) @import("builtin").TypeInfo{#endsyntax#}
Returns information on the type. Returns a value of the following union:
@@ -6392,14 +6395,14 @@ pub const TypeInfo = union(TypeId) { {#code_end#} {#header_close#} {#header_open|@typeName#} -@typeName(T: type) []u8
+ {#syntax#}@typeName(T: type) []u8{#endsyntax#}
This function returns the string representation of a type.
{#header_close#} {#header_open|@typeOf#} -@typeOf(expression) type
+ {#syntax#}@typeOf(expression) type{#endsyntax#}
This function returns a compile-time constant, which is the type of the expression passed as an argument. The expression is evaluated. @@ -6576,11 +6579,11 @@ pub fn main() void { {#header_open|Default Operations#}
The following operators can cause integer overflow:
+ (addition)- (subtraction)- (negation)* (multiplication)/ (division)These functions provided by the standard library return possible errors.
@import("std").math.add@import("std").math.sub@import("std").math.mul@import("std").math.divTrunc@import("std").math.divFloor@import("std").math.divExact@import("std").math.shlExample of catching an overflow for addition:
{#code_begin|exe_err#} @@ -6632,7 +6635,7 @@ pub fn main() !void { {#header_close#} {#header_open|Builtin Overflow Functions#}
- These builtins return a bool of whether or not overflow
+ These builtins return a {#syntax#}bool{#endsyntax#} of whether or not overflow
occurred, as well as returning the overflowed bits:
+% (wraparound addition)-% (wraparound subtraction)-% (wraparound negation)*% (wraparound multiplication)One way to avoid this crash is to test for null instead of assuming non-null, with
- the if expression:
One way to avoid this crash is to test for an error instead of assuming a successful result, with
- the if expression:
- This safety is not available for extern or packed unions.
+ This safety is not available for {#syntax#}extern{#endsyntax#} or {#syntax#}packed{#endsyntax#} unions.
To change the active field of a union, assign the entire union, like this: @@ -7087,7 +7090,7 @@ fn bar(f: *Foo) void { {#header_close#} {#header_open|Compile Variables#}
- Compile variables are accessible by importing the "builtin" package,
+ Compile variables are accessible by importing the {#syntax#}"builtin"{#endsyntax#} package,
which the compiler makes available to every Zig source file. It contains
compile-time constants such as the current target, endianness, and release mode.
- Example of what is imported with @import("builtin"):
+ Example of what is imported with {#syntax#}@import("builtin"){#endsyntax#}:
c_shortc_ushortc_intc_uintc_longc_ulongc_longlongc_ulonglongc_longdoublec_void
- The @cImport builtin function can be used
+ The {#syntax#}@cImport{#endsyntax#} builtin function can be used
to directly import symbols from .h files:
- The @cImport function takes an expression as a parameter.
+ The {#syntax#}@cImport{#endsyntax#} function takes an expression as a parameter.
This expression is evaluated at compile-time and is used to control
preprocessor directives and include multiple .h files:
One of the primary use cases for Zig is exporting a library with the C ABI for other programming languages
- to call into. The export keyword in front of functions, variables, and types causes them to
+ to call into. The {#syntax#}export{#endsyntax#} keyword in front of functions, variables, and types causes them to
be part of the library API:
mathtest.zig
@@ -7454,7 +7457,7 @@ Environments: coreclr opencl
- The Zig Standard Library (@import("std")) has architecture, environment, and operating sytsem
+ The Zig Standard Library ({#syntax#}@import("std"){#endsyntax#}) has architecture, environment, and operating sytsem
abstractions, and thus takes additional work to support more platforms.
Not all standard library code requires operating system abstractions, however,
so things such as generic data structures work an all above platforms.
@@ -7491,25 +7494,25 @@ coding style.
{#header_close#}
{#header_open|Names#}
- Roughly speaking: camelCaseFunctionName, TitleCaseTypeName,
- snake_case_variable_name. More precisely:
+ Roughly speaking: {#syntax#}camelCaseFunctionName{#endsyntax#}, {#syntax#}TitleCaseTypeName{#endsyntax#},
+ {#syntax#}snake_case_variable_name{#endsyntax#}. More precisely:
x is a struct (or an alias of a struct),
- then x should be TitleCase.
+ If {#syntax#}x{#endsyntax#} is a {#syntax#}struct{#endsyntax#} (or an alias of a {#syntax#}struct{#endsyntax#}),
+ then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}.
x otherwise identifies a type, x should have snake_case.
+ If {#syntax#}x{#endsyntax#} otherwise identifies a type, {#syntax#}x{#endsyntax#} should have {#syntax#}snake_case{#endsyntax#}.
x is callable, and x's return type is type, then x should be TitleCase.
+ If {#syntax#}x{#endsyntax#} is callable, and {#syntax#}x{#endsyntax#}'s return type is {#syntax#}type{#endsyntax#}, then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}.
x is otherwise callable, then x should be camelCase.
+ If {#syntax#}x{#endsyntax#} is otherwise callable, then {#syntax#}x{#endsyntax#} should be {#syntax#}camelCase{#endsyntax#}.
x should be snake_case.
+ Otherwise, {#syntax#}x{#endsyntax#} should be {#syntax#}snake_case{#endsyntax#}.
@@ -7521,7 +7524,7 @@ coding style.
These are general rules of thumb; if it makes sense to do something different,
do what makes sense. For example, if there is an established convention such as
- ENOENT, follow the established convention.
+ {#syntax#}ENOENT{#endsyntax#}, follow the established convention.